質問するログイン新規登録

回答編集履歴

2

追記

2020/11/22 18:42

投稿

退会済みユーザー
answer CHANGED
@@ -1,3 +1,9 @@
1
+ **追記:**
2
+ この解答欄のrunner.pyと別の回答のenvs.pyを使ってください。
3
+
4
+ ---
5
+
6
+
1
7
  **■動かすまで**
2
8
  コメントにも書きましたが、gym側は環境を提供するしかできないため、自前でQ学習をする環境を用意してあげないといけないようです。
3
9
 
@@ -12,6 +18,7 @@
12
18
  |low_bound|行動の取りえる選択肢の最小値|
13
19
  |high_bound|行動の取りえる選択肢の最大値|
14
20
 
21
+
15
22
  この「行動の取りえる選択肢数」は離散値である必要があるそうで、本当はいろいろめんどくさいことをやらないといけませんが、Takahiro Kuboさんのコードがそれを吸収してくれます。コードをひとまとめにした方が扱いやすいため、コピペで1つにまとめました。
16
23
 
17
24
  **■補足**
@@ -21,209 +28,224 @@
21
28
  Takahiro Kuboさん:素晴らしいコードを公開いただいた漢気にこの場を使って感謝いたします。ありがとうございます。
22
29
  shi.hiさん:強化学習に手を付けるきっかけを頂けました。ありがとうございます。
23
30
 
