世界で一番分かりやすい ML-Agents 0.2 リリースノート

# 前書き
どうも今日は。「世界で一番分かりやすい」シリーズでおなじみ（？）のどらです。これを自分のブランドにしたいのであらゆる所で使っていく所存です（笑） どうぞよろしくお願い致します。

この記事は ML-Agents 0.2 のリリースノートを世界で一番分かりやすくお伝えするものですが、ML-Agents 自体が何なのか分からない方や、ML-Agents を一度も使った事がない方は申し訳ありませんが対象外となりますのでご容赦下さい（そのうちそういう記事も書きたいとは思っています！）。簡単に言えば Unity を使って深層強化学習させるためのライブラリですが、詳しくは[本家リポジトリ](https://github.com/Unity-Technologies/ml-agents)や[これから強化学習を勉強する人のための「強化学習アルゴリズム・マップ」と、実装例まとめ](https://qiita.com/sugulu/items/3c7d6cbe600d455e853b)などをご覧下さい。

お伝えする内容は、[公式ブログ](https://blogs.unity3d.com/jp/2017/12/08/introducing-ml-agents-v0-2-curriculum-learning-new-environments-and-more/)、[リリースノート](https://github.com/Unity-Technologies/ml-agents/releases/tag/0.2.0)、[ソースコード](https://github.com/Unity-Technologies/ml-agents)から、**「ML-Agents 0.2 って大きく何が変わったの？」**と、**「公式ブログに大きく謳われてはいないが地味に便利な機能たち」**です。

# ML-Agents 0.2 って大きく何が変わったの？
一言で言うなれば、こうなります。

1. カリキュラム学習に標準で対応した → **つまり難しい問題を学習させやすくなった！**
2. ブロードキャストという機能が加わった → **つまり模倣学習ができる様になった！**
3. フレキシブルモニタという機能が加わった → **つまり学習時の状態を確認しやすくなった！**

これらについて、詳細を個別に記述します。

## カリキュラム学習に標準で対応した
そもそもカリキュラム学習って何やねんという感じですが、簡単に言うと**「難しい事を一気に学習させようとするのではなく、段階的に簡単な問題からトライさせて一歩一歩学習させる」**のがカリキュラム学習の考え方です。

ML-Agents でも何か環境を作って Agent に学習させようとしても、報酬を得られるまでがあまりに長い道のりだったりすると学習に非常に時間がかかってしまいます。そういった場合に有効な手段になりますが、個人的な印象としてはこれは実用レベルではほぼ必須と言えるのではないでしょうか。経験的に、カリキュラム学習を使わずに学習させるのはかなり難しい様に感じます。

カリキュラム学習をさせる時には、学習の流れを**レッスンを１つ１つこなしていくカリキュラムを組む**という形で定めます。例えば「とても簡単なレッスン→ちょっと難しいレッスン→とても難しいレッスン」、これらをまとめたものがカリキュラム、という事です。どうやって次のレッスンに進むのかというと、報酬がある程度得られる様になったら、あるいはステップ数がある程度進んだら、といった条件を満たしたらになります。

![ML-Agents のリポジトリから引用](https://github.com/Unity-Technologies/ml-agents/raw/master/images/math.png)

以前のバージョンではカリキュラム学習は一部しか実装されておらず、利用するにはコードを改変して自分で対応するしかありませんでした。今回、カリキュラム学習に標準で対応した事でその様な事をしなくて済む様になりました。具体的には、下記の様な json ファイルを作り `ppo.py` の起動時にオプションの `--curriculum=<file>` を指定する事で対応可能です。

```:sample.json
{
    "measure" : "reward",
    "thresholds" : [10, 20, 50],
    "min_lesson_length" : 3,
    "signal_smoothing" : true, 
    "parameters" : 
    {
        "param1" : [0.7, 0.5, 0.3, 0.1],
        "param2" : [100, 50, 20, 15],
        "param3" : [0.2, 0.3, 0.7, 0.9]
    }
}

```

項目の意味は、下記の様な感じです。

- `measure` = レッスンを次に進める基準を何にするか。`reward`: 報酬の多寡、`progress`: ステップの進捗（`steps / max_steps`）。
- `thresholds` = レッスンを次に進める閾値。`measure` の基準で比較。
- `min_lesson_length` = 最低でもどれだけのステップを1レッスンで実行すべきか。
- `signal_smoothing ` = `measure` の値をスムージングするかどうかを `true`/`false` で与える。スムージングすると、例えば報酬（`cumulative_reward`）の値が `前の測定時の報酬` * 0.25 + `今回の測定時の報酬` * 0.75 で判定される事になる。要は `true`
 にしておくと突発的に高い値が出た時にそれでレッスン OK と判断してしまうリスクを減らす事ができる。
- `parameters` = それぞれのレッスンで使う `reset_parameter` を指定する。`reset_parameter` とは何かと言うと、Unity 側の環境をセットアップするためにリセット時に利用するパラメータの事で、例えば壁が高くて難しいとか、敵の動きが速い、といったパラメータになる。`Academy` の中に `resetParameters` という変数があり、そこに格納される事になるので Unity 側でそれを利用して環境を再構築する事になる。`threshold` で与えた配列の要素数よりも１つ多い要素数である必要がある（当たり前ですが、レッスンが進んだら次のパラメータが必要になるので）。

上記の例では、下記の様なリセットパラメータが Unity 側に送られる事になります。

```:reset_parameter.json
{ "param1": 0.7, "param2": 100, "param3": 0.2 } ←レッスン0
{ "param1": 0.5, "param2": 50, "param3": 0.3 } ←レッスン1
{ "param1": 0.3, "param2": 20, "param3": 0.7 } ←レッスン2
```
これらを使って、環境を構築します。

`signal_smoothing` は値直接指定でもよかったんではないかと思いますけどね。デフォルトで `1.0` とかにしておいて🤔

リセットパラメータについては少し注意が必要で、**Academy の `done` をしないと反映されません**。延々いつまでも試行し続ける環境を作って報酬がどんどん上がっていったとしても `done` しない事には次のレッスンに進まない事には注意が必要です。

ちなみにカリキュラム学習を `--load` と共存させると再度起動した時にレッスン 0 から開始される事になってしまって微妙なので、これは今私が修正して[プルリク](https://github.com/Unity-Technologies/ml-agents/pull/179)を投げておいたので取り込まれれば途中からレッスンを指定して起動する事ができる様になります。

## ブロードキャストという機能が加わった
v0.2 ではブロードキャストという機能が加わりました。これは何かと言うと、これまで学習する時には `BrainType` が `External` でなければならず、PPO が決定した行動によって環境とインタラクトして報酬を決定して学習するという事しかできませんでした。しかしブロードキャストをオンにすると、`Player`, `Heuristic`, `Internal` でも同様のプロセスを経る事ができます。これによって何が可能になるかと言うと、`Imitation Learning`（模倣学習）、つまり人間がお手本となる動きを教えられるという事です。

例えば、`BrainType` を `Player` にした上で実行すると、自分がその Agent の実行主となり、その行動と報酬を Python 側に渡す事ができる様です。これは面白そう！でも私もまだ試していません😅 近々試してみたいと思います！

詳しい事は今後 Unity の公式ブログで紹介される予定との事なので、楽しみにしておきましょう。

## フレキシブルモニタという機能が加わった

これまで、`AgentMonitor` は固定の要素を表示してくれるだけで（要素のオンオフはできましたが）あまり汎用性のあるものではありませんでした。そこで、v0.2 ではこれを書き直し、自由に要素を追加できる汎用性のあるものとしています。

![Monitor](https://github.com/Unity-Technologies/ml-agents/raw/master/images/monitor.png)

具体的には、`Monitor` クラスの static メソッドの `Log` を呼び出す事で様々な表示が行える様になっています。詳しくは[公式のドキュメント](https://github.com/Unity-Technologies/ml-agents/blob/master/docs/monitor.md)をご参照下さい。

# 公式ブログに大きく謳われてはいないが地味に便利な機能たち
さて、ここまで主に公式ブロクに書かれている内容をご紹介してきました。しかし、リリースノートをよく見てみると地味に便利な機能や改修が多く含まれています。ここでは、それらを列挙してみます。

- サンプル実装がいくつか追加されている
    - 初心者の方は先ずはこれらを実行していじって感覚を掴むのがよいと思います
- ステートが自動で正規化できる様になった（オプション）
    - ステートはこれまで正規化（`0〜1` の値に調整すること）する事が推奨されていました
    - 正規化するために `xx/yy` とかやっていると、ふいに `yy` に 0 が入ってしまい方策が一気に壊れるという事がありましたが、自動でやってくれるとそういう事もなさそうです
- 学習環境（hoge.app）が絶対パスで指定可能になった
- 学習環境の例外が `unity-environment.log` ファイルに出力される様になった
    - これまで例外が結構確認し辛かったのですが、ファイルに出力されるのであれば確認しやすそうです
- 大きなステートやカメラの情報に対応した
    - これまでかなり大きなステート情報などを Python 側に送ろうとするとエラーになってしまう事がありました。これが解消されている様です
- `CumulativeReward` の値が正確に報酬の値をトラックする様になった
    - これは具体的なバグ内容までは把握できていませんが、おそらく何か計算にミスがあったのだと思います
- `AcademyReset` が `AgentReset` の前に呼ばれる様になった
- `isInference` がエディタ上で正確に動作する様になった
- `Frame-rate is unlocked by default when in isInference is false.`
    - これ正直何を言っているのか分かりませんでした。`inference` が `false` という事は学習時の事を言っているのだと思いますが、`frame-rate is unlocked` というのは何を指しているんでしょうね。。。よく分かりません。
- `num-layers` オプションが追加されている
    - これはリリースノートにも書かれていない機能なのですが、結構インパクトがある気がしています
    - これまで、`hidden-units` で隠れ層の1層の要素数は指定できましたが、層の数自体は指定できませんでした（2で固定だった）
    - v0.2 では、`num-layers` オプションで層の厚みを指定する事ができ、より複雑な学習ができる様になりました

個人的にはステートの自動正規化や、大きなステートでのバグ修正、`num-layers` は結構アツい修正だなと思っています。みなさんはいかがでしょうか？

# 終わり

それでは、よい Unity ML-Agents ライフを！　何か間違いなどありましたら、コメント頂ければと思います。