はじめに
この記事は、
ml-agents/Learning-Environment-Create-New.md at master · Unity-Technologies/ml-agents · GitHub
に従って実際に強化学習のチュートリアルをやってみた、というだけのものです。
実行環境
- macOS Mojave 10.14.5
- Unity 2019.1.4f1
- ML-Agents Beta 0.8.1
ML-Agentsの導入
以下のリンク等を参考にしてML-Agentsを導入してください。
プロジェクトの準備
- Unityで
RollerBall
という名前のプロジェクトを作成します。 - ProjectSetting -> Player -> Configuration でScripting Runtime Versionが .NET 4.x Equivalentになっていることを確認します。
-
ml-agents-master
フォルダをコピーしてRollerBall/Assets/
にペーストします。
環境の作成
Floorの作成
- Planeの3D Objectを作成し、
Floor
という名前を付けます。 -
Floor
のTransformをPosition = (0, 0, 0)
,Rotation = (0, 0, 0)
,Scale = (1, 1, 1)
にします。 -
Floor
のMesh RendererでMaterialをLightGridFloorSquare
に変更します。
Targetの作成
- Cubeの3D Objectを作成し、
Target
という名前を付けます。 -
Target
のTransformをPosition = (3, 0.5, 3)
,Rotation = (0, 0, 0)
,Scale = (1, 1, 1)
にします。 -
Floor
と同様にTarget
のMaterialをBlock
に変更します。
Agentの作成
- Sphereの3D Objectを作成し、
RollerAgent
という名前を付けます。 -
RollerAgent
のTransformをPosition = (0, 0.5, 0)
,Rotation = (0, 0, 0)
,Scale = (1, 1, 1)
にします。 - これまでと同様に
RollerAgent
のMaterialをCheckerSquare
に変更します。 -
Rigidbody
をRollerAgent
にAdd Componentします。
Academyの作成
Create Emptyで空のGameObjectを作成し、Academy
という名前を付けます。
Academyの実装
- Create -> C# Scriptで
RollerAcademy.cs
を作成します。 -
RollerAcademy.cs
をAcademy
にAdd Componentします。 -
RollerAcademy.cs
を次のように編集します。
using MLAgents;
public class RollerAcademy : Academy {
}
Brainの追加
- Assets -> Create -> ML-Agents で
Learning Brain
を作成し、RollerBallBrain
と名前を付けます。 - 同様にAssets -> Create -> ML-Agentsで
Player Brain
を作成し、RollerBallPlayer
と名前を付けます。
Agentの実装
- Create -> C# Scriptで
RollerAgent.cs
を作成し、RollerAgent
にAdd Componentします。 -
RollerAgent.cs
を次のように編集します。
using MLAgents;
public class RollerAgent : Agent
{
}
今回の簡単な状況ではAcademy
は使用せずに、Agent
にのみ処理を担当させます。
Agentの実装(続き)
RollerAgent.cs
を次のように編集します。
using UnityEngine;
using MLAgents;
public class RollerAgent : Agent
{
Rigidbody rBody;
void Start () {
rBody = GetComponent<Rigidbody>();
}
public Transform Target;
public override void AgentReset()
{
if (this.transform.position.y < 0)
{
// If the Agent fell, zero its momentum
this.rBody.angularVelocity = Vector3.zero;
this.rBody.velocity = Vector3.zero;
this.transform.position = new Vector3( 0, 0.5f, 0);
}
// Move the target to a new spot
Target.position = new Vector3(Random.value * 8 - 4,
0.5f,
Random.value * 8 - 4);
}
}
インスペクタ のTargetにTarget
オブジェクトを代入します。
ここでは次のことを行なうための処理を書いています。
-
RollerAgent
がTarget
に到着した時、Done()
を呼び出し、そのターン(エピソード)を終了させる。 -
RollerAgent
がTarget
に到着した時、Target
をランダムな場所に移動させる。 -
RollerAgent
がFloor
から落ちた時、そのRollerAgent
をFloor
の上に戻す。
観測
今回、RollerAgent
が集めてRollerBallBrain
に送る情報は次のものになります。
-
Target
の位置
AddVectorObs(Target.position);
-
RollerAgent
の位置
AddVectorObs(this.transform.position);
-
RollerAgent
の速度(RollerAgent
がTarget
を通り越したり、Floor
から落ちないようにするために必要です)
AddVectorObs(rBody.velocity.x);
AddVectorObs(rBody.velocity.z);
よって情報を集めてRollerBallBrain
へ送る処理を担当する、CollectObservations()
メソッドは次のようになります。
public override void CollectObservations()
{
// Target and Agent positions
AddVectorObs(Target.position);
AddVectorObs(this.transform.position);
// Agent velocity
AddVectorObs(rBody.velocity.x);
AddVectorObs(rBody.velocity.z);
}
このCollectObservation()
メソッドをRollerAgent.cs
に追加します。
using UnityEngine;
using MLAgents;
public class RollerAgent : Agent
{
Rigidbody rBody;
void Start()
{
rBody = GetComponent<Rigidbody>();
}
public Transform Target;
public override void AgentReset()
{
if (this.transform.position.y < 0)
{
// If the Agent fell, zero its momentum
this.rBody.angularVelocity = Vector3.zero;
this.rBody.velocity = Vector3.zero;
this.transform.position = new Vector3(0, 0.5f, 0);
}
// Move the target to a new spot
Target.position = new Vector3(Random.value * 8 - 4,
0.5f,
Random.value * 8 - 4);
}
public override void CollectObservations()
{
// Target and Agent positions
AddVectorObs(Target.position);
AddVectorObs(this.transform.position);
// Agent velocity
AddVectorObs(rBody.velocity.x);
AddVectorObs(rBody.velocity.z);
}
}
報酬
RollerAgent
がTarget
に到着した時、RollerAgent
にSetReward()
メソッドを使って1.0の報酬を与え、Done()
メソッドを実行して終了します。
float distanceToTarget = Vector3.Distance(this.transform.position,
Target.position);
// Reached target
if (distanceToTarget < 1.42f)
{
SetReward(1.0f);
Done();
}
Floor
から落ちた場合もDone()
メソッドを実行して終了します。
// Fell off platform
if (this.transform.position.y < 0)
{
Done();
}
AgentAction()メソッドの作成
以上より、AgentAction()
メソッドは次のようになります。
public float speed = 10;
public override void AgentAction(float[] vectorAction, string textAction)
{
// Actions, size = 2
Vector3 controlSignal = Vector3.zero;
controlSignal.x = vectorAction[0];
controlSignal.z = vectorAction[1];
rBody.AddForce(controlSignal * speed);
// Rewards
float distanceToTarget = Vector3.Distance(this.transform.position,
Target.position);
// Reached target
if (distanceToTarget < 1.42f)
{
SetReward(1.0f);
Done();
}
// Fell off platform
if (this.transform.position.y < 0)
{
Done();
}
}
したがって、最終的にRollerAgent.cs
は次のようになります。
using UnityEngine;
using MLAgents;
public class RollerAgent : Agent
{
Rigidbody rBody;
public float speed = 10;
void Start()
{
rBody = GetComponent<Rigidbody>();
}
public Transform Target;
public override void AgentReset()
{
if (this.transform.position.y < 0)
{
// If the Agent fell, zero its momentum
this.rBody.angularVelocity = Vector3.zero;
this.rBody.velocity = Vector3.zero;
this.transform.position = new Vector3(0, 0.5f, 0);
}
// Move the target to a new spot
Target.position = new Vector3(Random.value * 8 - 4,
0.5f,
Random.value * 8 - 4);
}
public override void CollectObservations()
{
// Target and Agent positions
AddVectorObs(Target.position);
AddVectorObs(this.transform.position);
// Agent velocity
AddVectorObs(rBody.velocity.x);
AddVectorObs(rBody.velocity.z);
}
public override void AgentAction(float[] vectorAction, string textAction)
{
// Actions, size = 2
Vector3 controlSignal = Vector3.zero;
controlSignal.x = vectorAction[0];
controlSignal.z = vectorAction[1];
rBody.AddForce(controlSignal * speed);
// Rewards
float distanceToTarget = Vector3.Distance(this.transform.position,
Target.position);
// Reached target
if (distanceToTarget < 1.42f)
{
SetReward(1.0f);
Done();
}
// Fell off platform
if (this.transform.position.y < 0)
{
Done();
}
}
}
Unityエディタ側の設定
-
Academy
のインスペクターのBroadcast HubにRollerBallBrain
とRollerBallPlayer
を追加します。 -
RollerBallPlayer
をRollerAgent
のBrainに代入します。 - Decision Intervalを1から10に変更します。
-
Target
GameObjectをTargetに代入します。
RollerBallPlayer
とRollerBallBrain
のSpace Size(Vector Observation)、Space Type、Space Size(Vector Action)をそれぞれ次のように変更します。
テスト
RollerBallPlayer
のKey Continuous Player Actionsのサイズを4にして、Element0からElement3までを次のように設定します。
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()
メソッドに渡されるaction配列のindexに対応しています。 Keyを押すとaction[index]
にValueが代入されます。
これでPlayするとWASDキーでRollerAgent
を私達の手で操作できます。
RollerAgent
がTarget
に近づくとTarget
の位置がランダムな位置に移ることも、RollerAgent
がFloor
から落ちると中心の位置に戻ることも確認できます。
学習
RollerAgent
のBrainをRollerBallPlayer
からRollerBallBrain
に切り替えます。
Academy
にアタッチされているRollerAcademy
で、Controlにチェックをします。
ターミナルでRollerBall/Assets/
に移動して、
$ mlagents-learn ml-agents-master/config/trainer_config.yaml --run-id=RollerBall-1 --train
を実行します。
次のように表示されたらUnityエディタでPlayボタンを押します。
INFO:mlagents.envs:Start training by pressing the Play button in the Unity Editor.
次のように表示されたら無事に学習が開始したことになります。(今回は50000steps学習させます)
INFO:mlagents.envs:
'Academy' started successfully!
Unity Academy name: Academy
Number of Brains: 2
Number of Training Brains : 1
Reset Parameters :
Unity brain name: RollerBallBrain
Number of Visual Observations (per agent): 0
Vector Observation space size (per agent): 8
Number of stacked Vector Observation: 1
Vector Action space type: continuous
Vector Action space size (per agent): [2]
Vector Action descriptions: ,
Unity brain name: RollerBallPlayer
Number of Visual Observations (per agent): 0
Vector Observation space size (per agent): 8
Number of stacked Vector Observation: 1
Vector Action space type: continuous
Vector Action space size (per agent): [2]
Vector Action descriptions: ,
2019-05-29 12:13:39.143382: I tensorflow/core/platform/cpu_feature_guard.cc:140] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
INFO:mlagents.envs:Hyperparameters for the PPO Trainer of brain RollerBallBrain:
batch_size: 1024
beta: 0.005
buffer_size: 10240
epsilon: 0.2
gamma: 0.99
hidden_units: 128
lambd: 0.95
learning_rate: 0.0003
max_steps: 5.0e4
normalize: False
num_epoch: 3
num_layers: 2
time_horizon: 64
sequence_length: 64
summary_freq: 1000
use_recurrent: False
summary_path: ./summaries/RollerBall-1-0_RollerBallBrain
memory_size: 256
use_curiosity: False
curiosity_strength: 0.01
curiosity_enc_size: 128
model_path: ./models/RollerBall-1-0/RollerBallBrain
INFO:mlagents.trainers: RollerBall-1-0: RollerBallBrain: Step: 1000. Time Elapsed: 11.076 s Mean Reward: 0.178. Std of Reward: 0.382. Training.
学習が終わると、推論モデルであるRollerBallBrain.nn
ファイルがAssets/models/RollerBall-1-0/
に生成されるので、これをRollerBallBrain
のModelにセットします。
また、RollerAcademy
のControlのチェックを外します。
これでUnityのエディタでPlayボタンを押すと、RollerAgent
が自発的に動きます。
あまり賢いとは言えませんが、Target
に向かっていこうとする意思は感じられます。
ターミナルで
$ tensorboard --logdir=summaries
を実行して、http://localhost:6006 をブラウザで開くと、今回の学習状況を詳細に調べることができます。