24
- envs.py
31
+ runner.py
25
32
  ```Python3
33
+ # Original code was provided on https://github.com/icoxfog417/techcircle_openai_handson
34
+ # that provided as MIT license by Takahiro Kubo.
35
+ # This was modified from "handson3.py".
36
+
26
- import gym.spaces
37
+ import os
27
- import numpy as np
28
- import pandas
38
+ import sys
39
+
29
40
  import math
30
- import matplotlib.pyplot as plt
41
+ import argparse
31
- import time
42
+ import gym
32
- import random
33
43
 
34
- class Game(gym.core.Env):
35
- #初期条件や各種変数の初期格納する。
36
- def __init__(self):
37
- self.hunter_Position_X=random.randint(0,5)
38
- self.hunter_Position_Y=random.randint(0,5)
39
- # print("鬼の初期位置は"+str(self.hunter_Position_X),self.hunter_Position_Y)
40
- #selfでグローバル変数化している。鬼のx,y座標をランダムに配置。
41
- self.fugitive_Position_X=random.randint(0,5)
42
- self.fugitive_Position_Y=random.randint(0,5)
43
- # print("逃亡者の初期位置は"+str(self.fugitive_Position_X),self.fugitive_Position_Y)
44
- #selfでグローバル変数化している。逃亡者のx,y座標をランダムに配置。fugitiveは逃亡者という意味。
45
- while self.hunter_Position_X == self.fugitive_Position_X and self.hunter_Position_Y == self.fugitive_Position_Y:
46
- self.hunter_Position_X=random.randint(0,5)
47
- self.hunter_Position_Y=random.randint(0,5)
48
- #print(self.hunter_Position_X,self.hunter_Position_Y)
49
- #逃亡者と鬼の位置が完全に一致している場合、鬼の初期位置を再度決める。
50
- self.game_count=0
51
- #1ゲームで行動できる上限を設定をしている。今回は10回とする。
52
- self.initial_distance=int(100*math.sqrt((self.hunter_Position_X-self.fugitive_Position_X)**2+(self.hunter_Position_Y-self.fugitive_Position_Y)**2))
53
- # print("初期の距離は"+str(self.initial_distance))
54
- #鬼と逃亡者の距離を定義する。ただの三平方の定理。自然数で処理するため100倍した。
55
- self.lists = []
56
- #距離を格納するリスト。
57
- self.current_hunter_profit_lists = []
58
- #鬼の報酬を各ステップごとに加える。
59
- self.current_fugitive_profit_lists = []
60
- #逃亡者の報酬を各ステップごとに加える。
61
44
 
62
- self.action_space = gym.spaces.Discrete(4)
63
- low = np.array([0, 0, 0, 0])
64
- high = np.array([5, 5, 5, 5])
65
- self.observation_space = gym.spaces.Box(low, high, dtype=np.int64)
45
+ RECORD_PATH = os.path.join(os.path.dirname(__file__), "./upload")
66
- #逃走エリアを定義している。
67
- self.hunter_reward=0
68
- self.fugitive_reward=0
69
- #鬼と逃亡者の報酬を0で初期化している。
70
- self.learn_count=0
71
- #学習回数を10000回と制限。
72
- self.lists.append(self.initial_distance)
46
+ from collections import defaultdict
73
- #開始時の距離を格納する。
47
+ import numpy as np
74
48
 
49
+ ####
75
- def step(self,action):
50
+ class COMMON():
76
- self.game_count += 1
77
- self.learn_count += 1
51
+ # target_env = "myenv-v1" # "CartPole-v0"
78
- # print("学習回数は",self.learn_count)
52
+ # target_env = "CartPole-v0"
79
- if action == 0 and self.hunter_Position_X < 5:
53
+ target_env = "myenv-v1"
80
- self.hunter_Position_X += 1
81
- if action == 1 and self.hunter_Position_X > 0:
82
- self.hunter_Position_X -= 1
83
- if action == 2 and self.hunter_Position_Y < 5:
84
- self.hunter_Position_Y += 1
85
- if action == 3 and self.hunter_Position_Y > 0:
86
- self.hunter_Position_Y -= 1
87
- # print("鬼の位置は"+str(self.hunter_Position_X),self.hunter_Position_Y)
88
- # print("逃亡者の位置は"+str(self.fugitive_Position_X),self.fugitive_Position_Y)
89
54
 
90
- #鬼の行動を4つ設け選択できるようにする。上下左右に移動できる。
55
+ if target_env == "" "CartPole-v0":
56
+ bins_size = [3, 3, 8, 5] # number of splitted parameters
57
+ low_bound= [None, -0.5, None, -math.radians(50)] # Limit of minimum value for each parameter
58
+ high_bound= [None, 0.5, None, math.radians(50)] # Limit of maximum value for each parameter
91
59
 
92
- if action == 0 and self.hunter_Position_X == 5:
93
- pass
60
+ else:
61
+ bins_size= [5, 5, 5, 5]
94
- if action == 1 and self.hunter_Position_X == 0:
62
+ low_bound= [0, 0, 0, 0] # Limit of minimum value for each parameter
63
+ high_bound= [4, 4, 4, 4] # Limit of maximum value for each parameter
95
- pass
64
+ ####
96
- if action == 2 and self.hunter_Position_Y == 5:
65
+ # Copied from "q.py"
97
- pass
66
+ class Q():
98
- if action == 3 and self.hunter_Position_Y == 0:
99
- pass
100
- #例外処理としてエリア外に出る行為は1ターン無駄に消費する事とする。andは&と書くと想定外の動作となった為使用禁止。
101
- # time.sleep(0.01)
102
- #間隔を0.01秒とする。
103
- self.d = self.cal_distance(h_X = self.hunter_Position_X , h_Y = self.hunter_Position_Y , f_X = self.fugitive_Position_X , f_Y = self.fugitive_Position_Y)
104
- self.lists.append(self.d)
105
- #距離を格納
106
- self.observation = (self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y)
107
- #鬼と逃亡者の位置を毎回格納する。
108
67
 
109
- hunter_reward,fugitive_reward=self.calc_profit()
110
- #報酬はcalc_profitcalc_profit関数で計算するのでそちらを参照。
111
- # print("鬼の報酬は"+str(hunter_reward),"逃亡者の報酬は"+str(fugitive_reward))
112
- print("鬼の総合報酬は",sum(self.current_hunter_profit_lists),"逃亡者の総合報酬は",sum(self.current_fugitive_profit_lists))
68
+ def __init__(self, n_actions, observation_space, bin_size, low_bound=None, high_bound=None, initial_mean=0.0, initial_std=0.0):
69
+ self.n_actions = n_actions
70
+ self._observation_dimension = 1
71
+ for d in observation_space.shape:
72
+ self._observation_dimension *= d
113
73
 
74
+ self._bin_sizes = bin_size if isinstance(bin_size, list) else [bin_size] * self._observation_dimension
75
+ self._dimension_bins = []
76
+ for i, low, high in self._low_high_iter(observation_space, low_bound, high_bound):
114
- is_end = self.reset()
77
+ b_size = self._bin_sizes[i]
78
+ bins = self._make_bins(low, high, b_size)
79
+ self._dimension_bins.append(bins)
115
80
 
116
- # print("return値は",np.array(self.observation),hunter_reward,action)
117
- return np.array(self.observation),hunter_reward,action,{}
81
+ # if we encounter the new observation, we initialize action evaluations
118
- #値は4つ必要。学習が良くない時は上記の変数値を変える必要あり。行動を決める要素を入れる。
82
+ self.table = defaultdict(lambda: initial_std * np.random.randn(self.n_actions) + initial_mean)
119
83
 
84
+ @classmethod
85
+ def _make_bins(cls, low, high, bin_size):
86
+ bins = np.arange(low, high, (float(high) - float(low)) / (bin_size - 2)) # exclude both ends
87
+ if min(bins) < 0 and 0 not in bins:
88
+ bins = np.sort(np.append(bins, [0])) # 0 centric bins
120
- #if action == 4:
89
+ return bins
121
- #self.fugitive_Position_X += 1
122
- #if action == 5:
123
- #self.fugitive_Position_X -= 1
124
- #if action == 6:
125
- #self.fugitive_Position_Y += 1
126
- #if action == 7:
127
- #self.fugitive_Position_Y -= 1
128
90
 
91
+ @classmethod
92
+ def _low_high_iter(cls, observation_space, low_bound, high_bound):
93
+ lows = observation_space.low
94
+ highs = observation_space.high
129
- def reset_position(self):
95
+ for i in range(len(lows)):
96
+ low = lows[i]
130
- hunter_Position_X=random.randint(0,5)
97
+ if low_bound is not None:
131
- hunter_Position_Y=random.randint(0,5)
132
- fugitive_Position_X=random.randint(0,5)
133
- fugitive_Position_Y=random.randint(0,5)
134
- while hunter_Position_X == fugitive_Position_X and hunter_Position_Y == fugitive_Position_Y:
98
+ _low_bound = low_bound if not isinstance(low_bound, list) else low_bound[i]
135
- hunter_Position_X=random.randint(0,5)
136
- hunter_Position_Y=random.randint(0,5)
137
- print("リセットされました!!!")
138
- print()
139
- return hunter_Position_X,hunter_Position_Y,fugitive_Position_X,fugitive_Position_Y
99
+ low = low if _low_bound is None else max(low, _low_bound)
140
- #返り値を残しておく。
141
- #1ゲームの終了条件を満たしたときに行う指示を記載。
142
- #鬼、逃亡者をランダムに配置する。
143
100
 
144
- def cal_distance(self , h_X , h_Y ,f_X ,f_Y):
145
- distance = int(100*math.sqrt((h_X-f_X)**2 +(h_Y-f_Y)**2))
146
- return distance
101
+ high = highs[i]
102
+ if high_bound is not None:
103
+ _high_bound = high_bound if not isinstance(high_bound, list) else high_bound[i]
104
+ high = high if _high_bound is None else min(high, _high_bound)
147
105
 
148
- def calc_profit(self):
149
- i= self.game_count
150
- if i <= 10 and self.lists[i] == 0:
151
- self.hunter_reward += 1
152
- self.fugitive_reward -= 1
153
- current_hunter_reward = 1
154
- current_fugitive_reward = -1
155
- self.current_hunter_profit_lists.append(current_hunter_reward)
156
- self.current_fugitive_profit_lists.append(current_fugitive_reward)
157
- # print("確保成功!!!")
158
- self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y = self.reset_position()
159
- self.game_count = 0
160
- self.lists = []
106
+ yield i, low, high
161
- self.lists.append(self.cal_distance(self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y))
162
- #10回の行動以下で鬼が確保できた時の報酬を定義している。また距離のリストやゲームカウントを初期化している。
163
107
 
164
- elif i == 10 and (0 not in self.lists):
165
- self.hunter_reward -= 1
166
- self.fugitive_reward += 1
167
- current_hunter_reward = -1
168
- current_fugitive_reward = 1
169
- self.current_hunter_profit_lists.append(current_hunter_reward)
108
+ def observation_to_state(self, observation,target_env):
170
- self.current_fugitive_profit_lists.append(current_fugitive_reward)
171
- # print("確保失敗!!!")
109
+ if target_env == "CartPole-v0":
172
- self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y = self.reset_position()
173
- self.game_count = 0
174
- self.lists = []
110
+ state = 0
175
- self.lists.append(self.cal_distance(self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y))
176
- #10回の行動以下で鬼が確保出来なかった時の報酬を定義している。また距離のリストやゲームカウントを初期化している。
111
+ # caution: bin_size over 10 will not work accurately
112
+ unit = max(self._bin_sizes)
177
113
 
178
- elif i <= 10 and self.lists[i-1] < self.lists[i]:
114
+ for d, o in enumerate(observation.flatten()):
179
- self.hunter_reward -= 1
180
- self.fugitive_reward += 1
181
- current_hunter_reward = -1
182
- current_fugitive_reward = 1
183
- self.current_hunter_profit_lists.append(current_hunter_reward)
184
- self.current_fugitive_profit_lists.append(current_fugitive_reward)
115
+ state = state + np.digitize(o, self._dimension_bins[d]) * pow(unit, d) # bin_size numeral system
185
- # print("逃げられてるよ!!!")
116
+ else:
186
- #前回ステップと今回のステップで距離を比較して報酬を定義している。
187
117
 
188
- elif i <= 10 and self.lists[i-1] > self.lists[i]:
189
- self.hunter_reward += 1
118
+ state = 0
190
- self.fugitive_reward -= 1
191
- current_hunter_reward = 1
119
+ unit = max(self._bin_sizes)
192
- current_fugitive_reward = -1
193
- self.current_hunter_profit_lists.append(current_hunter_reward)
194
- self.current_fugitive_profit_lists.append(current_fugitive_reward)
195
- # print("距離を詰めてるね!!!")
196
- #前回ステップと今回のステップで距離を比較して報酬を定義している。
197
120
 
198
- elif i <= 10 and self.lists[i-1] == self.lists[i]:
199
- self.hunter_reward += 0
121
+ if observation is None:
122
+ pass
200
- self.fugitive_reward += 0
123
+ else:
201
- current_hunter_reward = 0
202
- current_fugitive_reward = 0
203
- self.current_hunter_profit_lists.append(current_hunter_reward)
124
+ for d, o in enumerate(np.asarray(observation).flatten()):
204
- self.current_fugitive_profit_lists.append(current_fugitive_reward)
125
+ state = state + np.digitize(o, self._dimension_bins[d]) * pow(unit, d) # bin_size numeral system
205
- # print("距離が変わってないよ!!!")
126
+ return state
206
- #前回ステップと今回のステップで距離を比較して報酬を定義している。
207
127
 
128
+ def values(self, observation,target_env):
129
+ state = self.observation_to_state(observation,target_env)
130
+ return self.table[state]
131
+
132
+ ####
133
+ # Copied from "agent.py"
134
+ import random
135
+ import numpy as np
136
+ class Agent():
137
+
138
+ def __init__(self, q, epsilon=0.05):
139
+ self.q = q
140
+ self.epsilon = epsilon
141
+
142
+ def act(self, observation,target_env):
143
+ # your code here
144
+ action = -1
145
+ if np.random.random() < self.epsilon:
146
+ action = np.random.choice(self.q.n_actions)
208
147
  else:
209
- pass
148
+ action = np.argmax(self.q.values(observation,target_env))
210
149
 
211
- return current_hunter_reward,current_fugitive_reward
150
+ return action
212
151
 
152
+ ####
213
- #def Linear_function:
153
+ # Copied from "trainer.py"
214
- #Y_intercept_1 = self.hunter_Position_Y - math.sqrt(3)*self.hunter_Position_X
215
- #Y_intercept_2 = self.hunter_Position_Y + math.sqrt(3)*self.hunter_Position_X
216
- #Y_intercept_3 = self.hunter_Position_Y - (1/math.sqrt(3))*self.hunter_Position_X
217
- #Y_intercept_4 = self.hunter_Position_Y + (1/math.sqrt(3))*self.hunter_Position_X
218
- #Y = math.sqrt(3)X + b
154
+ from collections import deque
219
155
 
220
- #プログラミングは書いた通りにしか動かない。
221
156
 
222
- def reset(self):
157
+ class Trainer():
223
- if self.learn_count == 0:
224
- is_end = True
225
- else:
226
- is_end = False
227
- #リセットする条件は学習回数を満了した時のみ。その際に報酬をリセットする。
228
158
 
159
+ def __init__(self, agent,target_env, gamma=0.95, learning_rate=0.1, learning_rate_decay=None, epsilon=0.05, epsilon_decay=None, max_step=-1):
160
+ self.agent = agent
161
+ self.target_env = target_env
162
+ self.gamma = gamma
163
+ self.learning_rate = learning_rate
164
+ self.learning_rate_decay = learning_rate_decay
165
+ self.epsilon = epsilon
166
+ self.epsilon_decay = epsilon_decay
167
+ self.max_step = max_step
168
+
169
+ def train(self, env, episode_count, render=False):
170
+ default_epsilon = self.agent.epsilon
171
+ self.agent.epsilon = self.epsilon
172
+ values = []
173
+ steps = deque(maxlen=100)
174
+ lr = self.learning_rate
175
+ for i in range(episode_count):
176
+ obs = env.reset()
177
+ step = 0
178
+ done = False
179
+ while not done:
180
+ if render:
181
+ if self.target_env == "myenv-v1":
182
+ print("Not supported yet.")
183
+ else:
184
+ env.render()
185
+
186
+ action = self.agent.act(obs,self.target_env)
187
+ next_obs, reward, done, _ = env.step(action)
188
+
189
+ state = self.agent.q.observation_to_state(obs,self.target_env)
190
+ future = 0 if done else np.max(self.agent.q.values(next_obs,self.target_env))
191
+ value = self.agent.q.table[state][action]
192
+ self.agent.q.table[state][action] += lr * (reward + self.gamma * future - value)
193
+
194
+ obs = next_obs
195
+ values.append(value)
196
+ step += 1
197
+ if self.max_step > 0 and step > self.max_step:
198
+ done = True
199
+ else:
200
+ mean = np.mean(values)
201
+ steps.append(step)
202
+ mean_step = np.mean(steps)
203
+ print("Episode {}: {}steps(avg{}). epsilon={:.3f}, lr={:.3f}, mean q value={:.2f}".format(
204
+ i, step, mean_step, self.agent.epsilon, lr, mean)
205
+ )
206
+
207
+ if self.epsilon_decay is not None:
208
+ self.agent.epsilon = self.epsilon_decay(self.agent.epsilon, i)
209
+ if self.learning_rate_decay is not None:
210
+ lr = self.learning_rate_decay(lr, i)
211
+
212
+
213
+
214
+
215
+ def main(episodes, render):
216
+ env = gym.make(COMMON.target_env)
217
+
218
+ q = Q(
219
+ env.action_space.n,
220
+ env.observation_space,
221
+ bin_size= COMMON.bins_size,
222
+ low_bound= COMMON.low_bound,
223
+ high_bound= COMMON.high_bound
224
+ )
225
+ agent = Agent(q, epsilon=0.05)
226
+
227
+ learning_decay = lambda lr, t: max(0.1, min(0.5, 1.0 - math.log10((t + 1) / 25)))
228
+ epsilon_decay = lambda eps, t: max(0.01, min(1.0, 1.0 - math.log10((t + 1) / 25)))
229
+ trainer = Trainer(
230
+ agent,
231
+ target_env = COMMON.target_env,
232
+ gamma=0.99,
233
+ learning_rate=0.5, learning_rate_decay=learning_decay,
234
+ epsilon=1.0, epsilon_decay=epsilon_decay,
235
+ max_step=250)
236
+
237
+
238
+ trainer.train(env, episode_count=episodes, render=render)
239
+
240
+
241
+
242
+ if __name__ == "__main__":
243
+ parser = argparse.ArgumentParser(description="train & run cartpole ")
244
+ parser.add_argument("--episode", type=int, default=1000, help="episode to train")
245
+ parser.add_argument("--render", action="store_true", help="render the screen")
246
+
247
+ args = parser.parse_args()
248
+
249
+ main(args.episode, args.render)
250
+
229
251
  ```

