ML-AgentsのImitation Learningをバトルゲームで使ってみた

# はじめに

ML-Agents v0.3よりImitation Learning(模倣学習)が可能になりました。
Rewardを設定して高いRewardを目指して学習をさせる強化学習に対して、
模倣学習は模範となる動作を真似る学習を行います(※よってRewardは必要ありません)

自分の場合は強化学習で使用した[こちら](https://qiita.com/muroon/items/c9f0d7565405284f8df1)のゲームをベースに模倣学習を行いました。


# 環境設定・サンプルプログラム

初めての方は本家のサンプルプログラムであるBananaImitationを見てみることをおすすめします。
[こちら](https://qiita.com/decchi/items/e2300f8a9dacf6ac4ccd)がわかりやすいです。

# フロー
1. 模倣学習用ビルド作成(Unity上)
2. python環境にて学習
3. 学習結果を使用して動作(Unity上)

# 1. 模倣学習用ビルド作成(Unity上)

## Unityプロジェクト内での構成
模倣学習プロジェクトのAcademy, Brain, Agentは下記の通りです。
![UnityProjectArchitecture.png](https://qiita-image-store.s3.amazonaws.com/0/76076/6218c722-a9ce-9af7-bf5a-92647ed648e4.png)


## Academy
* 基本的には[強化学習](https://qiita.com/muroon/items/c9f0d7565405284f8df1)の場合と同じ

![RoundAcademySetting.png](https://qiita-image-store.s3.amazonaws.com/0/76076/e96d2988-8460-0b4a-8ff5-6438a6b61154.png)


## Brain
Academy配下にTeacherBrain、StudentBrainゲームオブジェクトを配置
![RoundAcademy.png](https://qiita-image-store.s3.amazonaws.com/0/76076/91c16a5f-241d-22fa-6bd7-5a54ebda9755.png)

### TeacherBrain
* 模倣学習の教師用Brain
* ユーザー動作を担うのでBrainType = Playerとする
* BroadCastにチェックを入れる
* その他のBrainParametersは[強化学習](https://qiita.com/muroon/items/c9f0d7565405284f8df1#brain)の場合と同じ

![RoundTeacherBrain.png](https://qiita-image-store.s3.amazonaws.com/0/76076/e654d9f7-1628-5642-9a00-4d50a90a0054.png)

 
### StudentBrain
* 模倣学習の生徒用Brain
* 学習結果を動作させる際に使用するものなので、学習前のビルド作成時は特に意識する必要ないがBrainTypeをExternalに設定
 * 学習結果にて動作させる際の設定は[こちら](#studentbrainのインスペクターにて)
* その他のBrainParametersは[強化学習](https://qiita.com/muroon/items/c9f0d7565405284f8df1#brain)の場合と同じ

![RoundStudentBrain.png](https://qiita-image-store.s3.amazonaws.com/0/76076/27b9545b-f9dc-8780-08b2-f92cb2a14c17.png)


## Agent

### ソースコード

* 強化学習とソースを共有する場合は[強化学習](https://qiita.com/muroon/items/c9f0d7565405284f8df1#%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89)の場合と基本的には同じソースで問題ない
 * 環境を表すVector Observationを定義するCollectObservationsメソッド
 * Agentのアクションの中身を定義するAgentActionメソッド
 * AddRewardメソッドは模倣学習では無効だが、実行しても別に不具合はない
* TeacherAgent, StudentAgentのソースも同じで問題ない

### TeacherAgent
* 学習ビルドにて使用
* BrainはTeacherBrainのGameObjectを指定
* その他のパラメータは[強化学習](https://qiita.com/muroon/items/c9f0d7565405284f8df1)の場合と同じ

![RoundAgent_Teacher.png](https://qiita-image-store.s3.amazonaws.com/0/76076/517a650a-57ce-ab6d-431f-c30c902fbe8e.png)

### StudentAgent
* 学習結果にて動作確認時に使用
* BrainはStudentBrainのGameObjectを指定
* その他のパラメータは[強化学習](https://qiita.com/muroon/items/c9f0d7565405284f8df1)の場合と同じ

![RoundAgent_Student.png](https://qiita-image-store.s3.amazonaws.com/0/76076/ea5b2b07-91cb-70c0-3815-3f1038fc8193.png)


# 2. python環境にて学習

## trainer_config.yamlを編集

python/trainer_config.yamlに設定を追加

* StudentBrainであるRoundStudentBrain用の設定項目を作成する
* brain_to_imitationにTeacherBrainであるRoundTeacherBrainを設定
* その他の[設定値](https://github.com/Unity-Technologies/ml-agents/blob/master/docs/Training-ML-Agents.md#training-config-file)は必要に応じて修正

![trainer_config_imimation.png](https://qiita-image-store.s3.amazonaws.com/0/76076/1b3ff89f-b9b9-713a-6c6d-28e3c584f0f4.png)

## 学習開始
* Unity上でビルドを実行後に、python環境にて下記を実行

```
python python/learn.py ビルドファイルのパス --train --slow
```

* ゲームアプリが立ち上がるので、ユーザー操作を行い学習をさせる

しばらくプレイしている(※指定のmax stepsを超える)と自動的にアプリが終了します。python/models/ppo配下に学習したモデルデータ(ビルド名_ppo.bytes)が作成されます。ここで学習は終了です。

# 3. 学習結果を使用して動作(Unity上)
* 上記で作成した学習モデルデータ(ビルド名_ppo.bytes)をUnityプロジェクト配下のAssets/ML-Agents/TFModels/配下に配置 

## StudentBrainのインスペクターにて
* Brain TypeをInternalへ変更
* Graph Modelに上記で取り込んだビルド名_ppo.bytesを選択

![RoundStudentBrain2.png](https://qiita-image-store.s3.amazonaws.com/0/76076/26fd4d4e-7d76-2936-f57d-aa61dfdfd453.png)

## AgentのGameObjectのインスペクターにて
* 上記で記載の通り、StudentAgentを動作させるためBrainはStudentBrainのGameObjectを指定

![RoundAgent_Student.png](https://qiita-image-store.s3.amazonaws.com/0/76076/ea5b2b07-91cb-70c0-3815-3f1038fc8193.png)


# 動作結果

上記にて動作させた結果はこちらです。

![imitation.gif](https://qiita-image-store.s3.amazonaws.com/0/76076/71e3528e-8f21-7233-df0d-2c1812abe9ff.gif)

## 模倣学習ならではの動作をさせる

ゲームの[仕様上](https://qiita.com/muroon/items/c9f0d7565405284f8df1#%E3%82%B2%E3%83%BC%E3%83%A0%E4%BB%95%E6%A7%98)4つあるストップポイントの内1つは岩に隠れており、そこで留まっている間は敵からの攻撃を受けません。なるべく岩の後ろのポイントを通って移動したほうがダメージを受けづらいです。

強化学習の結果では特にこの岩を活かした動作をしてくれませんでした（Rewardの値をそうするように仕向ければできたのかもしれませんが）。4方向を万遍なく利用するのは攻撃的には有効かもしれませんがダメージも受けやすかったので、もっと岩のストップポイントの利用を増やせないかと思いました。

そこで岩陰をベースに攻撃するように1, 2, 3を順に繰り返し動作する学習をひたすら繰り返しました
1. 岩陰に隠れる
2. 岩陰から出てくる
3. 攻撃する

![dualLast6.gif](https://qiita-image-store.s3.amazonaws.com/0/76076/b50007e1-1a0b-ada8-668c-5bebc86b5586.gif)

左が強化学習の結果、右が模倣学習の結果です。
強化学習に比べると模倣学習のほうが頻繁に岩陰の後ろに隠れる動作になってきたかと思います。


# 最後に
最終的な勝利を目指すAIというよりは
「こんな感じの動作をしてほしい」みたいに個別の動作をAIに促したいときには模倣学習は有効なのではないでしょうか。