open ai gymを使用して鬼ごっこの強化学習を作成しています。 まず鬼のみ動かせる状態としています。 ``` 発生している問題
ルールは作成済ですが、いざ学習してみると鬼の学習が全然できていない状態です。
10万回学習しても何故か上手く行かないです。
被疑個所としてreturn np.array(self.observation),hunter_reward,action,{}だと考えていますが、他の要因があるか分からないのでご教示いただけないでしょうか。
特になし ``` 該当のソースコード import gym.spaces import numpy as np import pandas import math import matplotlib.pyplot as plt import time import random class Game(gym.core.Env): #初期条件や各種変数の初期格納する。 def __init__(self): self.hunter_Position_X=random.randint(0,5) self.hunter_Position_Y=random.randint(0,5) print("鬼の初期位置は"+str(self.hunter_Position_X),self.hunter_Position_Y) #selfでグローバル変数化している。鬼のx,y座標をランダムに配置。 self.fugitive_Position_X=random.randint(0,5) self.fugitive_Position_Y=random.randint(0,5) print("逃亡者の初期位置は"+str(self.fugitive_Position_X),self.fugitive_Position_Y) #selfでグローバル変数化している。逃亡者のx,y座標をランダムに配置。fugitiveは逃亡者という意味。 while self.hunter_Position_X == self.fugitive_Position_X and self.hunter_Position_Y == self.fugitive_Position_Y: self.hunter_Position_X=random.randint(0,5) self.hunter_Position_Y=random.randint(0,5) #print(self.hunter_Position_X,self.hunter_Position_Y) #逃亡者と鬼の位置が完全に一致している場合、鬼の初期位置を再度決める。 self.game_count=0 #1ゲームで行動できる上限を設定をしている。今回は10回とする。 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)) print("初期の距離は"+str(self.initial_distance)) #鬼と逃亡者の距離を定義する。ただの三平方の定理。自然数で処理するため100倍した。 self.lists = [] #距離を格納するリスト。 self.current_hunter_profit_lists = [] #鬼の報酬を各ステップごとに加える。 self.current_fugitive_profit_lists = [] #逃亡者の報酬を各ステップごとに加える。 self.action_space = gym.spaces.Discrete(4) low = np.array([0, 0, 0, 0]) high = np.array([5, 5, 5, 5]) self.observation_space = gym.spaces.Box(low, high, dtype=np.int64) #逃走エリアを定義している。 self.hunter_reward=0 self.fugitive_reward=0 #鬼と逃亡者の報酬を0で初期化している。 self.learn_count=0 #学習回数を10000回と制限。 self.lists.append(self.initial_distance) #開始時の距離を格納する。 def step(self,action): self.game_count += 1 self.learn_count += 1 print("学習回数は",self.learn_count) if action == 0 and self.hunter_Position_X < 5: self.hunter_Position_X += 1 if action == 1 and self.hunter_Position_X > 0: self.hunter_Position_X -= 1 if action == 2 and self.hunter_Position_Y < 5: self.hunter_Position_Y += 1 if action == 3 and self.hunter_Position_Y > 0: self.hunter_Position_Y -= 1 print("鬼の位置は"+str(self.hunter_Position_X),self.hunter_Position_Y) print("逃亡者の位置は"+str(self.fugitive_Position_X),self.fugitive_Position_Y) #鬼の行動を4つ設け選択できるようにする。上下左右に移動できる。 if action == 0 and self.hunter_Position_X == 5: pass if action == 1 and self.hunter_Position_X == 0: pass if action == 2 and self.hunter_Position_Y == 5: pass if action == 3 and self.hunter_Position_Y == 0: pass #例外処理としてエリア外に出る行為は1ターン無駄に消費する事とする。andは&と書くと想定外の動作となった為使用禁止。 time.sleep(0.01) #間隔を0.01秒とする。 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) self.lists.append(self.d) #距離を格納 self.observation = (self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y) #鬼と逃亡者の位置を毎回格納する。 hunter_reward,fugitive_reward=self.calc_profit() #報酬はcalc_profitcalc_profit関数で計算するのでそちらを参照。 print("鬼の報酬は"+str(hunter_reward),"逃亡者の報酬は"+str(fugitive_reward)) print("鬼の総合報酬は",sum(self.current_hunter_profit_lists),"逃亡者の総合報酬は",sum(self.current_fugitive_profit_lists)) is_end = self.reset() print("return値は",np.array(self.observation),hunter_reward,action) return np.array(self.observation),hunter_reward,action,{} #値は4つ必要。学習が良くない時は上記の変数値を変える必要あり。行動を決める要素を入れる。 #if action == 4: #self.fugitive_Position_X += 1 #if action == 5: #self.fugitive_Position_X -= 1 #if action == 6: #self.fugitive_Position_Y += 1 #if action == 7: #self.fugitive_Position_Y -= 1 def reset_position(self): hunter_Position_X=random.randint(0,5) hunter_Position_Y=random.randint(0,5) fugitive_Position_X=random.randint(0,5) fugitive_Position_Y=random.randint(0,5) while hunter_Position_X == fugitive_Position_X and hunter_Position_Y == fugitive_Position_Y: hunter_Position_X=random.randint(0,5) hunter_Position_Y=random.randint(0,5) print("リセットされました!!!") print() return hunter_Position_X,hunter_Position_Y,fugitive_Position_X,fugitive_Position_Y #返り値を残しておく。 #1ゲームの終了条件を満たしたときに行う指示を記載。 #鬼、逃亡者をランダムに配置する。 def cal_distance(self , h_X , h_Y ,f_X ,f_Y): distance = int(100*math.sqrt((h_X-f_X)**2 +(h_Y-f_Y)**2)) return distance def calc_profit(self): i= self.game_count if i <= 10 and self.lists[i] == 0: self.hunter_reward += 1 self.fugitive_reward -= 1 current_hunter_reward = 1 current_fugitive_reward = -1 self.current_hunter_profit_lists.append(current_hunter_reward) self.current_fugitive_profit_lists.append(current_fugitive_reward) print("確保成功!!!") self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y = self.reset_position() self.game_count = 0 self.lists = [] self.lists.append(self.cal_distance(self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y)) #10回の行動以下で鬼が確保できた時の報酬を定義している。また距離のリストやゲームカウントを初期化している。 elif i == 10 and (0 not in self.lists): self.hunter_reward -= 1 self.fugitive_reward += 1 current_hunter_reward = -1 current_fugitive_reward = 1 self.current_hunter_profit_lists.append(current_hunter_reward) self.current_fugitive_profit_lists.append(current_fugitive_reward) print("確保失敗!!!") self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y = self.reset_position() self.game_count = 0 self.lists = [] self.lists.append(self.cal_distance(self.hunter_Position_X,self.hunter_Position_Y,self.fugitive_Position_X,self.fugitive_Position_Y)) #10回の行動以下で鬼が確保出来なかった時の報酬を定義している。また距離のリストやゲームカウントを初期化している。 elif i <= 10 and self.lists[i-1] < self.lists[i]: self.hunter_reward -= 1 self.fugitive_reward += 1 current_hunter_reward = -1 current_fugitive_reward = 1 self.current_hunter_profit_lists.append(current_hunter_reward) self.current_fugitive_profit_lists.append(current_fugitive_reward) print("逃げられてるよ!!!") #前回ステップと今回のステップで距離を比較して報酬を定義している。 elif i <= 10 and self.lists[i-1] > self.lists[i]: self.hunter_reward += 1 self.fugitive_reward -= 1 current_hunter_reward = 1 current_fugitive_reward = -1 self.current_hunter_profit_lists.append(current_hunter_reward) self.current_fugitive_profit_lists.append(current_fugitive_reward) print("距離を詰めてるね!!!") #前回ステップと今回のステップで距離を比較して報酬を定義している。 elif i <= 10 and self.lists[i-1] == self.lists[i]: self.hunter_reward += 0 self.fugitive_reward += 0 current_hunter_reward = 0 current_fugitive_reward = 0 self.current_hunter_profit_lists.append(current_hunter_reward) self.current_fugitive_profit_lists.append(current_fugitive_reward) print("距離が変わってないよ!!!") #前回ステップと今回のステップで距離を比較して報酬を定義している。 else: pass return current_hunter_reward,current_fugitive_reward #def Linear_function: #Y_intercept_1 = self.hunter_Position_Y - math.sqrt(3)*self.hunter_Position_X #Y_intercept_2 = self.hunter_Position_Y + math.sqrt(3)*self.hunter_Position_X #Y_intercept_3 = self.hunter_Position_Y - (1/math.sqrt(3))*self.hunter_Position_X #Y_intercept_4 = self.hunter_Position_Y + (1/math.sqrt(3))*self.hunter_Position_X #Y = math.sqrt(3)X + b #プログラミングは書いた通りにしか動かない。 def reset(self): if self.learn_count == 0: is_end = True else: is_end = False #リセットする条件は学習回数を満了した時のみ。その際に報酬をリセットする。 ```ここに言語名を入力
python
gymにあるcartpoleのコードを参考にしてstep内のreturnを復元してみました。
なし
大変興味深い内容で私も興味あります。ですが、teratailの質問(回答)投稿時に、
```ここに言語名を入力
```
のところに、
```Python3
import numpy as np
```
のようにしないとインデントが崩れてしまいます。
ですので、取り急ぎこの点のみ修整ください。
これ単品ではコードが走らせられませんが、どのように走らせるか教えていただけますか?
例:○○関数をif __name__ == "__main__":の後に入れる
情報が不足していて申し訳ございません。
既に載せたコード以外に下記の別ファイルを作成しています。
下記のファイルを実行する事で質問文に記載したコードを走らせています。
import gym
#env_dict = gym.envs.registration.registry.env_specs.copy()
#for env in env_dict:
# if 'myenv-v1' in env:
# print("Remove {} from registry".format(env))
# del gym.envs.registration.registry.env_specs[env]
from tqdm import tqdm
import matplotlib.pyplot as plt
env = gym.make('myenv-v1')
observation = env.reset()
for t in tqdm(range(1000000), leave=False):
#env.render()
observation, reward, done, info = env.step(env.action_space.sample())
#if reward >= 0:
#print("STEP_"+str(t)+" Reward:"+str(reward))
#plt.imshow(observation)
plt.show()
env.close()
#の行は現在使用していないので、整理すると下記となります。
import gym
from tqdm import tqdm
import matplotlib.pyplot as plt
env = gym.make('myenv-v1')
observation = env.reset()
for t in tqdm(range(1000000), leave=False):
observation, reward, done, info = env.step(env.action_space.sample())
plt.show()
env.close()
最初の質問文に載せたコード文にコメントを追加しました。
何の目的があって記載しているかの説明を簡易的にいたしました。
可能な限り手元で再現したいのですが、うまく走らない状況です。フォルダ構成やファイル構成についても差し支えなければ教えていただけますか?
最初に載せたコード文の格納先は下記となります。またファイル名はenv.pyとなります。
C:\Users\user\AppData\Local\Programs\Python\Python37\Lib\site-packages\gym\envs\myenv
2020/11/16 22:11に追記したコードのファイルの格納先は任意となります。
追加したファイルの位置は以上となります。そこ以外はファイルの位置は変更していません。
gym/envs/__init__.pyに
register(
id='myenv-v1',
...
)のように書くと思うのですが(あっていますか?)もしそうであればこれの中身を教えていただけますか?
御認識の通りです。__init__.pyに
register(id='myenv-v1', entry_point='gym.envs.myenv.env:Game',)
を追記しました。
まだ何にも進んでいませんが、おそらくGymの学習(ランダムに値を振って重みの学習)をするのが今のコードで、うまく動かすにはこの先の推論(predict)がいりそうな気がします。進展があったら書き込みます。
学習が失敗する原因として
①まだコードが不足してるから。(predictが足りていない)
②observation, reward, done, info = env.step(env.action_space.sample())でsample()と記載しているから学習せずに適当になっているから。
の2つが考えられると認識しています。
fourteenlength様は前者の可能性が高い認識でしょうか?
恐らくこれの両方と思います。env.action_space.sample()は「環境によらず適当な乱数を入れる関数」で、predictは「適当な乱数のうち、環境にうまく作用した乱数(のうちのどれか)を返す関数」だろうと踏んでいるためです。
ーー強化学習をやりたいな(でもまだやるにはなぁ)と思っている中でのshi.hiさんの質問でした。私も勉強中の身なので、これだ!という解ではないことをご理解ください。
(強化学習は普通の深層学習より触っていて楽しいですね)
承知いたしました。
自分の方でもpredict関数の実装をしてみます。
こちらの方のgithubに実際に動くサンプルがありました。
MITライセンスですので、大人の事情的にも使いやすいと思います。
https://github.com/icoxfog417/techcircle_openai_handson/tree/answer/handson_3
gymでは「環境」を提供するものであって、ユーザー側で環境を乗り倒すことのできる学習関数(Q)を実装しないといけないね、ということみたいですね。gymのドキュメントがもっとあると良いのですが、先人の皆様のブログ等なしにはなしえないですね
ちょっと魔改造しましたが動くようになりましたので近いうち(今日の夜には)にUploadしますね。
回答2件
あなたの回答
tips
プレビュー