強化学習を実践していく上でシミュレータが必要なことがわかり、シミュレータとしてはUnityが便利だということがわかり、さらにUnity ML-Agentsを使うとPythonからUnityを動作させることが分かりました。 そして参考文献を探したところ目的にはまった下記の書籍を見つけましたがバージョンが古いせいでしょうか、まったく動作させることができずしばらく放置していました。
しかしなんとか動作させることができるようになったので備忘録としてまとめておきます。
Pythonで学ぶ強化学習 -入門から実践まで- サンプルコード
【手順1】Unityインストール 書籍(P.41)にしたがってUnityをインストールします。 私の環境ではUnityのバージョンは2017.3.1f1 (64-bit)を使用しました。
【手順2】Unity ML-Agents v0.4.0bダウンロード サポートサイトに記載されていますが、下記のリンクからUnity ML-Agents v0.4.0bをダウンロードします。https://github.com/Unity-Technologies/ml-agents/tree/0.4.0b
※2019/11/16現在の最新バージョンは0.11なのでかなり古いバージョンです。
【手順3】TensorFlowSharpプラグインダウンロード 書籍(P.42)にしたがってTensorFlowSharpプラグインをダウンロードをインストールします。
【手順4】Pythonインストール 書籍(P.43)にしたがってPythonをインストールし、仮想環境を構築します。 Pythonバージョンは3.6で問題ありません。
【手順5】Pythonパッケージインストール 書籍(P.44)に該当する箇所ですが、【手順2】でダウンロードしたファイルを使ってPythonパッケージをインストールします。 ダウンロードしたものの中にpythonフォルダがありますのでそのフォルダに移動してインストールコマンドを実行します。
1 2 cd (ダウンロードした中のpythonフォルダ) pip install .
【手順6】Numpyバージョン変更 ここが一番はまったポイントでした。 Numpyのバージョンは1.17.4がインストールされていたのですがこれを1.14.5に落とします。
1 2 pip uninstall numpy pip install numpy==1.14.5
(動作確認時に配列関連エラーでExceptionが発生していたのでnumpyのバージョンを疑い、結果動作させることができるようになりました。)
【手順7】プロジェクト設定 書籍(P.47~P.49)にしたがってプロジェクトの設定を行います。
【手順8】Unity Editorで動作確認 書籍(P.50~P.52)のexeを作っての実行はうまくいかないのであきらめました。 書籍(P.63)「Unity Editor上での学習」の方を実行したところ問題なく動作確認できました。
以上で一通り書籍に書かれているサンプルを実行させることができるようになります。
もしこれでもうまくいかない場合のため、動作確認ができた環境のライブラリバージョン一覧を書いておきますので、参考にして頂ければと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 > pip list Package Version ------------------ ------------------- absl-py 0.8.1 astor 0.8.0 atomicwrites 1.3.0 attrs 19.3.0 backcall 0.1.0 bleach 1.5.0 certifi 2019.9.11 colorama 0.4.1 cycler 0.10.0 decorator 4.4.1 defusedxml 0.6.0 docopt 0.6.2 entrypoints 0.3 gast 0.3.2 grpcio 1.11.0 html5lib 0.9999999 importlib-metadata 0.23 ipykernel 5.1.3 ipython 7.9.0 ipython-genutils 0.2.0 ipywidgets 7.5.1 jedi 0.15.1 Jinja2 2.10.3 jsonschema 3.1.1 jupyter 1.0.0 jupyter-client 5.3.4 jupyter-console 6.0.0 jupyter-core 4.6.1 kiwisolver 1.1.0 Markdown 3.1.1 MarkupSafe 1.1.1 matplotlib 3.1.1 mistune 0.8.4 more-itertools 7.2.0 nbconvert 5.6.1 nbformat 4.4.0 notebook 6.0.2 numpy 1.14.5 packaging 19.2 pandocfilters 1.4.2 parso 0.5.1 pickleshare 0.7.5 Pillow 6.2.1 pip 19.3.1 pluggy 0.13.0 prometheus-client 0.7.1 prompt-toolkit 2.0.10 protobuf 3.5.2 py 1.8.0 Pygments 2.4.2 pyparsing 2.4.5 pyrsistent 0.15.5 pytest 5.2.3 python-dateutil 2.8.1 pywin32 227 pywinpty 0.5.5 PyYAML 5.1.2 pyzmq 18.1.1 qtconsole 4.5.5 Send2Trash 1.5.0 setuptools 41.6.0.post20191030 six 1.13.0 tensorboard 1.7.0 tensorflow 1.7.1 termcolor 1.1.0 terminado 0.8.3 testpath 0.4.4 tornado 6.0.3 traitlets 4.3.3 unityagents 0.4.0 wcwidth 0.1.7 Werkzeug 0.16.0 wheel 0.33.6 widgetsnbextension 3.5.1 wincertstore 0.2 zipp 0.6.0
私と同じように動作確認をあきらめてしまった方の一助になれば幸いです。
経験の蓄積と活用のトレードオフのバランスをとる手法としてEpsilon-Greedy法を実装します。
何枚かのコインから1枚を選んで、投げた時表が出れば報酬が得られるゲームを考えます。 各コインの表が出る確率はバラバラです。
必要なパッケージをインポートします。
1 2 import randomimport numpy as np
コイントスゲームの実装を行います。 head_probsは配列のパラメータで各コインの表が出る確率を指定します。
max_episode_stepsはコイントスを行う回数で、この回数の実行して表がでた回数が報酬となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class CoinToss (): def __init__ (self, head_probs, max_episode_steps=30 ): self.head_probs = head_probs self.max_episode_steps = max_episode_steps self.toss_count = 0 def __len__ (self ): return len (self.head_probs) def reset (self ): self.toss_count = 0 def step (self, action ): final = self.max_episode_steps - 1 if self.toss_count > final: raise Exception("The step count exceeded maximum. Please reset env." ) else : done = True if self.toss_count == final else False if action >= len (self.head_probs): raise Exception("The No.{} coin doesn't exist." .format (action)) else : head_prob = self.head_probs[action] if random.random() < head_prob: reward = 1.0 else : reward = 0.0 self.toss_count += 1 return reward, done
エージェントを作成します。
policy関数で、epsilonの確率でランダムにコインを選択し(探索)、それ以外の確率で各コインの期待値にそってコインを選択します(活用)。 play関数は、コイントスを行う処理です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class EpsilonGreedyAgent (): def __init__ (self, epsilon ): self.epsilon = epsilon self.V = [] def policy (self ): coins = range (len (self.V)) if random.random() < self.epsilon: return random.choice(coins) else : return np.argmax(self.V) def play (self, env ): N = [0 ] * len (env) self.V = [0 ] * len (env) env.reset() done = False rewards = [] while not done: selected_coin = self.policy() reward, done = env.step(selected_coin) rewards.append(reward) n = N[selected_coin] coin_average = self.V[selected_coin] new_average = (coin_average * n + reward) / (n + 1 ) N[selected_coin] += 1 self.V[selected_coin] = new_average return rewards
5枚のコインを用意し、コイントスの回数を変えながら、各エピソードにおける1回のコイントスあたりの報酬を記録していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 if __name__ == "__main__" : import pandas as pd import matplotlib.pyplot as plt def main (): env = CoinToss([0.1 , 0.5 , 0.1 , 0.9 , 0.1 ]) epsilons = [0.0 , 0.1 , 0.2 , 0.5 , 0.8 ] game_steps = list (range (10 , 310 , 10 )) result = {} for e in epsilons: agent = EpsilonGreedyAgent(epsilon=e) means = [] for s in game_steps: env.max_episode_steps = s rewards = agent.play(env) means.append(np.mean(rewards)) result["epsilon={}" .format (e)] = means result["coin toss count" ] = game_steps result = pd.DataFrame(result) result.set_index("coin toss count" , drop=True , inplace=True ) result.plot.line(figsize=(10 , 5 )) plt.show() main()
epsilon=0.1と0.2ではコイントスの回数とともに報酬が向上していることが分かります。
参考
Pythonで学ぶ強化学習 -入門から実践まで- サンプルコード
価値を再帰的かつ期待値で表現する手法をBellman Equationと呼びます。(Valueベース) Bellman Equationを使えば各状態の価値が計算可能となります。
まず価値を返す関数を定義します。
1 2 3 def V (s, gamma=0.99 ): V = R(s) + gamma * max_V_on_next_state(s) return V
報酬関数を定義します。 エピソード終了のとき”happy_end”であれば1を返し、”bad_end”であれば-1を返します。 エピソードが終了していなければ0を返します。
1 2 3 4 5 6 7 def R (s ): if s == "happy_end" : return 1 elif s == "bad_end" : return -1 else : return 0
全ての行動でV(s)を計算し値が最大になる価値を返します。 評価vの計算式は確率遷移×遷移先の価値となります。
upかdownかを繰り返していき5回行動したら終了となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def max_V_on_next_state (s ): if s in ["happy_end" , "bad_end" ]: return 0 actions = ["up" , "down" ] values = [] for a in actions: transition_probs = transit_func(s, a) v = 0 for next_state in transition_probs: prob = transition_probs[next_state] v += prob * V(next_state) values.append(v) return max (values)
遷移関数を定義します。
引数sには”state”や”state_up_up”、”state_down_down”などが受け渡されます。
引数aは”up”か”down”が設定されます。
エピソード完了時は1要素が返り、途中の場合は2要素が返ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 def transit_func (s, a ): actions = s.split("_" )[1 :] LIMIT_GAME_COUNT = 5 HAPPY_END_BORDER = 4 MOVE_PROB = 0.9 def next_state (state, action ): return "_" .join([state, action]) if len (actions) == LIMIT_GAME_COUNT: up_count = sum ([1 if a == "up" else 0 for a in actions]) state = "happy_end" if up_count >= HAPPY_END_BORDER else "bad_end" prob = 1.0 return {state: prob} else : opposite = "up" if a == "down" else "down" return { next_state(s, a): MOVE_PROB, next_state(s, opposite): 1 - MOVE_PROB }
実際に価値V(s)の計算を行ってみます。
1 2 3 4 if __name__ == "__main__" : print (V("state" )) print (V("state_up_up" )) print (V("state_down_down" ))
upの数が多い方が評価されます。
参考
Pythonで学ぶ強化学習 -入門から実践まで- サンプルコード
Prev 1 … 173 174 175 176 177 … 185 Next