0.7.0だと色々変更になったものと思います。たっつー様が0.7.0の導入方法を以下で公開して下さっていることをお知らせくださいました。
www.fast-system.jp
Unityで新規プロジェクトを作って、ML-Agentsの0.6.0aを組み込む手順です。
こんな感じ
以下のML-Agentsリポジトリ ーのドキュメントを元に進めていきます。
github.com
目次
動作環境
以下で確認しました。
Windows10
Unity2018.2.10
ML-Agents Beta 0.6.0a
ML-Agentsのリポジトリ ーをクローンしていなかったり環境構築ができていない場合は、以下で済ませてください。
am1tanaka.hatenablog.com
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を起動します
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プロジェクトを作成して、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
ウィンドウにドロップしてインポートします
Import ML-Agent System
Unityのバージョンによって表示は変わりますが、おおよそ以下のようになります。
Imported Packages
環境(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
Inspector ウィンドウのMesh Renderer 欄にあるMaterials の左の三角をクリックして開いたら、Element 0 の右の〇をクリックして、ウィンドウからLightGridFloorSquare マテリアル(別のものでも構いません)を選択して割り当てます
Set Material
以上で床は完成です。
取るためのキューブを作る
Hierarchy ウィンドウのCreate をクリックして、3D Object > Cube を選択します
作成したCubeの名前をTarget
にします
作成したTarget
をクリックして選択します
Inspector ウィンドウのTransform 欄を以下の通り設定します
Position = 3, 0.5, 3
Rotation = 0, 0, 0
Scale = 1, 1, 1
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
Inspector ウィンドウのMesh Renderer 欄にあるMaterials の左の三角をクリックして開いたら、Element 0 の右の〇をクリックして、ウィンドウからCheckerSquare マテリアルを選択して割り当てます
Add Component をクリックします
Physics からRigidbody を選択してアタッチします
後程、このオブジェクトにエージェントサブクラスをアタッチします。
アカデミー(Academy)を持たせるための空のゲームオブジェクトを作る
Hierarchy ウィンドウのCreate をクリックして、Create Empty を選択します
作成したGameObjectの名前をAcademy
にします
以上でシーンが完成です。
Created Hierarchy
Main Camera の座標や角度を調整して、Game ウィンドウで見やすくなるようにしてください。
Game Window Sample
アカデミーの実装
アカデミーオブジェクトは、シーン内の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 ウィンドウで変更する項目はありません。
Default MLAgents
ブレイン(Brain)を追加する
ブレインアセットは、行動を決める処理を担当します。エージェントは自らが観測した情報をブレインに送ります。ブレインは送られてきた観測情報を元に行動を決定してエージェントに伝えます。エージェントは、ブレインから受け取ったデータに従って行動します。作成するブレインアセットの種類によって、そのブレインの行動の決め方を選択することができます(Learning =AI学習, Heuristic =アルゴリズム で実装, Player =人間が操作)。
ブレインアセットを作成します(0.5.0からこの部分が完全に変わりました! )
Project ウィンドウのCreate ボタンをクリックして、ML-Agents から、作成したいBrain の種類のアセットを選択します。ここでは、Learning Brain とPlayer Brain を作成します
Create Asset
Create Brains
作成したら、それぞれの名前をRollerBallBrain
と、RollerBallPlayer
にします
作成した2つのBrain
設定は実際に動かす時に行うので、一先ずこのままで先に進めます。
エージェントの実装
エージェントを制御するスクリプト を作成します。
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
クラス内に、以下のメソッドを追加します。
public override void CollectObservations()
{
AddVectorObs(Target.position);
AddVectorObs(this .transform.position);
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
クラス内に加えてください。
public float speed = 10 ;
public override void AgentAction(float [] vectorAction, string textAction)
{
Vector3 controlSignal = Vector3.zero;
controlSignal.x = vectorAction[0 ];
controlSignal.z = vectorAction[1 ];
rBody.AddForce(controlSignal * speed);
float distanceToTarget = Vector3.Distance(
this .transform.position,
Target.position);
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 ボタンをクリックします
1つ目のBrain欄を追加
もう一つ設定したいので、Add New ボタンをクリックして増やします
Add Newで2つ目のBrain欄を追加
Project ウィンドウからRollerBallBrain をドラッグして、Inspector ウィンドウのBrains 欄にドロップします。RollerBallPlayer も同様に2つ目のBrains 欄にドラッグ&ドロップします
Brainアセットを設定
Hierarchy ウィンドウからRollerAgent オブジェクトをクリックして選択します
Project ウィンドウからRollerBallPlayer をドラッグして、Inspecor ウィンドウのBrain 欄にドロップします
Inspector ウィンドウのDecision Frequency を10
にします(ブレインは10ステップごとに意思決定をして、行動は毎フレーム実行します)
Hierarcy ウィンドウからTarget オブジェクトをドラッグして、Inspector ビューのTarget 欄にドロップします
RollerAgentの設定
最後に、Brain アセットの設定をします。
Project ウィンドウからRollerBallBrain アセットをクリックして選択したら、Inspector ウィンドウで以下を設定します。
Vector Observation のSpace Size = 8
ブレインに送る観測データベクトルの次元数(要素数 )
Vector Action のSpace Type = Continuous
行動結果を表すベクトルを、整数(Discrete=不連続)で返すか、小数(Continuous=連続)で返すか
Vector Action のSpace Size = 2
Project ウィンドウからRollerBallPlayer アセットをクリックして選択して、以上と同じく設定します。これで環境を試すための準備が整いました。
Brainアセットの設定
環境を手動で試す
実際に学習を開始する前に、手動で環境を試すのがおすすめです。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 欄にドロップします
Brainを入れ替え
Hierarchy ウィンドウでAcademy オブジェクトをクリックして選択します
Inspector ウィンドウのBroadcast Hub 欄に設定したRollerBallBrain の右のチェックボックス にチェックを入れます
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
名前を付けて保存を選択して、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を開いてください
以下のようにグラフが確認できます
TensorBoard
Environment 欄のCumulative Reward と、Policy 欄のValue Estimate のグラフで、エージェントが目的をどれぐらい達成できたかを把握できます。今回の例では、エージェントが得られる最大の報酬は1.0
です。エージェントが目的を達成するほど、グラフは1.0
に近づきます。
Note: TensorBoardを利用する場合、mlagents-learn
コマンドで学習を実行するたびに、run-id の部分を増やすなどして変更した方がよいかも知れません。同じrun-id で学習させると、過去の学習結果のグラフも重ねて表示されるので、傾向の把握が難しくなる可能性があります。
同じrun-idで学習させた時のグラフ
シーンのまとめ
Unity環境で、ML-Agentsを利用する時にシーンをどのように構成するかをまとめます。
Unity ML-Agentを利用する場合、一つのアカデミー と、一つ以上のエージェント ゲームオブジェクトが必要です。また、利用したい種類のブレイン アセットを作成して、エージェント とアカデミー に設定する必要があります。
約束事です。
一つのシーンには、アカデミー ゲームオブジェクトを一つだけ配置します
学習に利用できるブレイン は、アカデミー のBroardcast Hub リストに追加したものだけです
参照したドキュメントは以上です。以下はこのブログでの追記です。
学習したモデルを試す
学習が完了したモデルを使って、実際にRollerAgent を動かしてみます。再生するには、TensorflowSharp プラグイン をプロジェクトにインポートする必要があります。0.5.0の時と同じプラグイン が利用できるので、ダウンロード済みのTFSharpPlugin.unitypackage
があればそれを利用できます。
TFSharpパッケージのダウンロード
ダウンロードしたTFSharpPlugin.unitypackage
をドラッグして、Project ウィンドウにドロップして、インポートします
Edit メニューから、Project Settings > Player を開きます
Other Settings のScripting Define Symbols に、ENABLE_TENSORFLOW
と入力します
Allow 'unsafe' Code 欄にチェックを入れます
以上、ビルドしたい全てのタブでおこないます。
Tensorflowを有効にする
学習させたモデルデータをブレインに設定します。
エクスプローラ ーなどで、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()
メソッドを以下のように書き換えて、学習しなおすと効果が分かります。
public override void CollectObservations()
{
AddVectorObs(Target.position);
AddVectorObs(this .transform.position);
AddVectorObs(rBody.velocity);
}
以下、学習結果です。青がサンプルのまま。オレンジがRollerAgent の速度をベクトルで与えた時のものです。
観測データをベクトルにするかどうかの違い
速度をベクトルで与えたところ、1万ステップの辺りでMean Reward が1.000
になることもありました。ベクトルデータはベクトルのまま 渡した方がよさそうです。
まとめ
Unityの新規プロジェクトに学習用の環境を構築して、Python と連携した強化学習 の実行、そして学習結果のモデルデータを利用してエージェントを動かすことができました。
0.5.0との目立った違いとしては以下が挙げられます。
ブレインがアセットになって、設定が楽になった
学習の切り替えを、AcademyのControlチェックでできるのも楽
報酬を設定するメソッドがSetReward
に変更になった
あとはおおよそそのままいけました。慣れれば導入はかなり簡単だと思います。楽しいAIライフを!
参考URL