ML-Agents Python Low Level API入門：Pythonによる環境操作その2

# はじめに
今回はPythonパッケージmlagents-envsのアーキテクチャについて、理論的な側面を解説していきます。あまりコードは出てきませんが、重要な概念なのでしっかり理解しましょう。

# 環境操作のアーキテクチャ
まず、第一に抑えておくべきことは、mlagents-envsは他の多くのUnityを用いた機械学習の手法と比べて"Python寄り"であるということです。他の手法としてメジャーなものを列挙します。

- IronPythonやPython.NETなど、UnityがPythonを呼べるようにするための手法
- ML.NETやTorch.NETなど、C#で直接学習できるようにするための手法

これらはあくまで「Unityがメインで、Pythonの資産をUnityから呼び出したり、Unity側にNumpyなどと同等の機能を提供する。学習はUnity内で行われる」という考え方をとっています。
これらに対してmlagents-envsは「環境を進める」「リセットする」などの命令をUnity側に伝えて、その結果をもらってPythonに返すだけという通信路としての役割を持つライブラリになります。そして、学習部分はすべてPythonに丸投げしているのです。したがって、**mlagents-envsは学習に関する機能を全く持っていません**。強化学習用ライブラリという先入観を持ってしまうと、mlagents-envsが何をやっているのか分からなくなってしまうので注意してください。

# UnityEnvironmentとBaseEnv
```UnityEnvironment```と```BaseEnv```は、Pythonから環境を操作するための重要なクラスです。```BaseEnv```は抽象クラスで、環境操作のための基本的なメソッドを備えています。そして、```UnityEnvironment```はその具体的な実装です。mlagents-envsに```BaseEnv```を実装するクラスは```UnityEnvironment```しかありませんが、Unityに接続しない方法で新しい環境を作成したとしても、```BaseEnv```に要求さえ満たせば同じコードでmlagents-envsを用いた学習をすることができます。

# 基本的な環境操作
```BaseEnv```のメソッドのうち、環境全体の操作として特に重要なのが```reset```と```step```と```close```です。

- ```reset```：シミュレーションを最初からスタートする。環境を生成したら最初に呼び出す。Unityと通信している場合は、自動的にエージェントの```OnEpisodeBegin```が呼ばれて、初期化処理が行われる
- ```step```：1ステップだけシミュレーションを進める。この部分はややこしいので後述
- ```close```：シミュレーションを終了して、環境との接続を切る。Unityと通信している場合は、Unityアプリケーションがシャットダウンする

```reset```および```close```は非常に直感的な挙動をしますが、```step```は、強化学習の環境がどのようなアーキテクチャで動いているのかを理解していないと使いこなすことはできません。

# 並列学習
ここでいったんUnityでの環境作成に話を戻します。深層強化学習に限らず深層学習では学習を速めるためバッチ処理を行います。バッチ処理とは、複数個のデータを同時に利用して学習する処理です。そのため、Unity内部には並列して複数のTraining Areaが作成されます。Training Areaについては強化学習の環境を作成したときに、詳しくは後述するといって作成していました。この章でTraining Areaについて詳しく述べます。

まず、Unityを開いて、```TrainingArea```ゲームオブジェクトをプレハブ化しましょう。
新たに空のゲームオブジェクトを作成し```Replicator```と命名しましょう。さらに、```Training Area Replicator```コンポーネントをアタッチして、以下のように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1412657/d723ff5f-322b-40c7-e1c0-32bd9f6b0e79.png)
```Base Area```には、先ほど作成したPrefabを指定します。なお、```Num Areas```は複製する環境の個数、```Separation```は複製された環境同士の距離を示します。
ここまでの設定をしたのちにPlayモードで起動するとシーンは以下のような状態になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1412657/52a3b3c8-8313-a724-f4f8-981185a12e14.png)
並列・独立に```Num Areas```に指定した個数の環境が動いていることが分かります。ここで作成されたエージェントは並列して行動し、並列してstepを進め、並列してエピソードを終えます。もちろん、エピソードを終えずに生き残り続けるものも存在します。すぐに脱落して再初期化し、エピソードを再開するものもいます。ちなみに、Replicatorが複製するのは、```Num Areas```-1個なので、最初にプレハブ化したTraining Areaは残しておかないと数が1つ少なくなってしまうので注意しましょう。

これらの複数のエージェントから次々と、しかもランダムな時間間隔で収集してくる情報を、ただ1つのPythonプログラムが受け取って制御するというのが、mlagents-envsのアーキテクチャになります。

# stepメソッドの詳細
## stepメソッドの前提
stepメソッドは、一言でいえば、Python側の学習stepを進めるメソッドです。注意点とは、**UnityのUpdateやFixedUpdateおよび、強化学習エージェントのstepとは完全に無関係に刻まれるstepである**ということです。あくまでPython都合の学習stepを1ステップだけすすめるメソッドです。これには、並列学習においてエージェントのステップはばらばらに刻まれることから、それにたった1つのPythonプログラムが追随するのは不可能であるという理由があります。

## エージェントの扱い方
エージェントは強化学習の環境に複数存在するので、それぞれにIDが割り振られています。```AgentId```という名前のint型の数値として与えられています。これらのエージェントが非同期的かつ並列に経験を収集するのですが、その過程でエージェントは2つの状態を行き来します。

- 実行中：決定無しに行動できるフレームであったり、1つの決定後は数秒決定が無くてもいい場合、対戦ゲームの相手の行動待ちなど、エージェントが自律的に行動できる状態
- 決定待ち：エージェントが強化学習モデルを使った決定を迫られている状態。この状態になると、訓練中のPythonモデルに決定を任せるためにエージェント、およびTraining Areaは動作をストップします

エージェントはこれらの状態を行き来しながら、適宜Pythonに決定を要求します。

## get_stepsとset_actions
```step```に関連するメソッドを2つ紹介します。```get_steps```と```set_actions```です。これらは、実行中と決定待ちを行き来するエージェントに決定を与えるために重要な役割を果たしています。細かい仕様はおいておいて、基本的な役割を説明します。

- ```get_steps```：「今回のstep」までに決定待ちに入っていたエージェントの情報を取得する
- ```set_actions```：「今回のstep」までに決定待ちに入っていたエージェントの行動を設定する

ここで「今回のPython側のstep」というのが理解のキーになります。ここまでで環境との通信を理解するための前提知識がそろいました。

## 図解：Pythonと環境の通信
通信の様子が複雑なので、時系列が分かるように図にしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1412657/8174f99f-7eb5-76bb-eb61-ae49e9ad710c.png)
以下に要点をまと目ます。
- ◎で表されるのが```step```メソッドの呼び出しです。Python側のステップは、```step```が呼び出されてから、次に```step```が呼び出されるまでの間を指します。```step```メソッドはステップを1つ進めるメソッドということです。
- ```step```命令を受け取ったUnity環境は、受け取った時点での決定待ちのエージェントを覚えておき、それらの行動を```get_steps```と```set_actions```によってPython側に指定してもらいます。
- 決定を設定後に```step```メソッドを呼び出すと、```step```命令を出すと同時に、```set_actions```で設定されている決定がUnity側に伝わる。これにより、ステップ開始時に決定待ち状態だったエージェントたちが再起動する

# おわりに
今回は具体的な実装には立ち入らず、理論的なmlagents-envsの通信モデルを解説しました。複数のプログラムが非同期的に動くので理解が難しいところではありまずが、自分自身で図を書いてみるなどすれば、徐々に分かってくると思います。