TensorBoard(2)

TesnorBoardはTesorFlowのデータを可視化するツールです。
学習状況をより詳細に観察することができるようになります。

4.Episode Length

エピソードの平均の長さです。評価する環境によって望まれる結果は異なります。
ボールを落ちないようにする環境では、増加することが期待されます。
迷路を解くようなゲームでは、減少することが期待されます。

Episode Length

5.Learning Rate

学習率です。今回の行動評価を過去の行動評価と比べてどの程度信じるかという割合になります。
時間とともに継続して減少します。

Learning Rate

6.Policy Loss

Brainが行動を決定する「方策がどれだけ変化しているか」を示す値となります。
学習成功時には減少し、継続的に減少することが期待されます。

Policy Loss

TensorBoard(1)

TesnorBoardはTesorFlowのデータを可視化するツールです。
学習状況をより詳細に観察することができるようになります。

1.Lesson

カリキュラム学習のレッスンの進捗です。カリキュラム学習でない場合は、Lesson 0のままとなります。

Lesson

2.Cumulative Reward

エージェントの平均累積報酬です。継続して増加し、上下の振れ幅が小さいことが期待されます。
タスクの複雑さによってはなかなか増加しないこともあります。

Cumulative Reward

3.Entropy

Brainが決定する「Actionがどれだけランダムであるか」を示す値です。
継続的に減少することが期待されます。

Actionのデータ型が離散(Discrete)の場合、次のような対応が有効となります。

  • エントロピーの減少が早すぎる。
    → ハイバーパラメータのbetaを増やす。
  • エントロピーの減少が遅すぎる。
    → ハイバーパラメータのbetaを減らす。

Entropy

Unity ML-AgentsのBrain

Agentが観測した状態に応じて、行動を決定するオブジェクトとなります。
1つのBrainで複数のAgentsの行動を決定することもできます。
Brainには下記の4種類があります。

1.External

外部の自作MLライブラリ(Tensorflowなど)を使用します。
学習時に設定されます。

2.Internal

プロジェクトに埋め込まれた推論モデルを使用します。
推論時に設定されます。

3.Player

プレイヤー(人間)の入力に従って行動します。
学習環境の動作確認時などに利用します。

4.Heuristic

ルールベース(プログラム)に従って行動します。

Unity ML-Agentsのプロセス

Unity ML-Agentsは、Unityで機械学習の学習環境を構築するためのフレームワークです。
Unity ML-Agentsでの2プロセスに関して説明します。

学習プロセス

学習用Pythonスクリプトが学習環境となるUnityで強化学習を行います。
学習結果は推論モデルとして保存されます。

推論プロセス

学習結果となる推論モデルをつかってUnityで動作します。
推論モデルは与えられたデータから推論結果を導き出すものです。

Intrinsic Curiosity Module(ICM)

Intrinsic Curiosity Module(ICM)

まだ見たことのない場面に対する好奇心を報酬として学習させる手法です。

ICMでは次の2つのモデルを同時に学習します。

  • 逆モデル
    2つの状態からその間に選択した行動を予測する。
  • 順モデル
    状態と選択した行動から次の状態を予測する。
    この予測が外れるほど多くの報酬を与える。

これらによってエージェントにとって未知である行動を取るほど報酬を多く受け取ることになります。
迷路を探索してさまざまな行動をとる必要があるゲーム等に最適な学習方法です。

Recurrent Neural Network(RNN)とLong Short-Term Memory(LSTM)

Recurrent Neural Network(RNN)

時系列を扱えるニューラルネットワークです。

強化学習では通常「現在の環境」に応じて行動を決定しますが、RNNを利用することで「過去の環境」の状態も踏まえて行動を決定することができるようになります。
エージェントが記憶を持つようなイメージです。

ただRNNでは長期記憶の学習がうまくできないという問題があるため、次で説明するLSTMで長期記憶ができるように改善します。

Long Short-Term Memory(LSTM)

長期的な依存関係を学習することのできるRNNの特別な一種で、1つ前の入力データをうまく扱うことに特化した「LSTMブロック」を組み込みます。

多種多様な問題にとてもよく動作し、現在では広く使用されています。

カリキュラム学習

カリキュラム学習はタスクの難易度を徐々に上げていくことにより、効率的な学習を可能にする手法です。

例としましては「足し算・引き算」を学んだあと、「掛け算・引き算」を学び、そのあとで「面積の計算」を学習します。
学んだ知識をその後の学習に生かすことで、より難しい問題を解くことが可能になります。

この手法は機械学習にも適用可能で、簡単なタスクを訓練することでより困難なタスクを達成することを目指します。

Unity ML-Agents V0.4.0bがなんとか動くようになった件

強化学習を実践していく上でシミュレータが必要なことがわかり、シミュレータとしては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

私と同じように動作確認をあきらめてしまった方の一助になれば幸いです。

経験の蓄積と活用のバランス Epsion-Greedey法

経験の蓄積と活用のトレードオフのバランスをとる手法としてEpsilon-Greedy法を実装します。

何枚かのコインから1枚を選んで、投げた時表が出れば報酬が得られるゲームを考えます。
各コインの表が出る確率はバラバラです。

必要なパッケージをインポートします。

1
2
import random
import 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):
# Initialize estimation.
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

価値を再帰的かつ期待値で表現する手法を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 game end, expected value is 0.
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で学ぶ強化学習 -入門から実践まで- サンプルコード