はじめに
今回は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
コンポーネントをアタッチして、以下のように設定します。
Base Area
には、先ほど作成したPrefabを指定します。なお、Num Areas
は複製する環境の個数、Separation
は複製された環境同士の距離を示します。
ここまでの設定をしたのちにPlayモードで起動するとシーンは以下のような状態になります。
並列・独立に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と環境の通信
通信の様子が複雑なので、時系列が分かるように図にしました。
以下に要点をまと目ます。
- ◎で表されるのが
step
メソッドの呼び出しです。Python側のステップは、step
が呼び出されてから、次にstep
が呼び出されるまでの間を指します。step
メソッドはステップを1つ進めるメソッドということです。 -
step
命令を受け取ったUnity環境は、受け取った時点での決定待ちのエージェントを覚えておき、それらの行動をget_steps
とset_actions
によってPython側に指定してもらいます。 - 決定を設定後に
step
メソッドを呼び出すと、step
命令を出すと同時に、set_actions
で設定されている決定がUnity側に伝わる。これにより、ステップ開始時に決定待ち状態だったエージェントたちが再起動する
おわりに
今回は具体的な実装には立ち入らず、理論的なmlagents-envsの通信モデルを解説しました。複数のプログラムが非同期的に動くので理解が難しいところではありまずが、自分自身で図を書いてみるなどすれば、徐々に分かってくると思います。