[Unity 3D] 新しいプロジェクトでML-Agetsを導入して学習させる方法。

(2022/10/22)
新しいプロジェクトでML-Agetsを導入して学習させる方法。
実行環境
  • macOS:Monterey(バージョン12.6)
  • Unityのバージョン:2020.3.25f1
  • ML-Agentsのバージョン:Release 19
  • Pythonのバージョン:3.7.0


  • この記事では、GitHubの を参考にして新しく作ったUnityのプロジェクトでML-Agentsを使う方法を書いています。

    新しいプロジェクトにML-Agentsを導入

    まずターミナルを起動し、ML-Agents Toolkitを任意の場所にクローンします。

    $ git clone --branch release_19 https://github.com/Unity-Technologies/ml-agents.git

    次にUnityの新しい3Dプロジェクトを作成します。

    プロジェクトが開いたら、Window→Package Managerをクリックし「+」からAdd package from disk...を選択します。

    新しいプロジェクトでML-Agetsを導入して学習させる方法。

    クローンした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)になっていることを確認します。

    新しいプロジェクトでML-Agetsを導入して学習させる方法。

    ②キューブを追加
    ・Hierarchyウィンドウで右クリックし、3D Object→Cubeを選択します。
    ・Cubeを選択しInspectorで名前をTargetに変更します。
    ・Transformの値をPosition(3,0.5,3)、Rotation(0,0,0)、Scale(1,1,1)に設定します。

    新しいプロジェクトでML-Agetsを導入して学習させる方法。

    ③スフィアを追加
    ・Hierarchyウィンドウで右クリックし、3D Object→Sphereを選択します。
    ・Sphereを選択しInspectorで名前をRollerAgentに変更します。
    ・Transformの値をPosition(0,0.5,0)、Rotation(0,0,0)、Scale(1,1,1)に設定します。
    ・Add ComponentからRigidbodyを追加します。

    新しいプロジェクトでML-Agetsを導入して学習させる方法。

    ④ゲームオブジェクトをグループ化
    ・Hierarchyウィンドウで右クリックし、Create Emptyを選択します。
    ・GameObjectを選択しInspectorで名前をTrainingAreaに変更します。
    ・Transformの値をPosition(0,0,0)、Rotation(0,0,0)、Scale(1,1,1)に設定します。

    Floor、Target、RollerAgentをTrainingAreaにドラッグします。

    新しいプロジェクトでML-Agetsを導入して学習させる方法。
    RollerAgentにスクリプトを追加する

    ①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をドラッグします。

    新しいプロジェクトでML-Agetsを導入して学習させる方法。

    ③Add ComponentからBehavior Parametersを追加し、
    ・Behavior NameをRollerBallに変更します。
    ・Vector ObservationのSpace Sizeを8に変更します。
    ・ActionsのContinuous Actionsを2に変更します。
    ・Discrete Branchesを0に変更します。
    ・ModelのInference DeviceをCPUに変更します。

    新しいプロジェクトでML-Agetsを導入して学習させる方法。

    ④Add ComponentからDecision Requesterを追加し、Decision Periodを10に変更します

    新しいプロジェクトでML-Agetsを導入して学習させる方法。
    正しく動作するかテスト

    RollerAgentのBehavior ParametersのBehavior TypeをHeuristic Onlyに変更して、Unityエディターを再生したら、RollerAgentが矢印キーで操作できるのでRollerAgentが落下した時、Targetに接近した時の動作を確認します。

    正しく動作していることが確認できたら、Behavior TypeをDefaultに戻しておきます。

    rollerball_config.yamlファイルを作成

    クローンしたml-agentsのファイル→configファイルにrollerball_config.yamlファイルを作成します

    新しいプロジェクトでML-Agetsを導入して学習させる方法。

    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のページで確認することができます。

    RollerAgentを学習させるための準備

    ①ターミナルでPythonのバージョンが3.6.1以降であることを確認します。

    $ python3 -V

    ②サンプルを学習させるために仮想環境を使うのでターミナルを立ち上げて任意の場所にディレクトリを作ってください。今回はSampleという名前のディレクトリを作りました。

    $ mkdir Sample

    ③cdコマンドでSampleに移動した後、今回使う新しい環境を作成します。ここでは、learning-envという名前の仮想環境を作成しました。

    $ python3 -m venv learning-env

    ④仮想環境が作成できたら、作成した仮想環境を有効化します。

    $ source learning-env/bin/activate

    ⑤仮想環境を有効化している状態でpipとsetuptoolsをアップグレードします。

    $ pip3 install --upgrade pip
    $ pip3 install --upgrade setuptools

    ⑥mlagentsPythonパッケージをインストールします。

    $ python -m pip install mlagents==0.28.0

    ⑦importlib-metadataのバージョンを変更します。

    $ pip install importlib-metadata==4.13.0

    仮想環境は$ deactivateで終了することができます。

    $ deactivate
    RollerAgentを学習させる

    仮想環境を有効化している状態でターミナルでcdコマンドを使い、クローンしたml-agentsのファイルに移動します。移動できたら下のコマンドを入力します。
    (--run-id=の「RollerBall」は好きに変えてもらっても大丈夫です。)

    $ mlagents-learn config/rollerball_config.yaml --run-id=RollerBall

    ターミナルにUnityのロゴが表示されたら、Unityエディターで再生をクリックします。

    問題なく動作すれば学習が開始されます。

    学習はターミナルでCtrl+Cを実行することで終了させることができます。

    学習させたモデルを使う

    学習させたモデルはクローンしたml-agentsのresultsの中の保存されます。今回は、resultsにRollerBallというディレクトリが作成されているはずなので、そのディレクトリの中のRollerBall.onnxをUnityのProjectウィンドウのAssetsにドラッグアンドドロップします。

    次に、RollerAgentのBehaviorParametersのModelにRollerBall.onnxをドラッグします。

    新しいプロジェクトでML-Agetsを導入して学習させる方法。

    その状態でUnityエディターを再生すると、学習させたモデルを使うことができます。

    UnityのML-Agentsについて学べる本

     
    他の記事も見る
     
  • プライバシーポリシー