1

実際のコード添付

2020/11/22 18:41

投稿

退会済みユーザー
answer CHANGED
@@ -21,256 +21,209 @@
21
21
  Takahiro Kuboさん:素晴らしいコードを公開いただいた漢気にこの場を使って感謝いたします。ありがとうございます。
22
22
  shi.hiさん:強化学習に手を付けるきっかけを頂けました。ありがとうございます。
23
23
 
24
-
24
+ envs.py
25
25
  ```Python3
26
- # Original code was provided on https://github.com/icoxfog417/techcircle_openai_handson
27
- # that provided as MIT license by Takahiro Kubo.
28
- # This was modified from "handson3.py".
29
-
30
- import os
26
+ import gym.spaces
27
+ import numpy as np
31
- import sys
28
+ import pandas
32
-
33
29
  import math
34
- import argparse
30
+ import matplotlib.pyplot as plt
35
- import gym
31
+ import time
36
- from trainer import Trainer
37
-
38
-
39
- RECORD_PATH = os.path.join(os.path.dirname(__file__), "./upload")
40
- from collections import defaultdict
41
- import numpy as np
42
-
43
- ####
44
- class COMMON():
45
- # target_env = "myenv-v1" # "CartPole-v0"
46
- # target_env = "CartPole-v0"
47
- target_env = "myenv-v1"
48
-
49
- if target_env == "" "CartPole-v0":
50
- bins_size = [3, 3, 8, 5] # number of splitted parameters
51
- low_bound= [None, -0.5, None, -math.radians(50)] # Limit of minimum value for each parameter
52
- high_bound= [None, 0.5, None, math.radians(50)] # Limit of maximum value for each parameter
53
-
54
- else:
55
- bins_size= [5, 5, 5, 5]
56
- low_bound= [0, 0, 0, 0] # Limit of minimum value for each parameter
57
- high_bound= [4, 4, 4, 4] # Limit of maximum value for each parameter
58
- ####
59
- # Copied from "q.py"
60
- class Q():
61
-
62
- def __init__(self, n_actions, observation_space, bin_size, low_bound=None, high_bound=None, initial_mean=0.0, initial_std=0.0):
63
- self.n_actions = n_actions
64
- self._observation_dimension = 1
65
- for d in observation_space.shape:
66
- self._observation_dimension *= d
67
-
68
- self._bin_sizes = bin_size if isinstance(bin_size, list) else [bin_size] * self._observation_dimension
69
- self._dimension_bins = []
70
- for i, low, high in self._low_high_iter(observation_space, low_bound, high_bound):
71
- b_size = self._bin_sizes[i]
72
- bins = self._make_bins(low, high, b_size)
73
- self._dimension_bins.append(bins)
74
-
75
- # if we encounter the new observation, we initialize action evaluations
76
- self.table = defaultdict(lambda: initial_std * np.random.randn(self.n_actions) + initial_mean)
77
-
78
- @classmethod
79
- def _make_bins(cls, low, high, bin_size):
80
- bins = np.arange(low, high, (float(high) - float(low)) / (bin_size - 2)) # exclude both ends
81
- if min(bins) < 0 and 0 not in bins:
82
- bins = np.sort(np.append(bins, [0])) # 0 centric bins
83
- return bins
84
-
85
- @classmethod
86
- def _low_high_iter(cls, observation_space, low_bound, high_bound):
87
- lows = observation_space.low
88
- highs = observation_space.high
89
- for i in range(len(lows)):
90
- low = lows[i]
91
- if low_bound is not None:
92
- _low_bound = low_bound if not isinstance(low_bound, list) else low_bound[i]
93
- low = low if _low_bound is None else max(low, _low_bound)
94
-
95
- high = highs[i]
96
- if high_bound is not None:
97
- _high_bound = high_bound if not isinstance(high_bound, list) else high_bound[i]
98
- high = high if _high_bound is None else min(high, _high_bound)
99
-
100
- yield i, low, high
101
-
102
- def observation_to_state(self, observation,target_env):
103
- if target_env == "CartPole-v0":
104
- state = 0
105
- # caution: bin_size over 10 will not work accurately
106
- unit = max(self._bin_sizes)
107
-
108
- for d, o in enumerate(observation.flatten()):
109
- state = state + np.digitize(o, self._dimension_bins[d]) * pow(unit, d) # bin_size numeral system
110
- else:
111
-
112
- state = 0
113
- unit = max(self._bin_sizes)
114
-
115
- if observation is None:
116
- pass
117
- else:
118
- for d, o in enumerate(np.asarray(observation).flatten()):
119
- state = state + np.digitize(o, self._dimension_bins[d]) * pow(unit, d) # bin_size numeral system
120
- return state
121
-
122
- def values(self, observation,target_env):
123
- state = self.observation_to_state(observation,target_env)
124
- return self.table[state]
125
-
126
- ####
127
- # Copied from "agent.py"
128
32
  import random
129
- import numpy as np
130
- class Agent():
131
33
 
34
+ class Game(gym.core.Env):
35
+ #初期条件や各種変数の初期格納する。
132
- def __init__(self, q, epsilon=0.05):
36
+ def __init__(self):
37
+ self.hunter_Position_X=random.randint(0,5)
38
+ self.hunter_Position_Y=random.randint(0,5)
39
+ # print("鬼の初期位置は"+str(self.hunter_Position_X),self.hunter_Position_Y)
40
+ #selfでグローバル変数化している。鬼のx,y座標をランダムに配置。
41
+ self.fugitive_Position_X=random.randint(0,5)
42
+ self.fugitive_Position_Y=random.randint(0,5)
43
+ # print("逃亡者の初期位置は"+str(self.fugitive_Position_X),self.fugitive_Position_Y)
44
+ #selfでグローバル変数化している。逃亡者のx,y座標をランダムに配置。fugitiveは逃亡者という意味。
45
+ while self.hunter_Position_X == self.fugitive_Position_X and self.hunter_Position_Y == self.fugitive_Position_Y:
46
+ self.hunter_Position_X=random.randint(0,5)
47
+ self.hunter_Position_Y=random.randint(0,5)
48
+ #print(self.hunter_Position_X,self.hunter_Position_Y)
49
+ #逃亡者と鬼の位置が完全に一致している場合、鬼の初期位置を再度決める。
50
+ self.game_count=0
51
+ #1ゲームで行動できる上限を設定をしている。今回は10回とする。
52
+ self.initial_distance=int(100*math.sqrt((self.hunter_Position_X-self.fugitive_Position_X)**2+(self.hunter_Position_Y-self.fugitive_Position_Y)**2))
53
+ # print("初期の距離は"+str(self.initial_distance))
54
+ #鬼と逃亡者の距離を定義する。ただの三平方の定理。自然数で処理するため100倍した。
133
- self.q = q
55
+ self.lists = []
134
- self.epsilon = epsilon
56
+ #距離を格納するリスト。
135
-
136
- def act(self, observation,target_env):
57
+ self.current_hunter_profit_lists = []
137
- # your code here
58
+ #鬼の報酬を各ステップごとに加える。
138
- action = -1
139
- if np.random.random() < self.epsilon:
140
- action = np.random.choice(self.q.n_actions)
59
+ self.current_fugitive_profit_lists = []
141
- else:
142
- action = np.argmax(self.q.values(observation,target_env))
143
-
144
- return action
145
-
146
- ####
147
- # Copied from "trainer.py"
148
- from collections import deque
60
+ #逃亡者の報酬を各ステップごとに加える。
149
61
 
62
+ self.action_space = gym.spaces.Discrete(4)
63
+ low = np.array([0, 0, 0, 0])
64
+ high = np.array([5, 5, 5, 5])
65
+ self.observation_space = gym.spaces.Box(low, high, dtype=np.int64)
66
+ #逃走エリアを定義している。
67
+ self.hunter_reward=0
68
+ self.fugitive_reward=0
69
+ #鬼と逃亡者の報酬を0で初期化している。
70
+ self.learn_count=0
71
+ #学習回数を10000回と制限。
72
+ self.lists.append(self.initial_distance)
73
+ #開始時の距離を格納する。
150
74
 
151
- class Trainer():
75
+ def step(self,action):
76
+ self.game_count += 1
77
+ self.learn_count += 1
78
+ # print("学習回数は",self.learn_count)
79
+ if action == 0 and self.hunter_Position_X < 5:
80
+ self.hunter_Position_X += 1
81
+ if action == 1 and self.hunter_Position_X > 0:
82
+ self.hunter_Position_X -= 1
83
+ if action == 2 and self.hunter_Position_Y < 5:
84
+ self.hunter_Position_Y += 1
85
+ if action == 3 and self.hunter_Position_Y > 0:
86
+ self.hunter_Position_Y -= 1
87
+ # print("鬼の位置は"+str(self.hunter_Position_X),self.hunter_Position_Y)
88
+ # print("逃亡者の位置は"+str(self.fugitive_Position_X),self.fugitive_Position_Y)
152
89
 
153
- def __init__(self, agent,target_env, gamma=0.95, learning_rate=0.1, learning_rate_decay=None, epsilon=0.05, epsilon_decay=None, max_step=-1):
154
- self.agent = agent
155
- self.gamma = gamma
156
- self.learning_rate = learning_rate
90
+ #鬼の行動を4つ設け選択できるようにする。上下左右に移動できる。
157
- self.learning_rate_decay = learning_rate_decay
158
- self.epsilon = epsilon
159
- self.epsilon_decay = epsilon_decay
160
- self.max_step = max_step
161
- self.target_env = target_env
162
91
 
163
- def train(self, env, episode_count, render=False):
164
- default_epsilon = self.agent.epsilon
92
+ if action == 0 and self.hunter_Position_X == 5:
93
+ pass
94
+ if action == 1 and self.hunter_Position_X == 0:
95
+ pass
96
+ if action == 2 and self.hunter_Position_Y == 5:
97
+ pass
98
+ if action == 3 and self.hunter_Position_Y == 0:
99
+ pass
100
+ #例外処理としてエリア外に出る行為は1ターン無駄に消費する事とする。andは&と書くと想定外の動作となった為使用禁止。
101
+ # time.sleep(0.01)
102
+ #間隔を0.01秒とする。
103
+ self.d = self.cal_distance(h_X = self.hunter_Position_X , h_Y = self.hunter_Position_Y , f_X = self.fugitive_Position_X , f_Y = self.fugitive_Position_Y)
165
- self.agent.epsilon = self.epsilon
104
+ self.lists.append(self.d)
166
- values = []
167
- steps = deque(maxlen=100)
168
- lr = self.learning_rate
169
- for i in range(episode_count):
170
- obs = env.reset()
171
- step = 0
105
+ #距離を格納
172
- done = False
173
- while not done:
174
- if render:
175
- # env.render()
176
- print("env.render() is not supported yet.")
177
- action = self.agent.act(obs,self.target_env)
178
- next_obs, reward, done, _ = env.step(action)
179
- state = self.agent.q.observation_to_state(obs,self.target_env)
180
- future = 0 if done else np.max(self.agent.q.values(next_obs,self.target_env))
106
+ self.observation = (self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y)
181
- value = self.agent.q.table[state][action]
107
+ #鬼と逃亡者の位置を毎回格納する。
182
- self.agent.q.table[state][action] += lr * (reward + self.gamma * future - value)
183
108
 
184
- obs = next_obs
185
- values.append(value)
186
- step += 1
187
- if self.max_step > 0 and step > self.max_step:
188
- done = True
189
- else:
190
- mean = np.mean(values)
191
- steps.append(step)
192
- mean_step = np.mean(steps)
193
- print("Episode {}: {}steps(avg{}). epsilon={:.3f}, lr={:.3f}, mean q value={:.2f}".format(
194
- i, step, mean_step, self.agent.epsilon, lr, mean)
195
- )
196
-
197
- if self.epsilon_decay is not None:
198
- self.agent.epsilon = self.epsilon_decay(self.agent.epsilon, i)
109
+ hunter_reward,fugitive_reward=self.calc_profit()
199
- if self.learning_rate_decay is not None:
110
+ #報酬はcalc_profitcalc_profit関数で計算するのでそちらを参照。
200
- lr = self.learning_rate_decay(lr, i)
111
+ # print("鬼の報酬は"+str(hunter_reward),"逃亡者の報酬は"+str(fugitive_reward))
112
+ print("鬼の総合報酬は",sum(self.current_hunter_profit_lists),"逃亡者の総合報酬は",sum(self.current_fugitive_profit_lists))
201
113
 
202
-
203
- def main(episodes, render):
114
+ is_end = self.reset()
204
- env = gym.make(COMMON.target_env)
205
115
 
206
- q = Q(
207
- env.action_space.n,
116
+ # print("return値は",np.array(self.observation),hunter_reward,action)
208
- env.observation_space,
117
+ return np.array(self.observation),hunter_reward,action,{}
209
- bin_size= COMMON.bins_size,
210
- low_bound= COMMON.low_bound,
211
- high_bound= COMMON.high_bound
212
- )
213
- agent = Agent(q, epsilon=0.05)
118
+ #値は4つ必要。学習が良くない時は上記の変数値を変える必要あり。行動を決める要素を入れる。
214
119
 
215
- learning_decay = lambda lr, t: max(0.1, min(0.5, 1.0 - math.log10((t + 1) / 25)))
216
- epsilon_decay = lambda eps, t: max(0.01, min(1.0, 1.0 - math.log10((t + 1) / 25)))
217
- trainer = Trainer(
120
+ #if action == 4:
218
- agent,
219
- target_env = COMMON.target_env,
220
- gamma=0.99,
221
- learning_rate=0.5, learning_rate_decay=learning_decay,
222
- epsilon=1.0, epsilon_decay=epsilon_decay,
121
+ #self.fugitive_Position_X += 1
223
- max_step=250)
122
+ #if action == 5:
123
+ #self.fugitive_Position_X -= 1
124
+ #if action == 6:
125
+ #self.fugitive_Position_Y += 1
126
+ #if action == 7:
127
+ #self.fugitive_Position_Y -= 1
224
128
 
129
+ def reset_position(self):
130
+ hunter_Position_X=random.randint(0,5)
131
+ hunter_Position_Y=random.randint(0,5)
132
+ fugitive_Position_X=random.randint(0,5)
133
+ fugitive_Position_Y=random.randint(0,5)
134
+ while hunter_Position_X == fugitive_Position_X and hunter_Position_Y == fugitive_Position_Y:
135
+ hunter_Position_X=random.randint(0,5)
136
+ hunter_Position_Y=random.randint(0,5)
137
+ print("リセットされました!!!")
138
+ print()
139
+ return hunter_Position_X,hunter_Position_Y,fugitive_Position_X,fugitive_Position_Y
140
+ #返り値を残しておく。
141
+ #1ゲームの終了条件を満たしたときに行う指示を記載。
142
+ #鬼、逃亡者をランダムに配置する。
225
143
 
144
+ def cal_distance(self , h_X , h_Y ,f_X ,f_Y):
226
- trainer.train(env, episode_count=episodes, render=render)
145
+ distance = int(100*math.sqrt((h_X-f_X)**2 +(h_Y-f_Y)**2))
146
+ return distance
227
147
 
148
+ def calc_profit(self):
149
+ i= self.game_count
150
+ if i <= 10 and self.lists[i] == 0:
151
+ self.hunter_reward += 1
152
+ self.fugitive_reward -= 1
153
+ current_hunter_reward = 1
154
+ current_fugitive_reward = -1
155
+ self.current_hunter_profit_lists.append(current_hunter_reward)
156
+ self.current_fugitive_profit_lists.append(current_fugitive_reward)
157
+ # print("確保成功!!!")
158
+ self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y = self.reset_position()
159
+ self.game_count = 0
160
+ self.lists = []
161
+ self.lists.append(self.cal_distance(self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y))
162
+ #10回の行動以下で鬼が確保できた時の報酬を定義している。また距離のリストやゲームカウントを初期化している。
228
163
 
164
+ elif i == 10 and (0 not in self.lists):
165
+ self.hunter_reward -= 1
166
+ self.fugitive_reward += 1
167
+ current_hunter_reward = -1
168
+ current_fugitive_reward = 1
169
+ self.current_hunter_profit_lists.append(current_hunter_reward)
170
+ self.current_fugitive_profit_lists.append(current_fugitive_reward)
171
+ # print("確保失敗!!!")
172
+ self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y = self.reset_position()
173
+ self.game_count = 0
174
+ self.lists = []
175
+ self.lists.append(self.cal_distance(self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y))
176
+ #10回の行動以下で鬼が確保出来なかった時の報酬を定義している。また距離のリストやゲームカウントを初期化している。
229
177
 
178
+ elif i <= 10 and self.lists[i-1] < self.lists[i]:
179
+ self.hunter_reward -= 1
180
+ self.fugitive_reward += 1
181
+ current_hunter_reward = -1
182
+ current_fugitive_reward = 1
183
+ self.current_hunter_profit_lists.append(current_hunter_reward)
184
+ self.current_fugitive_profit_lists.append(current_fugitive_reward)
230
- if __name__ == "__main__":
185
+ # print("逃げられてるよ!!!")
231
- parser = argparse.ArgumentParser(description="train & run cartpole ")
186
+ #前回ステップと今回のステップで距離を比較して報酬を定義している。
232
- parser.add_argument("--episode", type=int, default=1000, help="episode to train")
233
- parser.add_argument("--render", action="store_true", help="render the screen")
234
187
 
188
+ elif i <= 10 and self.lists[i-1] > self.lists[i]:
189
+ self.hunter_reward += 1
190
+ self.fugitive_reward -= 1
235
- args = parser.parse_args()
191
+ current_hunter_reward = 1
192
+ current_fugitive_reward = -1
193
+ self.current_hunter_profit_lists.append(current_hunter_reward)
194
+ self.current_fugitive_profit_lists.append(current_fugitive_reward)
195
+ # print("距離を詰めてるね!!!")
196
+ #前回ステップと今回のステップで距離を比較して報酬を定義している。
236
197
 
198
+ elif i <= 10 and self.lists[i-1] == self.lists[i]:
199
+ self.hunter_reward += 0
200
+ self.fugitive_reward += 0
201
+ current_hunter_reward = 0
202
+ current_fugitive_reward = 0
203
+ self.current_hunter_profit_lists.append(current_hunter_reward)
204
+ self.current_fugitive_profit_lists.append(current_fugitive_reward)
237
- main(args.episode, args.render)
205
+ # print("距離が変わってないよ!!!")
206
+ #前回ステップと今回のステップで距離を比較して報酬を定義している。
238
207
 
208
+ else:
209
+ pass
239
210
 
240
- ```
211
+ return current_hunter_reward,current_fugitive_reward
241
212
 
