UnityのML-Agents(Machine Learning Agents)は、ゲームやシミュレーション環境でAIエージェントをトレーニングするためのツールです。このツールは、強化学習(Reinforcement Learning, RL)とニューラルネットワーク(Neural Networks, NN)を組み合わせてエージェントの行動を学習させます。
強化学習は、エージェントが環境との相互作用を通じて報酬を最大化する行動を学ぶための機械学習の一分野です。主な要素は以下の通りです:
強化学習における方策は、ニューラルネットワークによってモデル化されることが多いです。ニューラルネットワークは、状態を入力として受け取り、行動を出力として返す関数として機能します。このネットワークは、トレーニングを通じて最適な方策を学習します。
UnityのML-Agentsでは、強化学習のプロセスは以下のように進行します:
OnEpisodeBegin()
メソッドなど)。CollectObservations()
メソッド)。これには位置、速度、センサー情報などが含まれます。OnActionReceived()
メソッド)。エージェントの学習は報酬信号を基に進行します。報酬が大きくなる行動を繰り返し、逆に報酬が少ない行動を避けるようにニューラルネットワークが調整されます。学習の過程でエージェントは、環境の状態をより良く観察し、効率的な行動を選択する能力を向上させます。
Unity ML-Agentsでは、一般的な強化学習アルゴリズムがサポートされています。最も一般的なのは、以下のアルゴリズムです:
Unity ML-Agentsは、強化学習とニューラルネットワークを組み合わせることで、エージェントが複雑な環境での行動を学習することを可能にします。エージェントは、観測された状態を基に行動を選択し、環境から得られる報酬を最大化するように学習します。これにより、ゲームやシミュレーション環境でのAI開発が大幅に効率化されます。
エージェントスクリプトは、ML-Agentsの中心的なコンポーネントであり、このスクリプトで、エージェントが観測、行動、報酬を受け取り、どのように環境と相互作用するかを定義します。
Agentクラスを継承させたスクリプトを作成します。
以下は、簡単なエージェントスクリプトの例です。
このスクリプトでは、エージェントが特定の目標に到達したときに報酬を与える例です。
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Actuators;
public class MyAgent : Agent
{
public Transform targetTransform;
public float moveSpeed = 1f;
// エピソードの開始時に呼び出されます
public override void OnEpisodeBegin()
{
// エージェントとターゲットの位置をリセット
transform.localPosition = new Vector3(Random.Range(-4f, 4f), 0, Random.Range(-4f, 4f));
targetTransform.localPosition = new Vector3(Random.Range(-4f, 4f), 0, Random.Range(-4f, 4f));
}
// 観測を収集するために呼び出されます
public override void CollectObservations(VectorSensor sensor)
{
// エージェントとターゲットの相対位置を観測
sensor.AddObservation(targetTransform.localPosition - transform.localPosition);
}
// 行動を実行するために呼び出されます
public override void OnActionReceived(ActionBuffers actions)
{
// 行動を取得
float moveX = actions.ContinuousActions[0];
float moveZ = actions.ContinuousActions[1];
// エージェントを移動
transform.localPosition += new Vector3(moveX, 0, moveZ) * moveSpeed * Time.deltaTime;
// ターゲットに到達したら報酬を与える
float distanceToTarget = Vector3.Distance(transform.localPosition, targetTransform.localPosition);
if (distanceToTarget < 1.5f)
{
SetReward(1.0f);
EndEpisode();
}
// 毎ステップ小さな負の報酬を与えることで、迅速な行動を促す
AddReward(-0.001f);
}
// ヒューマンデバッグ用のヒント
public override void Heuristic(in ActionBuffers actionsOut)
{
var continuousActions = actionsOut.ContinuousActions;
continuousActions[0] = Input.GetAxis("Horizontal");
continuousActions[1] = Input.GetAxis("Vertical");
}
}
OnEpisodeBegin
)(ちなみにStartの方が先に呼ばれる)CollectObservations
メソッドが呼び出されます。ここで収集される観測データは、エージェントの次の行動決定に使われます。OnActionReceived
メソッドが呼び出され、エージェントが決定した行動が環境に適用されます。この段階で、エージェントの行動によって環境が変化し、エージェントの位置や状態が更新されます。EndEpisode
メソッドが呼び出されます。この時点で、エピソードの成績や報酬が計算され、エージェントと環境の状態がリセットされます。OnEpisodeBegin
が呼び出され、エージェントとターゲットの位置がリセットされ、新しいエピソードの準備が整います。これにより、環境が初期状態に戻り、新しい学習サイクルが始まります。環境の更新がされるタイミング:
環境の更新はエージェントの行動が適用される際や、エピソードが終了する際に行われます。
エージェントスクリプトは、ML-Agentsの中心的なコンポーネントであり、このスクリプトで、エージェントが観測、行動、報酬を受け取り、どのように環境と相互作用するかを定義します。
Agentクラスを継承するスクリプトを作成します。
OnEpisodeBegin
メソッド:
public override void OnEpisodeBegin()
{
transform.localPosition = new Vector3(Random.Range(-4f, 4f), 0, Random.Range(-4f, 4f));
targetTransform.localPosition = new Vector3(Random.Range(-4f, 4f), 0, Random.Range(-4f, 4f));
}
CollectObservations
メソッド:
VectorSensor
オブジェクトに追加します。public override void CollectObservations(VectorSensor sensor)
{
sensor.AddObservation(targetTransform.localPosition - transform.localPosition);
}
OnActionReceived
メソッド:
public override void OnActionReceived(ActionBuffers actions)
{
float moveX = actions.ContinuousActions[0];
float moveZ = actions.ContinuousActions[1];
transform.localPosition += new Vector3(moveX, 0, moveZ) * moveSpeed * Time.deltaTime;
float distanceToTarget = Vector3.Distance(transform.localPosition, targetTransform.localPosition);
if (distanceToTarget < 1.5f)
{
SetReward(1.0f);
EndEpisode();
}
AddReward(-0.001f);
}
ContinuousActions
から移動方向を取得し、エージェントの位置を更新します。ターゲットに近づくと高い報酬を与え、エピソードを終了します。毎ステップで小さな負の報酬を与えます。Heuristic
メソッド:
public override void Heuristic(in ActionBuffers actionsOut)
{
var continuousActions = actionsOut.ContinuousActions;
continuousActions[0] = Input.GetAxis("Horizontal");
continuousActions[1] = Input.GetAxis("Vertical");
}
CollectObservations
と OnActionReceived
の呼び出しタイミングCollectObservations
:
OnActionReceived
:
public override void OnActionReceived(ActionBuffers actions)
{
float moveX = actions.ContinuousActions[0];
float moveZ = actions.ContinuousActions[1];
}
ContinuousActions
配列から移動方向を取得し、エージェントの動きを制御します。今回は使用していないが
public override void OnActionReceived(ActionBuffers actions)
{
int action = actions.DiscreteActions[0];
switch (action)
{
case 0:
// アクション0: 移動する
MoveForward();
break;
case 1:
// アクション1: ジャンプする
Jump();
break;
case 2:
// アクション2: 止まる
Stop();
break;
}
}
DiscreteActions
配列から選択されたアクションのインデックスを取得し、エージェントの動作を制御します。DiscreteActions
は離散的な値(整数)を提供し、それぞれの整数値が特定のアクションにマッピングされます。この方法で、エージェントはアクションの選択肢から1つを選び、それに応じて振る舞いを変えることができます。メリット: 離散的なアクションは簡単に理解でき、特定のアクションの選択肢を管理するのが容易です。適用しやすい場合も多いですが、アクションの選択肢が多すぎると、学習が複雑になることがあります。
Behavior Parameters
コンポーネントで、Space Type
をDiscrete
に設定し、アクションの数を指定します。OnActionReceived
内で適切な処理を行います。これにより、エージェントは定義されたアクションセットから選択し、環境に応じた行動を取ることができます。
ContinuousActionsとDiscreteActionsについて
AddReward
と SetReward
の使い分けAddReward
:
AddReward(-0.001f);
SetReward
:
SetReward(1.0f);
ML-Agentsでの「ステップ数」の設定は、エージェントが環境内で行動を決定するためのサイクル回数に関わります。
具体的には、以下のような設定が関係します。
trainer_config.yaml
)またはトレーニングのスクリプトで設定します。Academy
スクリプトで設定します。trainer_config.yaml
)またはトレーニングのスクリプトで設定します。OnEpisodeBegin
メソッドでエピソード開始時にリセットします。これらの設定を適切に調整することで、エージェントの学習プロセスを最適化し、効果的なトレーニングを実現できます。