LoginSignup
0

More than 1 year has passed since last update.

【Unity】2DでML-Agentsのチュートリアルをやってみた話

Last updated at Posted at 2022-12-22

0.はじめに

この記事はLife is Tech ! Kansai Advent Calendar の記事です。

ML-Agentsについて色々調べていくと2Dを使った記事が全然なくて困った過去がありました。
なので今回は2DでRay Perception Sensor 2Dを用いて、ML-Agentsの公式チュートリアル的なものを作ってみました!
2Dを久しぶりに触る人やML-Agentsを触ったばっかりの人に見ていただけると幸いです。

以下完成動画です

1.使用環境

  • Unity 2021.3.9f1
  • ML-Agent Release 20

2.学習環境の作成

UnityHubを開き新規2Dプロジェクトから「2DMLRaycast」という名前のプロジェクトを作成します。
スクリーンショット 2022-12-21 2.34.28.png

2-1 必要なPacakageのインストール

次に作成したプロジェクトにML-Agentsを追加していきましょう!
まず、WindowからPacakage Managerを開きます。次に+ボタンからadd package from diskを選択します。
そしてGithubからインストールしてきたml-Agentのフォルダの「com.unity.ml-agents/package.json」を選択してインポートをします。スクリーンショット 2022-12-21 2.52.27.png

2-2 Stageの作成

つづいて、Hierarchy ウィンドウから GameObjectを作成していきましょう。
(作成の方法はHierarchy ウィンドウ下の+ボタンをクリックして下図のように選択してください)
スクリーンショット 2022-12-21 3.03.53.png

今回必要な機能はStageとAgentTargetの3つなので順番に作っていきます。

  • 1.Stage
    2D Object > Sprites > Square を作成します。今回はStageという名前にしました。
    Position(0,0,0) , Rotation(0,0,0) , Scale(20,10,1)にしましょう。
  • 2.Agent
    2D Object > Sprites > Circle を作成します。今回はPlayerという名前にしました。
    Position(0,0,0) , Rotation(0,0,0) , Scale(1,1,1)にしましょう。
    そしてAdd ComponentでCircle Collider 2DRigidbody 2Dを追加しておきます。
  • 3.Target
    2D Object > Sprites > Square を作成します。今回はTargetという名前にしました。
    Position(2,2,0) , Rotation(0,0,0) , Scale(1,1,1)にしましょう。
    そしてAdd ComponentでBox Collider 2Dを追加しておきます。

更に後々使うので、TargetのタグをTargetに設定します。
スクリーンショット 2022-12-23 0.23.17.png

また、この際にPlayerTargetのSprite RendererにおけるAdditional SettingsのOrder inLayer を 1に設定しておきましょう

スクリーンショット 2022-12-21 3.22.41.png

すべての設置が終了したらこんな感じになります。(なお視認性をあげるために任意の色の設定とPlayerに簡易的な目をつけています)

スクリーンショット 2022-12-21 3.25.53.png

2-3 Agentに必要な設定

次にAgentであるPlayerに機械学習ができるように設定をしていきましょう !
Playerを選択したあとに Add Component を選択しBehavior Parametersを追加して以下のように設定します。

スクリーンショット 2022-12-21 3.36.53.png

「Behavior Parameters」 は Agentに必ず追加する必要があります

  • Behavior Name:訓練設定ファイルの名前で使用します
  • Vector Observation
    • Space Size : Vector Observationの大きさ
  • Continuous
    • Space Size : 行動の大きさ

また、Decision RequesterもPlayerに追加し、Decision Period を 10 に設定します。

2-4 Ray Perception Sensor 2D の設定

次にPlayerにRay Perception Sensor 2D を追加し、以下の設定をします。
これはPlayerからRayを飛ばし、ヒットした情報を観測データとして自動でエージェントに送る便利なコンポーネントです。
スクリーンショット 2022-12-22 22.42.19.png

上から順番に軽く説明していきます。

  • Detectable Tags:観測対象になるタグを選択します
  • Rays Per Direction: 左右に飛ばすRayの数を設定します。今回の場合値が「3」なので正面に1本、左右にそれぞれ3本の計7本Rayが飛ぶことになります。
  • Max Ray Degrees: 一番外側のRayから正面のRayまでの角度
  • Ray Length : Rayの長さ

このままだと、Player自体にRayが干渉してしまうのでPlayerのLayerを2: Ignore Raycastに選択して干渉しないようにしましょう!
スクリーンショット 2022-12-23 0.41.08.png

Playerのオブジェクトを選択肢して、以下のようにRayが飛んでいるのを確認出来たら準備OKです!
スクリーンショット 2022-12-22 22.42.03.png

2-5 Playerのスクリプトの作成

それではPlayerにアタッチするスクリプトを書いていきましょう!

C# PlayerAgent.cs
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Actuators;