213
+ #def Linear_function:
214
+ #Y_intercept_1 = self.hunter_Position_Y - math.sqrt(3)*self.hunter_Position_X
215
+ #Y_intercept_2 = self.hunter_Position_Y + math.sqrt(3)*self.hunter_Position_X
216
+ #Y_intercept_3 = self.hunter_Position_Y - (1/math.sqrt(3))*self.hunter_Position_X
217
+ #Y_intercept_4 = self.hunter_Position_Y + (1/math.sqrt(3))*self.hunter_Position_X
218
+ #Y = math.sqrt(3)X + b
242
219
 
220
+ #プログラミングは書いた通りにしか動かない。
243
221
 
222
+ def reset(self):
244
- 鬼の総合報酬は -5 逃亡者の総合報酬は 5
223
+ if self.learn_count == 0:
245
- Episode 295: 2steps(avg1.3). epsilon=0.010, lr=0.100, mean q value=0.04
246
- 学習回数は 440
247
- 鬼の総合報酬は -4 逃亡者の総合報酬は 4
248
- 学習回数は 441
249
- 鬼の総合報酬は -3 逃亡者の総合報酬は 3
250
- 学習回数は 442
251
- リセットされました!!!
224
+ is_end = True
225
+ else:
226
+ is_end = False
227
+ #リセットする条件は学習回数を満了した時のみ。その際に報酬をリセットする。
252
228
 
