まずターミナルを起動し、ML-Agents Toolkitを任意の場所にクローンします。
次にUnityの新しい3Dプロジェクトを作成します。
プロジェクトが開いたら、Window→Package Managerをクリックし「+」からAdd package from disk...を選択します。
クローンしたml-agents→com.unity.ml-agents→package.jsonを選択します。
①床を追加
・Hierarchyウィンドウで右クリックし、3D Object→Planeを選択します。
・Planeを選択しInspectorで名前をFloorに変更します。
・Transformの値がPosition(0,0,0)、Rotation(0,0,0)、Scale(1,1,1)になっていることを確認します。
②キューブを追加
・Hierarchyウィンドウで右クリックし、3D Object→Cubeを選択します。
・Cubeを選択しInspectorで名前をTargetに変更します。
・Transformの値をPosition(3,0.5,3)、Rotation(0,0,0)、Scale(1,1,1)に設定します。
③スフィアを追加
・Hierarchyウィンドウで右クリックし、3D Object→Sphereを選択します。
・Sphereを選択しInspectorで名前をRollerAgentに変更します。
・Transformの値をPosition(0,0.5,0)、Rotation(0,0,0)、Scale(1,1,1)に設定します。
・Add ComponentからRigidbodyを追加します。
④ゲームオブジェクトをグループ化
・Hierarchyウィンドウで右クリックし、Create Emptyを選択します。
・GameObjectを選択しInspectorで名前をTrainingAreaに変更します。
・Transformの値をPosition(0,0,0)、Rotation(0,0,0)、Scale(1,1,1)に設定します。
Floor、Target、RollerAgentをTrainingAreaにドラッグします。
①RollerAgent→Add Componentで適当な名前のスクリプトを追加します。ここではRollerAgentという名前のスクリプトを作成しました。
作成したスクリプトに下のコードを貼り付けます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//MLAgentsを使えるように名前空間を追加
using Unity.MLAgents;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Actuators;
//MonoBehaviourをAgentに変更
public class RollerAgent : Agent
{
public Transform Target;
Rigidbody rBody;
public float forceMultiplier = 10;
void Start()
{
rBody = GetComponent<Rigidbody>();
}
//エピソードの開始
public override void OnEpisodeBegin()
{
//Agentが落ちた時の処理
if (this.transform.localPosition.y < 0)
{
//Agentの回転を止める
this.rBody.angularVelocity = Vector3.zero;
//Agentの速度を0にする
this.rBody.velocity = Vector3.zero;
//Agentの位置を初期位置に戻す
this.transform.localPosition = new Vector3(0,0.5f,0);
}
//Targetの新しい位置
Target.localPosition = new Vector3(Random.value * 8 - 4,0.5f,Random.value * 8 - 4);
}
//環境の情報を収集
public override void CollectObservations(VectorSensor sensor)
{
//TargetとAgentの位置
sensor.AddObservation(Target.localPosition);
sensor.AddObservation(this.transform.localPosition);
//Agentの速度
sensor.AddObservation(rBody.velocity.x);
sensor.AddObservation(rBody.velocity.z);
}
//Agentの移動と報酬
public override void OnActionReceived(ActionBuffers actionBuffers)
{
//Agentを移動させる
Vector3 controlSignal = Vector3.zero;
controlSignal.x = actionBuffers.ContinuousActions[0];
controlSignal.z = actionBuffers.ContinuousActions[1];
rBody.AddForce(controlSignal * forceMultiplier);
//TargetとAgentの距離を取得
float distanceToTarget = Vector3.Distance(this.transform.localPosition, Target.localPosition);
//TargetとAgentの距離が1.42より小さい場合、1.0の報酬を与えてエピソードを終了する
if (distanceToTarget < 1.42f)
{
SetReward(1.0f);
EndEpisode();
}
//Agentが床から落ちたらエピソードを終了する
else if (this.transform.localPosition.y < 0)
{
EndEpisode();
}
}
//人が操作するときの処理
public override void Heuristic(in ActionBuffers actionsOut)
{
var continuousActionsOut = actionsOut.ContinuousActions;
continuousActionsOut[0] = Input.GetAxis("Horizontal");
continuousActionsOut[1] = Input.GetAxis("Vertical");
}
}
②RollerAgentのTargetにHierarchyのTargetをドラッグします。
③Add ComponentからBehavior Parametersを追加し、
・Behavior NameをRollerBallに変更します。
・Vector ObservationのSpace Sizeを8に変更します。
・ActionsのContinuous Actionsを2に変更します。
・Discrete Branchesを0に変更します。
・ModelのInference DeviceをCPUに変更します。
④Add ComponentからDecision Requesterを追加し、Decision Periodを10に変更します
RollerAgentのBehavior ParametersのBehavior TypeをHeuristic Onlyに変更して、Unityエディターを再生したら、RollerAgentが矢印キーで操作できるのでRollerAgentが落下した時、Targetに接近した時の動作を確認します。
正しく動作していることが確認できたら、Behavior TypeをDefaultに戻しておきます。
クローンしたml-agentsのファイル→configファイルにrollerball_config.yamlファイルを作成します
rollerball_config.yamlファイルに下のコードを貼り付けます。
behaviors:
RollerBall:
trainer_type: ppo
hyperparameters:
batch_size: 10
buffer_size: 100
learning_rate: 3.0e-4
beta: 5.0e-4
epsilon: 0.2
lambd: 0.99
num_epoch: 3
learning_rate_schedule: linear
beta_schedule: constant
epsilon_schedule: linear
network_settings:
normalize: false
hidden_units: 128
num_layers: 2
reward_signals:
extrinsic:
gamma: 0.99
strength: 1.0
max_steps: 500000
time_horizon: 64
summary_freq: 10000
yamlファイルの詳細は、下のGitHubのページで確認することができます。
①ターミナルでPythonのバージョンが3.6.1以降であることを確認します。
②サンプルを学習させるために仮想環境を使うのでターミナルを立ち上げて任意の場所にディレクトリを作ってください。今回はSampleという名前のディレクトリを作りました。
③cdコマンドでSampleに移動した後、今回使う新しい環境を作成します。ここでは、learning-envという名前の仮想環境を作成しました。
④仮想環境が作成できたら、作成した仮想環境を有効化します。
⑤仮想環境を有効化している状態でpipとsetuptoolsをアップグレードします。
⑥mlagentsPythonパッケージをインストールします。
⑦importlib-metadataのバージョンを変更します。
仮想環境は$ deactivateで終了することができます。
仮想環境を有効化している状態でターミナルでcdコマンドを使い、クローンしたml-agentsのファイルに移動します。移動できたら下のコマンドを入力します。
(--run-id=の「RollerBall」は好きに変えてもらっても大丈夫です。)
ターミナルにUnityのロゴが表示されたら、Unityエディターで再生をクリックします。
問題なく動作すれば学習が開始されます。
学習はターミナルでCtrl+Cを実行することで終了させることができます。
学習させたモデルはクローンしたml-agentsのresultsの中の保存されます。今回は、resultsにRollerBallというディレクトリが作成されているはずなので、そのディレクトリの中のRollerBall.onnxをUnityのProjectウィンドウのAssetsにドラッグアンドドロップします。
次に、RollerAgentのBehaviorParametersのModelにRollerBall.onnxをドラッグします。
その状態でUnityエディターを再生すると、学習させたモデルを使うことができます。