Unityで体感する強化学習【ML-Agents】

# 目的

- **強化学習**について概要を理解する 

- **迷路課題**を用いて実際に強化学習をやってみる

- **ML-Agents**を使ってUnity上で強化学習をやってみる



#人工知能・機械学習・強化学習

はじめに、強化学習に関連する用語、**人工知能**（Artificial Intelligence）、**機械学習**（Machine Learning）、**強化学習**（Reinforcement Learning）の意味を簡単に押さえておきます。

まず、**人工知能**についてですが、この言葉には明確な定義が存在しません。人工知能に関する研究領域はかなり広く、研究者についても様々な立場があるため、特定の定義を置くことが難しいという背景があるようです。ここでは**「人間が知能を使って行うことをコンピュータに模倣させようとする技術」**としておきましょう。

次に、**機械学習**とは、大量のデータからルールや知識を自ら学習する技術のことを指します。もう少し人工知能との関係を明瞭にする言い方をすれば、「データからその法則性を学習することで、解法が明確でない（人が規則を設計するのが難しい）タスクを遂行するためのモデルを構築すること」となるでしょうか。

重要なのは、機械学習の定義に**学習する**という文言が含まれることです。一見知的に振る舞うように見えるからといってもそれが全て機械学習であるとは限りません。専門家の知識を人手によってルール化し、そのルールに従って処理するようなシステム（エキスパートシステム）もある種知的に振る舞っているように見えることも多々あります。


##機械学習の分類

機械学習の手法を「**教師データ（正解ラベル）**がどのように与えられるか」という視点で大まかに分類すると以下のようになります。