public class PlayerAgent : Agent
{
    Rigidbody2D rBody;
    public Transform Target;

    void Start()
    {
        rBody = this.gameObject.GetComponent<Rigidbody2D>();
    }

    //初期化
    public override void OnEpisodeBegin()
    {
        //プレイヤーの初期化
        this.rBody.angularVelocity = 0;
        this.rBody.gravityScale = 0;
        this.rBody.velocity = Vector3.zero;
        this.transform.localPosition = new Vector3(0, 0.5f, 0);

        // ターゲットを生成
        Target.localPosition = new Vector3(Random.value * 10 - 2, Random.value * 5 - 2, 0);

    }

    //環境情報の収集
    public override void CollectObservations(VectorSensor sensor)
    {
        //自身の座標
        sensor.AddObservation(this.transform.localPosition);

        // 加えた力
        sensor.AddObservation(rBody.velocity.x);
        sensor.AddObservation(rBody.velocity.y);
    }

    private float moveSpeed = 5;
    private float rotateSpeed = 10.0f;

    //行った行動による報酬の決定
    public override void OnActionReceived(ActionBuffers actionBuffers)
    {
        // Actions, size = 2
        Vector2 controlSignal = Vector2.zero;
        controlSignal.x = actionBuffers.ContinuousActions[0];
        controlSignal.y = actionBuffers.ContinuousActions[1];

        //回転させる角度
        float angle = controlSignal.x * rotateSpeed;
        transform.Rotate(new Vector3(0, 0, -angle));

        float angleDir = (transform.eulerAngles.z + 90) * Mathf.Deg2Rad;
        Vector3 dir = new Vector3(Mathf.Cos(angleDir), Mathf.Sin(angleDir), 0.0f);
        rBody.velocity = dir.normalized * moveSpeed * controlSignal.y;


        // 報酬
        float distanceToTarget = Vector3.Distance(this.transform.localPosition, Target.localPosition);

        if (distanceToTarget < 1.3f)
        {
            SetReward(1.0f);
            EndEpisode();
        }
        else if (Mathf.Abs(this.transform.localPosition.x) > 9.5f || Mathf.Abs(this.transform.localPosition.y) > 4.5f)
        {
            EndEpisode();
        }
    }

    public override void Heuristic(in ActionBuffers actionsOut)
    {
        var continuousActionsOut = actionsOut.ContinuousActions;
        continuousActionsOut[0] = Input.GetAxis("Horizontal");
        continuousActionsOut[1] = Input.GetAxis("Vertical");
    }
}

このコードをPlayerにアタッチしたあとに、Target の GameObject をドラッグ & ドロップで PlayerAgentに設定します。
スクリーンショット 2022-12-21 3.50.47.png

2-6 Heuristicでの動作テスト

ここまで出来たのなら一度Heuristicモードで操作できるか確認してみましょう!
HeuristicモードはBehavior Parametersの「Behavior Type」をHeuristic Onlyにして再生をすると操作することが出来ます。
スクリーンショット 2022-12-23 0.46.27.png

3 訓練ファイルの作成

続いて訓練ファイルを作成していきましょう!
予めGitHubからクローンしたml-agentフォルダに移動し、config/ppo下に2DBall.yamlファイルを作成し、以下を書いていきます。

yaml 2DBall.yaml
behaviors:
  2DBall: # Behavior Name
    trainer_type: ppo  # トレーナー種別
    # 学習アルゴリズムの設定
    hyperparameters:
      batch_size: 128
      buffer_size: 256
      learning_rate: 3.0e-4
      beta: 5.0e-4
      epsilon: 0.2
      lambd: 0.99 
      num_epoch: 3
      learning_rate_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

4 強化学習の実施

すべて完了したらPythonのml-agentフォルダにて以下のコマンドを実行します。
このときの「run-id」は学習する際のIDで出力先のフォルダ名になります。
仮にIDを上書きで実行したい場合は末尾に --forceをつけてあげてください

$ mlagents-learn config/ppo/2DBall.yaml --run-id=2DBall

上記のコマンドを実行したあとにUnity EditorのPlayボタンを押すと学習が始まります。

ある程度学習させたあとにUnity Editorの再生を停止するとml-agentフォルダの「results/2DBall」に「2DBall.onnx」というモデルが生成されています。

そのモデルをUnityのAssets下に持ってきたあとに、Behavior Parameters のModelにドラッグ&ドロップしてモデルの設定をします。
その後シーンを実行すると学習モデルを実行することが出来ます!
スクリーンショット 2022-12-23 1.27.28.png

5 最後に

いかがでしたでしょうか。かなり端折った説明にはなっていますが、2DでML-Agentsを使用する際の参考になれば幸いです。

また余談にはなりますが、私自身この分野について勉強し始めたばかりなのとQiitaで執筆するのが初めてなので、間違いや不明点があればお気軽に知らせてください。

参考記事

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0