0.7.0だと色々変更になったものと思います。たっつー様が0.7.0の導入方法を以下で公開して下さっていることをお知らせくださいました。
Unityで新規プロジェクトを作って、ML-Agentsの0.6.0aを組み込む手順です。
以下のML-Agentsリポジトリーのドキュメントを元に進めていきます。
目次
- 目次
- 動作環境
- 0.5.0で環境を作成済みの場合
- このチュートリアルで作るもの
- Unityプロジェクトの作成
- 環境(Environment)を作る
- アカデミーの実装
- ブレイン(Brain)を追加する
- エージェントの実装
- 仕上げのエディター設定
- 環境を手動で試す
- 環境の学習
- シーンのまとめ
- 学習したモデルを試す
- おまけ
- 学習効果を高める(おまけ)
- まとめ
- 参考URL
動作環境
以下で確認しました。
- Windows10
- Unity2018.2.10
- ML-Agents Beta 0.6.0a
ML-Agentsのリポジトリーをクローンしていなかったり環境構築ができていない場合は、以下で済ませてください。
0.5.0で環境を作成済みの場合
PythonとAnaconda、TensorFlowは、0.5.0と同じバージョンなのでそのまま使えます。Pythonの実行環境に0.6.0用のツールをインストールする必要があるので、新しく実行環境を作ってインストールします(0.5.0を全く使わなくなるのであれば、0.5.0用のものに上書きインストールしても大丈夫そうです)。
- こちらのML-Agentsツールキットリポジトリーのダウンロードに従って、ML-Agentsのリポジトリーをクローンするか、ダウンロードして、ドキュメントフォルダーなど使いやすいところに展開してください
- スタートメニューなどから、Anaconda Promptを起動します
- 以下を実行して0.6.0用のPythonの実行環境を作成します。質問が表示されたらyキーでインストールを進めます
conda create -n ml-agents060 python=3.6
- 完了したら、以下を実行して実行環境を開始します
activate ml-agents060
cd
コマンドで、クローンやダウンロードした0.6.0のML-Agentsフォルダーを開きますcd ml-agents
でml-agents
フォルダーを開きます- 以下のコマンドを実行します
pip install -e . pip install pypiwin32
以上で、0.6.0用のファイルがインストールされます(2行目のpypiwin32
のインストールは、2019/1/17時点で発生するエラーを回避するためのものです。そのうち不要になるかも。こちら参照)。
Anaconda Promptはあとで利用するので開きっぱなしにしておいても構いません。
このチュートリアルで作るもの
ランダムな場所に登場するキューブを取るようにボールを操作するAIを学習して作ります。また、ボールが地面から落下しないようにもします。
- AIで動かすオブジェクトであるエージェント(Agent)が活動する環境(environment)をUnity上に作ります。環境は、いくつかのオブジェクトによるシンプルな物理シミュレーションから、ゲームやエコシステム全体まで含みます
- アカデミー(Academy)サブクラスを実装してゲームオブジェクトにアタッチして、環境を組み込んだUnityのシーン内に配置します。アカデミークラスには、AIエージェントとは別にシーンを更新するいくつかのオプションのメソッドを実装できます。例えば、環境内に、AIエージェントやその他のオブジェクトを追加、移動、削除したりできます
- 1つ以上のAIのブレイン(Brain=脳)を、AssetsメニューやProjectウィンドウのCreateボタンから、Create > ML-Agents > Brainを選択して作ることができます。名前は自由につけることができます
エージェントサブクラスを実装します。エージェントサブクラスは、環境を観察するためのコードを定義して、行動を割り当てて、強化学習のための報酬(Reward=リワード)を計算します。また、学習が終了したり、タスクが失敗した時に、エージェントをリセットするメソッドを実装することができます
AIで制御したいゲームオブジェクトに、作成したエージェントサブクラスをアタッチすることで、そのオブジェクトはAIで行動するようになります。エージェントには必ずブレインアセットを割り当てる必要があります
- AIを学習(Training)させる時は、アカデミーオブジェクトのBroadcastHub欄のControlチェックボックスにチェックを入れます
- 学習してできたモデルデータを使ってUnityでAIを動かすには、アカデミーオブジェクトのControlチェックボックスのチェックを外して、モデルデータをブレインに設定します。学習についてはこちら
Note
- Unityの操作になじみがなく、このマニュアルの操作が理解できない場合は、Unityの公式マニュアルのLearning the interfaceをおすすめします。
Unityプロジェクトの作成
まずは、新規でUnityプロジェクトを作成して、ML-Agentsを組み込みます。
- Unity2017.4以降を起動して、
RollerBall
などの名前で新しいプロジェクトを作成します - Editメニューから、Project Settings > Playerを選択します
以下を、利用したいプラットフォームごとに実施します
- Other Settingsを開きます
- Scripting Runtime VersionがExperimental、あるいは.NET 4.6 Equivalent、あるいは.NET 4.x Equivalentにします(2018.3ではデフォルトで4.xになっているのでこの手順は不要)
- Restartするかのウィンドウが表示されたら、Restartします
ML-Agentsのデータをプロジェクトに読み込みます。
- エクスプローラーで、ダウンロード(あるいはクローン)して展開したml-agentsフォルダーを開きます
UnitySDK/Assets
フォルダーを開きます- フォルダー内にある全てのファイルとフォルダーを選択したら、ドラッグしてUnityの
Project
ウィンドウにドロップしてインポートします
Unityのバージョンによって表示は変わりますが、おおよそ以下のようになります。
環境(Environment)を作る
ML-Agentsの環境用のシーンとして、エージェントが乗っかる床となるPlane、エージェントがゴールや目標として探索するCube、エージェントを表すSphereを作成します。
床のPlaneを作る
- HierarchyウィンドウのCreateをクリックして、3D Object > Planeを選択します
- 作成したPlaneの名前を
Floor
にします - 作成したFloorをクリックして選択します
- InspectorウィンドウのTransform欄を以下の通り設定します
- Position =
0, 0, 0
- Rotation =
0, 0, 0
- Scale =
1, 1, 1
- Position =
- InspectorウィンドウのMesh Renderer欄にあるMaterialsの左の三角をクリックして開いたら、Element 0の右の〇をクリックして、ウィンドウからLightGridFloorSquareマテリアル(別のものでも構いません)を選択して割り当てます
以上で床は完成です。
取るためのキューブを作る
- HierarchyウィンドウのCreateをクリックして、3D Object > Cubeを選択します
- 作成したCubeの名前を
Target
にします - 作成した
Target
をクリックして選択します - InspectorウィンドウのTransform欄を以下の通り設定します
- Position =
3, 0.5, 3
- Rotation =
0, 0, 0
- Scale =
1, 1, 1
- Position =
- InspectorウィンドウのMesh Renderer欄にあるMaterialsの左の三角をクリックして開いたら、Element 0の右の〇をクリックして、ウィンドウからBlockマテリアルを選択して割り当てます
エージェント(Agent)とするSphereを作る
- HierarchyウィンドウのCreateをクリックして、3D Object > Sphereを選択します
- 作成したSphereの名前を
RollerAgent
にします - 作成した
RollerAgent
をクリックして選択します - InspectorウィンドウのTransform欄を以下の通り設定します
- Position =
0, 0.5, 0
- Rotation =
0, 0, 0
- Scale =
1, 1, 1
- Position =
- InspectorウィンドウのMesh Renderer欄にあるMaterialsの左の三角をクリックして開いたら、Element 0の右の〇をクリックして、ウィンドウからCheckerSquareマテリアルを選択して割り当てます
- Add Componentをクリックします
- PhysicsからRigidbodyを選択してアタッチします
後程、このオブジェクトにエージェントサブクラスをアタッチします。
アカデミー(Academy)を持たせるための空のゲームオブジェクトを作る
- HierarchyウィンドウのCreateをクリックして、Create Emptyを選択します
- 作成したGameObjectの名前を
Academy
にします
以上でシーンが完成です。
Main Cameraの座標や角度を調整して、Gameウィンドウで見やすくなるようにしてください。
アカデミーの実装
アカデミーオブジェクトは、シーン内のML-Agentsを動かして、観測-意思決定-行動というシミュレーションループを制御します。ML-Agentのシーンごとに1つのアカデミーのインスタンスが必要です。アカデミークラスのベースクラスはabstractなので、メソッドを実装する必要がなくてもサブクラスを作成する必要があります。
先に作成したアカデミーオブジェクトに新しいスクリプトを追加します。
- HierarchyウィンドウからAcademyオブジェクトをクリックして選択します
- Inspectorウィンドウで、Add Componentをクリックします
- New Scriptを選択して、
RollerAcademy
という名前で作成します - 作成したRollerAcademyスクリプトをダブルクリックして、エディターで開きます
- MLAgentsの機能を使うために、
using MLAgents;
を定義します - クラスの継承元を
MonoBehaviour
からAcademy
に変更します Start()
とUpdate()
メソッドを削除します
基本的な機能はベースクラスのAcademyが持っているので、実装は不要です。以下の通りにしたら、上書き保存をしてUnityに切り替えます。
using MLAgents; public class RollerAcademy : Academy { }
デフォルトの設定で問題なく動作しますのでそのままの設定で使います。Inspectorウィンドウで変更する項目はありません。
ブレイン(Brain)を追加する
ブレインアセットは、行動を決める処理を担当します。エージェントは自らが観測した情報をブレインに送ります。ブレインは送られてきた観測情報を元に行動を決定してエージェントに伝えます。エージェントは、ブレインから受け取ったデータに従って行動します。作成するブレインアセットの種類によって、そのブレインの行動の決め方を選択することができます(Learning=AI学習, Heuristic=アルゴリズムで実装, Player=人間が操作)。
ブレインアセットを作成します(0.5.0からこの部分が完全に変わりました!)
- ProjectウィンドウのCreateボタンをクリックして、ML-Agentsから、作成したいBrainの種類のアセットを選択します。ここでは、Learning BrainとPlayer Brainを作成します
- 作成したら、それぞれの名前を
RollerBallBrain
と、RollerBallPlayer
にします
設定は実際に動かす時に行うので、一先ずこのままで先に進めます。
エージェントの実装
エージェントを制御するスクリプトを作成します。
- Hierarchyウィンドウから、RollerAgentオブジェクトをクリックして選択します
- Inspectorウィンドウで、Add Componentをクリックします
- New Scriptを選択して、
RollerAgent
という名前で作成します - 作成したRollerAgentスクリプトをダブルクリックして、エディターで開きます
- Academyの時と同じように、
using
を設定して、ベースクラスをMonoBehaviour
からAgent
に変更します
以下のようなコードになります。
using MLAgents; public class RollerAgent : Agent { }
上書き保存をして、Unityに戻ります。
ここまでの手順は、あらゆるUnityのプロジェクトにML-Agentsを加える基本的な手順です。次に、強化学習を使ってSphereのエージェントがキューブを取るように動かすためのロジックを加えていきます。
今回のシンプルなシナリオでは、アカデミーオブジェクトに環境の変更は実装しませんが、シミュレーション前やシミュレーション中に、床の大きさを変えたり、エージェントやその他のオブジェクトを追加したり削除したりしたい場合は、アカデミーにメソッドを自由に追加して実装することができます。ここでは、エージェントが成功したり失敗した時に、エージェントや目標物をリセットすることだけを行います。
エージェントの初期化とリセット
今回作成するエージェントは、Targetに触れたら自分自身でそのことを確認して、Targetをランダムな座標に配置し直すリセット関数を呼び出します。また、地面から落下したらリセット関数によって地面に戻します。
Targetオブジェクトに辿り着くには、エージェントはTargetのTransform
への参照を知っている必要があります(Transformには、3D空間における座標、回転、拡大率が記録されています)。そのために、RollerAgent
クラスにpublic
なTransform
を定義します。これにより、InspectorウィンドウでTargetのTransform
を渡せるようになります。
エージェントの速度をリセットしたり、エージェントを動かすための力を与えるために、Rigidbody
コンポーネントの参照が必要です。Rigidbody
は、Unityで物理シミュレーションをするための基本的なエレメントです。スクリプトのゲームオブジェクトにアタッチされているRigidbody
への参照は、Start()
メソッド内で、GameObject.GetComponent<T>()
を使って取得します。
RollerAgent.cs
は以下のようになります。
using System.Collections.Generic; using UnityEngine; using MLAgents; public class RollerAgent : Agent { Rigidbody rBody; private void Start() { rBody = GetComponent<Rigidbody>(); } public Transform Target; public override void AgentReset() { if (this.transform.position.y < 0) { // エージェントが落ちた this.rBody.angularVelocity = Vector3.zero; this.rBody.velocity = Vector3.zero; this.transform.position = new Vector3(0, 0.5f, 0); } // ターゲットを新しい場所へ移動させる Target.position = new Vector3( Random.value*8-4, 0.5f, Random.value*8-4 ); } }
次は、Agent.CollectObservations()
関数(情報を収集する関数)を実装します。
環境を観測する(Observing the Environment)
エージェントは、収集した環境の情報をブレインに送ります。ブレインは送られてきた情報を使って行動を決めます。エージェントを学習する時、あるいは、学習済みのモデルを利用する時に、観測(Observation)したデータをfeature vector(観測結果を表すベクトルデータ)としてニューラルネットワークに与えます。エージェントの学習を成功させるためには、正しい情報を与えなくてはなりません。どの情報を与えるのが正しいかを決めるよい指標は、問題を解決するために何が必要かを分析して考えることです。
今回の場合、エージェントは以下の情報を集めます。
- ターゲットの位置
// :
AddVectorObs(Target.position);
- エージェント自身の位置
// : AddVectorObs(this.transform.position);
- エージェントの速度。速度があれば、Targetを行き過ぎたり、床から転落したりするのを防ぐことを学習する助けになります
// :
AddVectorObs(rBody.velocity.x);
AddVectorObs(rBody.velocity.z);
以上、8次元のベクトル(TargetのX
, Y
, Z
、AgentのX
, Y
, Z
, Agentの速度X
, Z
)で、観測したデータをブレインに渡します。まとめると、以下のようになります。RollerAgent.cs
スクリプトのRollerAgent
クラス内に、以下のメソッドを追加します。
// 32: public override void CollectObservations() { // TargetとAgentの位置 AddVectorObs(Target.position); AddVectorObs(this.transform.position); // Agentの速度 AddVectorObs(rBody.velocity.x); AddVectorObs(rBody.velocity.z); }
エージェント用のコードの仕上げは、ブレインが選択した行動を受け取って、報酬を与えるAgent.AgentAction()
メソッドの作成です。
Actions
ブレインが決めた行動は、AgentAction()
関数に配列で渡されます。この配列の要素数は、エージェントのブレインのVector Actionの設定のSpace TypeとSpace Sizeによって決まります。今回作成しているRollerAgentは、行動データを加える力として利用します。力はfloat値(連続的な値)として使いたいので、Space TypeにContinuous(連続的)を選択します。行動に必要なデータの個数を表すAction Sizeには2
を設定します。1つ目のエレメントaction[0]
をX方向に加える力、2つ目のaction[1]
をZ方向に加える力とします(もし、Y方向の移動もあった場合は、Action Sizeを3
にして、Y方向の力の分を増やします)。ブレインは、これらの値がどのようなものかは把握しません。学習は、観測した入力に対して返す値を調整した結果、どのような報酬が得られるかということだけに注目して行われます。
(補足) Space TypeをDiscreteにすると、ブレインからは整数値が行動として返されるようになります。ボードゲームのマス目や、「止まる」「歩く」「パンチする」「食べる」など整数で表せる行動をさせたい場合は、Discreteにします。
RollerAgentはaction[]
配列の値をRigidbodyコンポーネントであるrBody
のAddForce()
で反映させます。以下、コード例です。実際に追加するコードは後述します。
// : Vector3 controlSignal = Vector3.zero; controlSignal.x = action[0]; controlSignal.z = action[1]; rBody.AddForce(controlSignal * speed);
報酬(Rewards=リワード)
強化学習(Reinforcement learning)では報酬の設定が必要です。報酬は、AgentAction()
関数内で割り当てます(他の場所では無効になるので注意!!)。学習アルゴリズムは、シミュレーションのステップごとにエージェントに報酬を与えて、エージェントにとって最適な行動が何かを学習するのに利用します。エージェントが目的を達成したら(今回ならTargetオブジェクトに辿り着いたら)報酬を与えて、望まない行動をしたら(今回なら床から転落したら)報酬を取り上げます。今回はTargetオブジェクトに辿り着いたら1
の報酬を与えます。
RollerAgentは、Targetに辿り着いたかを検出するために距離を計算します。算出した距離が到達したと判断する値以下になっていたら、Agent.SetReward()
メソッドを呼び出してエージェントに1
の報酬を与えて、完了したことを報告するためにDone()
を呼び出します。
(補足) 報酬を与えるメソッドが、
AddReward
からSetReward
に改名されました。
// : float distanceToTarget = Vector3.Distance(this.transform.position, Target.position); // ターゲットに辿り着いたか if (distanceToTarget < 1.42f) { SetReward(1.0f); Done(); }
メモ: Done()
を呼び出してエージェントが完了したことを知らせると、リセットするまで動作が停止します。Agent.ResetOnDone
プロパティーをインスペクター上でTrueに設定しておくことで、完了したらすぐに自動的にエージェントをリセットすることもできますし、アカデミーがMaxStepに到達して、環境をリセットするのを待つこともできます。今回はResetOnDoneプロパティーをTrueに設定してリセットします。MaxStepは0
のままにして、アカデミーが環境をリセットしないようにします。
最後に、プラットフォームから転落した時にDone
を呼び出して、次のステップで自分自身をリセットさせます。
// : // プラットフォームからの転落 if (this.transform.position.y < 0) { Done(); }
(補足) 0.5.0では床から転落した時に報酬を
-1
していましたが、その処理がなくなっています。あえて報酬を下げなくても、報酬が得られないだけで学習には十分なようです。
AgentAction()
行動と報酬の考え方は以上の通りです。AgentAction()
関数の完成形は以下のようになります。RollerAgent.cs
のRollerAgent
クラス内に加えてください。
// 43: public float speed = 10; public override void AgentAction(float[] vectorAction, string textAction) { // 動作の設定。sizeが2なのでvectorActionは2つ Vector3 controlSignal = Vector3.zero; controlSignal.x = vectorAction[0]; controlSignal.z = vectorAction[1]; rBody.AddForce(controlSignal * speed); // Targetとの距離 float distanceToTarget = Vector3.Distance( this.transform.position, Target.position); // Targetに接触したか if (distanceToTarget < 1.42f) { SetReward(1); Done(); } // プラットフォームから転落 if (this.transform.position.y < 0) { Done(); } }
speed
プロパティーを関数の前にpublic
で定義することで、Inspectorウィンドウで速さを調整できるようにしてあります。
仕上げのエディター設定
全てのゲームオブジェクトとML-Agentコンポーネントの設定が完了したので、データを接続していきます。
- HierarchyウィンドウのAcademyオブジェクトをクリックして選択します
- ProjectウィンドウのBroadcast Hubの下のAdd Brain to Broadcast Hubボタンをクリックします
- もう一つ設定したいので、Add Newボタンをクリックして増やします
- ProjectウィンドウからRollerBallBrainをドラッグして、InspectorウィンドウのBrains欄にドロップします。RollerBallPlayerも同様に2つ目のBrains欄にドラッグ&ドロップします
- HierarchyウィンドウからRollerAgentオブジェクトをクリックして選択します
- ProjectウィンドウからRollerBallPlayerをドラッグして、InspecorウィンドウのBrain欄にドロップします
- InspectorウィンドウのDecision Frequencyを
10
にします(ブレインは10ステップごとに意思決定をして、行動は毎フレーム実行します) - HierarcyウィンドウからTargetオブジェクトをドラッグして、InspectorビューのTarget欄にドロップします
最後に、Brainアセットの設定をします。
- ProjectウィンドウからRollerBallBrainアセットをクリックして選択したら、Inspectorウィンドウで以下を設定します。
- Vector ActionのSpace Type = Continuous
- 行動結果を表すベクトルを、整数(Discrete=不連続)で返すか、小数(Continuous=連続)で返すか
- Vector ActionのSpace Size = 2
- 行動結果として返すベクトルの次元数(要素数)
ProjectウィンドウからRollerBallPlayerアセットをクリックして選択して、以上と同じく設定します。これで環境を試すための準備が整いました。
環境を手動で試す
実際に学習を開始する前に、手動で環境を試すのがおすすめです。RollerAgentのBrainにRollerBrainPlayerを設定したので、キー入力でAgentオブジェクトを操作することができます。実行する前に、前後左右の4方向に移動するためのキーを4つ割り当てます。
- ProjectウィンドウからRollerBallPlayerアセットをクリックして選びます
- InspectorウィンドウのKey Continuous Player Actions欄を開きます(この設定は、PlayerBrainのみ表示されます)
- Sizeを
4
にします - 以下の通り、設定します
Element | Key | Index | Value |
---|---|---|---|
Element 0 | D | 0 | 1 |
Element 1 | A | 0 | -1 |
Element 2 | W | 1 | 1 |
Element 3 | S | 1 | -1 |
Indexの値は、AgentAction()
関数に渡す配列のインデックスを表します。Valueの値は、Keyが押された時にvectorAction[Index]
に渡される値です。
Playすると、[W][A][S][D]キーで、Agentを操作することができます。エラーが発生しないことと、Targetに触ったり床から落ちたらエージェントがリセットされることを確認してください。ML-Agents SDKには、ゲームウィンドウにエージェントの状態を簡単に表示させることができるMonitor
クラスが用意されています。より詳細な状態が見たい場合は利用するとよいでしょう。
(ここではやりませんが)作成した環境とPython APIが想定通りに動くかどうかを、Jupyter notebookを使って試すことができます。確認のためには、notebooks/getting-started.ipynb
を利用します。ノートブックのenv_nameに、この環境をビルドして生成した実行ファイル名を設定します。
環境の学習
学習を開始するには、AgentのBrainをRollerBallBrainに変更して、AcademyオブジェクトのControlプロパティーにチェックを入れます。
- HierarchyウィンドウでRollerAgentをクリックして選択します
- ProjectウィンドウからRollerBallBrainをドラッグして、InspectorウィンドウのBrain欄にドロップします
- HierarchyウィンドウでAcademyオブジェクトをクリックして選択します
- InspectorウィンドウのBroadcast Hub欄に設定したRollerBallBrainの右のチェックボックスにチェックを入れます
これで、AIのブレインを利用するようになります。ここからの設定は、Training ML-Agentsと同様です。
mlagents-learnプログラムに渡すconfigurationファイル内の学習のためのパラメーターを設定します。Clone、あるいはダウンロードしたml-agents
フォルダー内のconfig/trainer_config.yaml
ファイルにデフォルト値が設定されています。
今回は、この設定ファイルのdefault
設定を利用します。そのままの設定で学習させる場合、30万ステップ程度学習させる必要があります。しかし、以下の設定をすることで、2万ステップ程度で学習を完了させることができるようになります。
batch_size: 10 buffer_size: 100
今回のサンプルは、入力も出力も数が少ないシンプルな学習なので、小さなバッチ(batch)やバッファー(buffer)サイズにして、学習を高速化することができます。ただし、環境が複雑になったり、報酬や観測方法を変更したら、このパラメーターは調整が必要になるかも知れません。
Note: trainer_config.yaml
に加えて、AgentのDecisionFrequencyパラメーターも、学習時間や成功するかどうかに大きく影響します。大きな値を設定すると、学習アルゴリズムが行動を判断する回数を減らすことができるので、今回のようなシンプルな環境では学習のスピードアップにつながります。
エディターで学習を開始するには、UnityでPlayする前に、ターミナルやコマンドプロンプトからPythonコマンドを実行します。
- Anaconda Promptを起動していなかければ、スタートメニューなどから起動します
- 以下を実行して、ML-Agents用の実行環境を開始します
activate ml-agents060
- クローンやダウンロードした
ml-agents
フォルダーにcd
コマンドで移動します - 初めて学習する時は、設定を調整するために、
config
フォルダー内のtrainer_config.yaml
を何らかのエディターで開きます default
の設定の以下の部分を書き換えます
- 名前を付けて保存を選択して、
config.yaml
の名前で保存します - Anaconda Promptで以下を実行します
mlagents-learn config/config.yaml --run-id=RollerBall-1 --train
しばらく待つと以下のような画面が表示されて、最後にUnityをPlayするようにメッセージが出るので、UnityをPlayしてください。
Unity上で学習が始まります。2万ステップの学習が完了したら、Anaconda Promptが以下のように表示されて学習が完了します。
学習の様子は、TensorBoardを使ってグラフで確認できます。
Anaconda Promptで、以下を実行します。
tensorboard --logdir=summaries
以下のようなメッセージが表示されます。
- Webブラウザーで、メッセージの最後の部分に書かれている
http://
で始まるURLを開いてください - 以下のようにグラフが確認できます
Environment欄のCumulative Rewardと、Policy欄のValue Estimateのグラフで、エージェントが目的をどれぐらい達成できたかを把握できます。今回の例では、エージェントが得られる最大の報酬は1.0
です。エージェントが目的を達成するほど、グラフは1.0
に近づきます。
Note: TensorBoardを利用する場合、mlagents-learn
コマンドで学習を実行するたびに、run-idの部分を増やすなどして変更した方がよいかも知れません。同じrun-idで学習させると、過去の学習結果のグラフも重ねて表示されるので、傾向の把握が難しくなる可能性があります。
シーンのまとめ
Unity環境で、ML-Agentsを利用する時にシーンをどのように構成するかをまとめます。
Unity ML-Agentを利用する場合、一つのアカデミーと、一つ以上のエージェントゲームオブジェクトが必要です。また、利用したい種類のブレインアセットを作成して、エージェントとアカデミーに設定する必要があります。
約束事です。
- 一つのシーンには、アカデミーゲームオブジェクトを一つだけ配置します
- 学習に利用できるブレインは、アカデミーのBroardcast Hubリストに追加したものだけです
参照したドキュメントは以上です。以下はこのブログでの追記です。
学習したモデルを試す
学習が完了したモデルを使って、実際にRollerAgentを動かしてみます。再生するには、TensorflowSharpプラグインをプロジェクトにインポートする必要があります。0.5.0の時と同じプラグインが利用できるので、ダウンロード済みのTFSharpPlugin.unitypackage
があればそれを利用できます。
- https://github.com/Unity-Technologies/ml-agents/blob/master/docs/Using-TensorFlow-Sharp-in-Unity.mdを開きます
- Requirements欄のDownload hereをクリックして、プラグインをダウンロードします
- ダウンロードした
TFSharpPlugin.unitypackage
をドラッグして、Projectウィンドウにドロップして、インポートします
- Editメニューから、Project Settings > Playerを開きます
- Other SettingsのScripting Define Symbolsに、
ENABLE_TENSORFLOW
と入力します - Allow 'unsafe' Code欄にチェックを入れます
以上、ビルドしたい全てのタブでおこないます。
学習させたモデルデータをブレインに設定します。
- エクスプローラーなどで、ML-Agentsをクローンやダウンロードしたフォルダーを開きます
- フォルダー内の
models
>RollerBall-1
を開きます RollerBallBrain.bytes
をドラッグして、UnityのProjectウィンドウにドロップしてインポートします
- Projectウィンドウから、RollerBallBrainアセットをクリックして選択します
- Projectウィンドウから、インポートしたRollerBallBrainをドラッグして、InspectorウィンドウのModel欄にドロップします
- HierarchyウィンドウからAcademyオブジェクトをクリックして選択します
- InspectorウィンドウのRollerBallBrain欄のControlのチェックを外します
以上で学習したモデルデータを使ってRollerAgentが動くようになります。
おまけ
default以外の設定を使う
ドキュメントではconfig.yaml
のdefault
設定を書き換えましたが、ブレインアセットの名前をキーにして、ブレインごとの設定を作ることができます。
上記のようにすることで、default
を書き換えなくても、RollerBallBrain
を学習させるときに利用したい設定をすることができます。
ログの見方
コンソール画面に謎の文字が表示されますが、ここから学習がどのように進んでいるかを読み取ることができます。このログは、設定した回数ごとの集計になっています。デフォルトでは千回に1回、集計されて以下のように表示されます。
重要なのはStep以降の部分です。
Step
何ステップ学習したかを表示します。今回は2万ステップ設定したので、Step: 20000.
で終了しています。
Mean Reward
獲得した報酬の平均値です。最初の千回の平均は0.212
で、かなり失敗していることが分かります。学習を進めることでどんどん改善して、1万4千ステップには1.000
を達成しています。ほぼ全部ターゲットを取ったということです。
Std of Reward
報酬の標準偏差です。標準偏差とは、データのバラつきを表す値です。全てのリワードが同じ値ならこの値は0
になり、バラけているほど大きな値になります。
AIがめちゃくちゃに動いている最初の方は、得られる報酬がバラバラなので大きな値になりがちです。頭が良くなるにつれて行動が似てくるので報酬のバラつきが減り、この値は小さくなっていくのが一般的です。
最初からこの値が小さい場合、めちゃくちゃに動いても報酬に変化がないことになります。この場合、学習のしようがないので報酬の与え方がよくないか、エージェントの設定に失敗している可能性があります。
学習の再開
同じrun-idで学習を開始しても、前に学習した内容は破棄されて学習はやり直しになります。今回は2万ステップで学習は十分でしたが、試した結果、もう少し学習を継続させたい場合があります。その時は、config.yaml
を開いてmax_stepsの値を増やして上書き保存をしてから、Anaconda Promptで以下を実行すれば、先ほどのデータの続きから学習を再開できます。
mlagents-learn config/trainer_config.yaml --run-id=RollerBall --train --load
注意!!: すでに学習ステップ数がmax_stepsに達していたら、学習を再開させてもすぐに終わってしまいます。学習回数を増やす場合は、config.yaml
のmax_stepsを増やす必要があります。
学習効果を高める(おまけ)
0.5.0と共通の知見としては、以下が挙げられます。
バッチとバッファの設定を適切にする
default値のまま学習すると、2万ステップでは学習が全く足りませんでした。どのぐらいの値がよいかの指標があるのかないのかも含めて調査したい項目です。
ベクトルの観測データはベクトルのまま渡す
観測データ(CollectObservations()
メソッド内でAddVectorObs()
メソッドで渡すデータ)がベクトルの場合、使ってないデータがあってもベクトルのまま渡した方がよさそうでした。
今回のサンプルでは、RollerAgent
のX
とZ
の速度を個別のAddVectorObs()
メソッドで渡していますが、これによって学習効果が下がってしまうようです。
RollerBallBrain
アセットのSpace Size
を9
にして、RollerAgent.cs
スクリプトのCollectObservations()
メソッドを以下のように書き換えて、学習しなおすと効果が分かります。
// 36: public override void CollectObservations() { // TargetとAgentの位置 AddVectorObs(Target.position); AddVectorObs(this.transform.position); // Agentの速度 AddVectorObs(rBody.velocity); }
以下、学習結果です。青がサンプルのまま。オレンジがRollerAgentの速度をベクトルで与えた時のものです。
速度をベクトルで与えたところ、1万ステップの辺りでMean Rewardが1.000
になることもありました。ベクトルデータはベクトルのまま渡した方がよさそうです。
まとめ
Unityの新規プロジェクトに学習用の環境を構築して、Pythonと連携した強化学習の実行、そして学習結果のモデルデータを利用してエージェントを動かすことができました。
0.5.0との目立った違いとしては以下が挙げられます。
- ブレインがアセットになって、設定が楽になった
- 学習の切り替えを、AcademyのControlチェックでできるのも楽
- 報酬を設定するメソッドが
SetReward
に変更になった
あとはおおよそそのままいけました。慣れれば導入はかなり簡単だと思います。楽しいAIライフを!
参考URL
- ml-agents/Learning-Environment-Create-New.md at master · Unity-Technologies/ml-agents · GitHub
- GitHub - Unity-Technologies/ml-agents: Unity Machine Learning Agents Toolkit
- Unity ML-AgentsをWindows10で使う 2018年11月版 - tanaka's Programming Memo
- TensorFlowSharpプラグインのダウンロード
- ModuleNotFoundError: No module named 'win32api' · Issue #1362 · Unity-Technologies/ml-agents · GitHub
- ml-agents/Migrating.md at master · Unity-Technologies/ml-agents · GitHub