![machine_learning.png](https://qiita-image-store.s3.amazonaws.com/0/208575/070fb7b4-4d25-6e22-f36a-650be43b37a0.png)




まず、**教師あり学習**と**教師なし学習**に関してはそのままの意味で、前者は教師データが与えられる手法、後者は教師データが与えられない手法になります。これらの手法とは異なり、**強化学習**は間接的に教師データが与えられる手法になります。

###教師あり学習
売上予測や株価予測のように、入力データと正解の数値の組み合わせを学習し、未知データから数値（連続値）を予測する**回帰**（Regression）と、画像分類、迷惑メールの判定といった入力データと正解のクラスの組み合わせを学習することで、未知データからクラス（離散値）を予測する**分類**（Classification）の2種類に大別されます。

###教師なし学習
教師なし学習はデータ自身の構造や分布をモデル化することで、データの性質を知る手法です。代表的な手法としてデータを同じような性質を持ついくつかのグループに分ける**クラスタリング**(Clustering)というものがあります。例えば、商品の購入状況から顧客をグループ化し、それぞれのグループに適したマーケティング手段を用いることでマーケティング効果を上げるといった使い方もできます。

他にも、
 
- **ソーシャルネットワーク分析**（SNS上で人のつながりを分析する）
- **アソシエーション分析**（顧客ごとに異なったオススメ商品を紹介する）

も教師なし学習の一種です。

###強化学習
間接的に教師データが与えられるというのは、**個々の決定に対して明確な正解は与えられないが、連続した決定の結果に対して（形を変えた）教師データが遅れて与えられる**ということです。例えば、コンピュータ将棋のソフトウェアを考えたとき、各盤面でどの駒をどのように動かせばよいかという正解は与えられませんが、最終的に試合に勝ったか負けたかなどの結果は分かります。この、「ゲームに勝つ」というような**「長期的な価値」を最大化するように試行錯誤を繰り返し行動を学習する**のが強化学習なのです。
<br/>
<details><summary>**深層学習**</summary><div>
近年注目を浴びている**深層学習**も機械学習の一手法です。具体的には下図のように**多層なニューラルネットワーク**を用いる手法です。様々な分野（特に画像、音声、自然言語の分野）でこれまで使われてきた古典的な手法を圧倒する性能を示しており、期待が寄せられています。
![スクリーンショット 2018-12-01 03.01.32.png](https://qiita-image-store.s3.amazonaws.com/0/208575/6a213a42-2f6d-dd16-f0a3-2546fb5f3bc2.png)
</div></details>

##強化学習
強化学習の概要とよく使われる用語を整理するために、迷路を解くための強化学習を考えます。迷路内を**エージェント**が移動してゴールを目指し、エージェントがゴールに辿り着くと**報酬**が与えられるという設定です。このとき、ある状態からどのように行動するのかを定めたルールを**方策**といいます。ここで、**状態**とはエージェントがいる位置になり、**行動**は上下左右のいずれかに進むことに当たります。さらに、今回でいう迷路の構造や設定全体のことを**環境**といいます。

<details><summary>**「環境」についての補足**</summary><div>
上記では、**環境**について少し曖昧な説明をしましたが、もう少し正確に書くと、環境はエージェントから行動の情報を受取り、その結果を報酬と次の状態という形で引き渡すものになります。
<img src= https://qiita-image-store.s3.amazonaws.com/0/208575/58514069-6308-dfc0-2299-61afb21453f3.png width=70%>
</div></details>

<img src= https://qiita-image-store.s3.amazonaws.com/0/208575/5252297f-eb18-d9a3-6f87-5eb49e79b683.png width=50%>

|用語|説明|
|:---|:---|
|エージェント（agent）|行動する主体|
|環境（environment）|エージェントが行動する対象|
|報酬（reward）|エージェントの行動の結果として獲得できる報酬|
|方策（policy）|行動を決めるルール|

### 方策勾配に基づくアルゴリズム
強化学習のアルゴリズムの一手法として方策勾配に基づくものを紹介します。

方策勾配に基づく強化学習を簡潔に述べると、**「方策を確率モデルで表現し、そのパラメータを学習する」**ということになりますが、文章を見ていても分かりづらいと思うので先程の迷路の設定で例を考えていきます。

まず、今回エージェントの行動を決めるルールである**方策**$\pi_{\theta}$を、ある状態から上下左右のいずれかに進むかの確率とします。例えば、迷路上の状態 s0（スタート）では、右（s1）、下（s4）の2方向に進むことができますが、初めのうちは、エージェントはどちらに進めばよいか分からないので、$\frac{1}{2}$の確率で右か下に進むことになります。ただし、迷路の構造を分かっている我々からすれば、下に進んでもゴールにはたどりつけないので、状態 s0 では右に進む確率の方が大きくなってくれると嬉しいです。このように、ゴールにより近づく方向に進む確率が大きくなるように何度も迷路を解くことで訓練していきます。

方策（各状態で上下左右に進む確率）を行列で表すと次のようになります。壁がある方向には進めないので確率は0とし、行は状態（s0〜s14）を、列は方向（↑、→、↓、←）を示します。例えば s1（2行目） は、↑以外の3方向(→、↓、←)に等しく0.333の確率で進むようになっています。

```console
[[0.    0.5   0.5   0.   ]
 [0.    0.333 0.333 0.333]
 [0.    0.    0.    1.   ]
 [0.    0.    1.    0.   ]
 [0.5   0.    0.5   0.   ]
 [0.333 0.333 0.333 0.   ]
 [0.    0.5   0.    0.5  ]
 [0.5   0.    0.    0.5  ]
 [0.5   0.    0.5   0.   ]
 [0.5   0.5   0.    0.   ]
 [0.    0.5   0.    0.5  ]
 [0.    0.    0.5   0.5  ]
 [0.5   0.5   0.    0.   ]
 [0.    0.5   0.    0.5  ]
 [0.    0.    0.    1.   ]]
```

この方策で迷路問題を解くと、次のようになります。当然ランダムに移動していくようなものなので、最短ルート s0(Start) → s1 ↓ s5 ↓ s9 → s10 → s11 → s15(Goal) **（6step）**からはほど遠く、同じところを何度も行ったり来たりしています。

```console
[[0, '→'], [1, '←'], [0, '↓'], [4, '↓'], [8, '↑'], [4, '↑'], [0, '↓'], [4, '↑'], [0, '→'], 
[1, '↓'], [5, '→'], [6, '→'], [7, '↑'], [3, '↓'], [7, '↑'], [3, '↓'], [7, '←'], [6, '→'], 
[7, '←'], [6, '→'], [7, '←'], [6, '←'], [5, '→'], [6, '→'], [7, '←'], [6, '←'], [5, '↓'], 
[9, '↑'], [5, '↓'], [9, '↑'], [5, '↓'], [9, '↑'], [5, '→'], [6, '→'], [7, '←'], [6, '→'], 
[7, '←'], [6, '←'], [5, '↓'], [9, '→'], [10, '→'], [11, '↓'], [15, 'np.nan']]
steps : 42
```

エージェントが最短ルートで迷路をクリアすることができるよう、方策を少しずつ更新していくのですが、実際には、その元になる**パラメータ**$\theta$を更新していきます。パラメータと言っても今回はかなりシンプルなもので、下のように、進める方向に対しては`1`、進めない方向（壁）に対しては`np.nan`とした行列とします。

<details><summary>**np.nan**</summary><div>
**NaN**とはNot a Numberのことで、無限大や不定形など実数で表せないものを表すときや、欠損値などを示すのに使われます。<br>
今回、進めない方向なので0とすればよいのでは？と、疑問かもしれませんが、この壁に進む方向の確率は方策の更新とは無関係に常に0とする必要がありますが、0としていると更新されてしまうかもしれないので、np.nanとしています。np.nanに対しては演算を施してもnp.nanになるので、更新されません。
</div></details>

```python
    theta_0 = np.array([[np.nan, 1, 1, np.nan],       # s0
                        [np.nan, 1, 1, 1],            # s1
                        [np.nan, np.nan, np.nan, 1],  # s2
                        [np.nan, np.nan, 1, np.nan],  # s3
                        [1, np.nan, 1, np.nan],       # s4
                        [1, 1, 1, np.nan],            # s5
                        [np.nan, 1, np.nan, 1],       # s6
                        [1, np.nan, np.nan, 1],       # s7
                        [1, np.nan, 1, np.nan],       # s8
                        [1, 1, np.nan, np.nan],       # s9
                        [np.nan, 1, np.nan, 1],       # s10
                        [np.nan, np.nan, 1, 1],       # s11
                        [1, 1, np.nan, np.nan],       # s12
                        [np.nan, 1, np.nan, 1],       # s13
                        [np.nan, np.nan, np.nan, 1],  # s14
                        ])
```

このパラメータを下のようにして単純に割合を求め、先程示したような方策とします。

```python
def policy(theta):
    [m, n] = theta.shape
    pi = np.zeros((m, n))

    for i in range(0, m):
        pi[i, :] = theta[i, :] / np.nansum(theta[i, :])

    pi = np.nan_to_num(pi)
    return pi
```

それでは、下のように方策を更新していきます。

```python
    stop_epsilon = 10**-4

    theta = theta_0
    pi = pi_0

    is_continue = True
    while is_continue:
        sa_history = solve(pi) #迷路を解く
        new_theta = update_theta(theta, pi, sa_history) #パラメータの更新
        new_pi = policy(new_theta) #方策の更新（パラメータ -> 方策）

        if np.sum(np.abs(new_pi - pi)) < stop_epsil
            is_continue = False
        else:
            theta = new_theta
            pi = new_pi
```

<details><summary>迷路を解く関数</summary><div>
引数：方策
戻り値：エージェントがどのルートを通ったかの記録

```python
def solve(pi):
    s = 0  # スタート
    sa_history = [[0, np.nan]]
    while (1):
        [action, next_s] = action_and_next_s(pi, s)
        sa_history[-1][1] = action
        sa_history.append([next_s, np.nan])

        if next_s == 15:  #ゴール
            break
        else:
            s = next_s
    return sa_history
```
</div></details>

<details><summary>パラメータの更新</summary><div>
引数：パラメータ、方策、エージェントがどのルートを通ったかの記録
戻り値：更新後のパラメータ

```python
def update_theta(theta, pi, sa_history):
    eta = 0.1 # 学習率
    T = len(sa_history) - 1  # ゴールまでの総ステップ数

    [m, n] = theta.shape
    delta_theta = theta.copy()

    for i in range(0, m):
        for j in range(0, n):
            if not(np.isnan(theta[i, j])):
                SA_i = [SA for SA in sa_history if SA[0] == i]
                SA_ij = [SA for SA in sa_history if SA == [i, j]]

                N_i = len(SA_i)
                N_ij = len(SA_ij)

                delta_theta[i, j] = (N_ij - pi[i, j] * N_i) / T

    new_theta = theta + eta * delta_theta
    return new_theta
```
</div></details>


学習が進んでいくと、段々と最短ルートに近いステップ数(6step)でゴールすることができるようになっています。

```console
Update amount0.0133  Steps 66
Update amount0.0161  Steps 62
Update amount0.0104  Steps 94
Update amount0.0105  Steps 78
Update amount0.0097  Steps 252
Update amount0.0100  Steps 74

~~~~~~~~~~~~省略~~~~~~~~~~~~~~

Update amount0.0041  Steps 6
Update amount0.0131  Steps 10
Update amount0.0036  Steps 6
Update amount0.0144  Steps 8
Update amount0.0036  Steps 6
Update amount0.0036  Steps 6
```

ゴールまでにかかったステップ数の遷移を図に表すと下のようになります。しっかり減っていっているのが確認できます。
![Figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/208575/3984b464-2916-e6e9-fd1f-22e2472ecc34.png)


最終的な方策と、その方策で迷路を解いた結果は次のようになります。例えばs11(下から4段目)は↓に進めばすぐにゴールですが、↓に進む確率が1で他が0となっており、うまく方策が学習できています。また、その方策で迷路を解くとs0(Start) → s1 ↓ s5 ↓ s9 → s10 → s11 → s15(Goal) **（6step）**の最短ルートでゴールできていることがわかります。

```console
[[0.    1.    0.    0.   ]
 [0.    0.    0.991 0.008]
 [0.    0.    0.    1.   ]
 [0.    0.    1.    0.   ]
 [0.631 0.    0.369 0.   ]
 [0.    0.    1.    0.   ]
 [0.    0.299 0.    0.701]
 [0.468 0.    0.    0.532]
 [0.574 0.    0.426 0.   ]
 [0.    1.    0.    0.   ]
 [0.    1.    0.    0.   ]
 [0.    0.    1.    0.   ]
 [0.523 0.477 0.    0.   ]
 [0.    0.499 0.    0.501]
 [0.    0.    0.    1.   ]]

[[0, '→'], [1, '↓'], [5, '↓'], [9, '→'], [10, '→'], [11, '↓'], [15, 'np.nan']]
steps : 6
```

今回使用した、ソースコードは以下に置いてあります。
https://github.com/casp39/rl_maze

# ML-Agents
Unity上で、強化学習、模倣学習、その他機械学習が行えるプラグインである**ML-Agents**の導入をし、サンプルのゲームを動かしてみます。

## ML-Agents 環境構築
### Unityのインストール
Unityを[ダウンロード](https://store.unity.com/download)し、インストールします。

ML-Agents は **Unity2017.4** 以降のバージョンにしか対応していません。
今回は、Unity2017.4を使用していきます。

### ML-Agentsリポジトリをクローン
適当なディレクトリにリポジトリをクローンします。

```console
git clone https://github.com/Unity-Technologies/ml-agents.git
```

### Python と ML-Agentsのインストール
ML-Agentsのインストールが終わったらPythonと、周辺ライブラリを入れます。

まず、Anacondaを[ダウンロード](https://www.anaconda.com/download/)し、インストールします。

<details><summary>Anaconda</summary><div>
Anacondaは、データサイエンス、機械学習などの科学計算でよく用いられるライブラリをまとめた、ディストリビューションです。
![スクリーンショット 2018-12-03 18.24.33.png](https://qiita-image-store.s3.amazonaws.com/0/208575/ccf510d1-1fdc-e2c6-b49b-cf1c93d055d7.png)
</div></details>

Anacondaのインストールが終わったらML-Agents用の仮想環境を用意します。

```console
conda update -n base conda
conda create --name mlagents python=3.6
source activate mlagents
pip install mlagents
```

Tensorflowをインストール

※ 現在ML-Agentsの最新verはTensorFlow1.15.0と互換がないのでTensorFlow1.15.0をインストールします。

```
pip install tensorflow==1.14
```

### UnityでML-Agentsをセットアップ

**1. Unityを起動する**

**2. Openボタン を選択し、ml-agents/UnitySDK/ を開く**

**3. Edit > Project Settings > Player**

　**Other Settings**を変更する

|**Scripting Runtime Version**|**Experimental (.NET 4.6 Equivalent or .NET 4.x Equivalent)**|
|:---|:---|
|**Scripting Defined Symbols**|**ENABLE_TENSORFLOW**|

<details><summary>参考画像</summary><div>
![スクリーンショット 2018-11-29 00.22.20.png](https://qiita-image-store.s3.amazonaws.com/0/208575/abf99410-cd66-aa29-856f-33deacc26e27.png)
</div></details>

**4. File > Save Project**

### サンプルの学習環境(3DBall)

Project window で ```Assets/ML-Agents/Examples/3DBall``` フォルダの中の **3DBall シーンファイル** を開きます。今回扱うサンプルは**箱の上に落下してくるボールを落とさないように箱を動かしてバランスをとる**というようなものです。

![スクリーンショット 2019-10-30 20.59.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208575/a90b2d83-cb91-6cd5-33df-67f05de2e173.png)

### ML-Agentsの用語整理

サンプルの学習を行う前に、ML-Agentsで重要になる用語を整理しておきます。

#### Agent
学習環境内で**行動**するオブジェクトのことを**Agent**と呼びます。今回の場合、ボールを落とさないようにボールを制御する箱がAgentに当たります。

#### Brain
BrainはAgentの観測した**状態**と**報酬**を用いてAgentの**行動**を決定します。今回Agentが観測できるのは、現在のAgent(箱)の回転角度とボールの位置・速度です。報酬は各時刻ごとににボールが箱の上にあると+0.1、ボールを箱の上から落としすと-1.0の報酬が得られる設定になっています。これらの状態と報酬を考慮しBrainが次のAgentの行動を決定します。

#### Academy
Academyは学習環境を管理するオブジェクトです。トレーニング1回分のことを1 **エピソード** と呼びますが、何エピソード分すなわち何回分トレーニングを行うかといったことや、学習環境の初期値の設定、レンダリング（解像度等）の設定などを行います。

### 強化学習によるトレーニング
####準備
1. まず、AgentにBrainを割り当てます。```Prefabs>3DBall>Agent```の```Ball 3D Agent (Script)```コンポーネントの```Brain```プロパティに```Assets>ML-Agents>Examples>3DBall>Brains>3DBallLearning ```をドラッグします。

2. 次に、Academyの設定を行います。**Hierarchy**ウィンドウで、Ball3DAcademyを選択します。Agentと同じようにして、```Ball 3D Academy (Script)```コンポーネントの'''Brain'''プロパティに```Assets>ML-Agents>Examples>3DBall>Brains>3DBallLearning ```をドラッグします。また、学習の際には```Control```プロパティにチェックを入れる必要があります。

#### 学習
1. 再度ターミナルを開き ML-Agentsリポジトリ をクローンしたディレクトリへ移動し、次を実行します。

```console
mlagents-learn config/trainer_config.yaml --run-id=firstRun --train
```
オプションの`--train`は**学習**を実行することを表しています。（**推論**時は不要）

2. *Start training by pressing the Play button in the Unity Editor.* のメッセージが表示されるのを確認後 Unity に戻り、 再生ボタン を押す

![スクリーンショット 2018-11-29 23.47.33.png](https://qiita-image-store.s3.amazonaws.com/0/208575/36991fc3-d80e-08e4-a8fc-2b53abbdc4b8.png)

すると、学習が始まります。初めのうちは板はボールをボロボロ落としています（左図）が、学習が進んでくるとなかなかボールを落とさなくなってくる（右図）のが分かります。

|1000ステップ後|10000ステップ後|
|:---:|:---:|
|![before.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208575/02c58078-1be2-6ff3-1121-cf599c2abfb2.gif)|![after.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208575/61a5b49a-c3a5-21d9-1a97-9e9a055648d3.gif)|

ターミナルにはもう少し詳しい情報が表示されています。少し確認してみましょう。
<details><summary>情報全体</summary><div>

```
INFO:mlagents.envs:Hyperparameters for the PPO Trainer of brain Ball3DBrain:
	batch_size:	64
	beta:	0.001
	buffer_size:	12000
	epsilon:	0.2
	gamma:	0.995
	hidden_units:	128
	lambd:	0.99
	learning_rate:	0.0003
	max_steps:	5.0e4
	normalize:	True
	num_epoch:	3
	num_layers:	2
	time_horizon:	1000
	sequence_length:	64
	summary_freq:	1000
	use_recurrent:	False
	graph_scope:
	summary_path:	./summaries/firstRun-0
	memory_size:	256
	use_curiosity:	False
	curiosity_strength:	0.01
	curiosity_enc_size:	128
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 1000. Mean Reward: 1.180. Std of Reward: 0.684. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 2000. Mean Reward: 1.328. Std of Reward: 0.755. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 3000. Mean Reward: 1.664. Std of Reward: 0.970. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 4000. Mean Reward: 2.355. Std of Reward: 1.631. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 5000. Mean Reward: 3.706. Std of Reward: 3.188. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 6000. Mean Reward: 6.255. Std of Reward: 6.104. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 7000. Mean Reward: 9.339. Std of Reward: 8.283. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 8000. Mean Reward: 12.943. Std of Reward: 11.746. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 9000. Mean Reward: 22.260. Std of Reward: 20.912. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 10000. Mean Reward: 39.189. Std of Reward: 29.556. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 11000. Mean Reward: 48.570. Std of Reward: 33.496. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 12000. Mean Reward: 66.494. Std of Reward: 32.763. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 13000. Mean Reward: 81.663. Std of Reward: 33.271. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 14000. Mean Reward: 88.731. Std of Reward: 21.941. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 15000. Mean Reward: 95.200. Std of Reward: 15.920. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 16000. Mean Reward: 91.186. Std of Reward: 25.583. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 17000. Mean Reward: 86.814. Std of Reward: 32.300. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 18000. Mean Reward: 85.985. Std of Reward: 20.061. Training.
INFO:mlagents.trainers: firstRun-0: Ball3DBrain: Step: 19000. Mean Reward: 100.000. Std of Reward: 0.000. Training.
^C--------------------------Now saving model-------------------------
INFO:mlagents.envs:Learning was interrupted. Please wait while the graph is generated.
```
</div></details>

まず、以下の部分では強化学習のアルゴリズムとして**PPO**（Proximal Policy Optimization）を用いていることを表しています。これは、先程説明した方策勾配法ベースの手法で、実装が比較的簡単なアルゴリズムとして注目されています。

```
INFO:mlagents.envs:Hyperparameters for the PPO Trainer of brain Ball3DBrain:
```
次に、ステップごとの平均**報酬**が表されていますが、段々と多くの報酬が貰えるようになっているので学習が上手くいっていることが分かります。

```
INFO: Step: 1000. Mean Reward: 1.180. 
INFO: Step: 2000. Mean Reward: 1.328. 
INFO: Step: 3000. Mean Reward: 1.664. 
INFO: Step: 4000. Mean Reward: 2.355. 
INFO: Step: 5000. Mean Reward: 3.706. 
INFO: Step: 6000. Mean Reward: 6.255. 
INFO: Step: 7000. Mean Reward: 9.339. 
INFO: Step: 8000. Mean Reward: 12.943. 
INFO: Step: 9000. Mean Reward: 22.260. 
INFO: Step: 10000. Mean Reward: 39.189. 
INFO: Step: 11000. Mean Reward: 48.570. 
INFO: Step: 12000. Mean Reward: 66.494. 
INFO: Step: 13000. Mean Reward: 81.663. 
INFO: Step: 14000. Mean Reward: 88.731. 
INFO: Step: 15000. Mean Reward: 95.200. 
INFO: Step: 16000. Mean Reward: 91.186. 
INFO: Step: 17000. Mean Reward: 86.814. 
INFO: Step: 18000. Mean Reward: 85.985. 
INFO: Step: 19000. Mean Reward: 100.000. 
```

ちなみに、途中で学習をやめるには`Ctrl + C`を押します。

#### 推論
さきほど学習したモデルは`models/firstRun-0/3DBallLearning.nn`にあります。これを**Project window**の`ML-Agents/Examples/3DBall/TFModels/`にドラッグします。
<details><summary>参考画像</summary><div>
![スクリーンショット 2019-10-30 23.00.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208575/ae7a34b8-ac70-92b4-c957-f4bc5236ef60.png)
</div></details>

※ デフォルトで`TFModels`内に`3DBallLearning.nn`がある場合は、先にそれを削除してからモデルをドラッグしましょう。

1. 推論の際は`Ball3DAcademy`の```Control```プロパティのチェックをはずす必要があります。

2. `Assets>ML-Agents>Examples>3DBall>Brains>3DBallLearning`の`Model`にさきほど学習したモデルをドラッグします。
<img src= https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208575/db6fbbb1-3613-d03f-bc9d-a607e6d5ff36.png width=80%>

3. 再生ボタンを押すと推論が始まります。
板がボールを落とさないように制御できていることが分かります。
<img src= https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208575/640b68f0-855b-149f-8b33-f7e6679e6f79.gif width=80%>

ML-Agentsには他にも様々なサンプルがあるので、試してみると良いでしょう。

|tennis|soccer|pyramids|
|---|---|---|
|![tennis.gif](https://qiita-image-store.s3.amazonaws.com/0/208575/25ba58c6-b4c7-98ab-75dc-df17c43e323d.gif)|![soccer.gif](https://qiita-image-store.s3.amazonaws.com/0/208575/7de9d99a-a3e5-b1aa-cc1c-d32b48c8b37d.gif)|![pyramids.gif](https://qiita-image-store.s3.amazonaws.com/0/208575/256e772d-a2cf-2423-ac12-223914aa419b.gif)|




# 補足
###人工知能の定義
松尾豊「人工知能は人間を超えるか」（KADOKAWA）に国内の研究者複数人の考える人工知能の定義がまとめられています。

###人工知能の分類
人工知能は**「汎用人工知能」**と**「特化型人工知能」**の２つに分類することができます。前者は様々な一般的な状況に対応し、自律的な思考・検討を行なうことができる人工知能のことを指します。ドラえもんをイメージするとわかりやすいでしょう。後者は自動運転や、画像識別、囲碁・将棋など特定の領域に対して専門化した能力を持つ人工知能です。今回の定義は後者寄りですが、実際昨今の人工知能関連の研究の多くは後者にあたります。

###中間的学習
機械学習を教師データの与えられ方を基準に、教師あり学習、教師なし学習、強化学習の3種類に分類しましたが、この他に少量のラベル（正解）付きデータと大量のラベル無しデータを用いて学習する半教師あり学習というものもあります。この半教師あり学習と強化学習をまとめて中間的学習とよぶ文献もあります。


# 参考文献
### 強化学習
[1] 牧野 貴樹ほか『これからの強化学習』（森北出版、2016）

[2] Richard S.Sutton and Andrew G.Barto（三上 貞芳、 皆川 雅章訳）『強化学習』（森北出版、2006）

[3] 小川雄太郎『つくりながら学ぶ! 深層強化学習』（マイナビ出版、2018）

### ML-Agents
[4] 「Learn how to use Unity Machine Learning Agents - Unity」
〔 https://unity3d.com/jp/how-to/unity-machine-learning-agents 〕
（最終検索日 : 2018 年 12 月 9 日）

[5] 布留川 英一『Unityではじめる機械学習・強化学習 Unity ML-Agents実践ゲームプログラミング』（ボーンデジタル、2018）

### Proximal Policy Optimization 
[6] J Schulman, F Wolski, P Dhariwal, A Radford and O Klimov. “Proximal Policy Optimization Algorithms”. In: arXiv preprint arXiv:1707.06347 (2017).