253
- 鬼の総合報酬は -2 逃亡者の総合報酬は 2
254
- 学習回数は 443
229
+ ```
255
- 鬼の総合報酬は -1 逃亡者の総合報酬は 1
256
- 学習回数は 444
257
- 鬼の総合報酬は 0 逃亡者の総合報酬は 0
258
- Episode 296: 5steps(avg1.34). epsilon=0.010, lr=0.100, mean q value=0.04
259
- 学習回数は 445
260
- 鬼の総合報酬は 1 逃亡者の総合報酬は -1
261
- 学習回数は 446
262
- 鬼の総合報酬は 2 逃亡者の総合報酬は -2
263
- Episode 297: 2steps(avg1.35). epsilon=0.010, lr=0.100, mean q value=0.04
264
- 学習回数は 447
265
- 鬼の総合報酬は 1 逃亡者の総合報酬は -1
266
- 学習回数は 448
267
- 鬼の総合報酬は 2 逃亡者の総合報酬は -2
268
- Episode 298: 2steps(avg1.36). epsilon=0.010, lr=0.100, mean q value=0.04
269
- 学習回数は 449
270
- 鬼の総合報酬は 2 逃亡者の総合報酬は -2
271
- 学習回数は 450
272
- 鬼の総合報酬は 2 逃亡者の総合報酬は -2
273
- 学習回数は 451
274
- 鬼の総合報酬は 2 逃亡者の総合報酬は -2
275
- 学習回数は 452
276
- リセットされました!!!