ゲーム開発
Unity
UnrealEngine
C++
Blender
ゲーム数学
ゲームAI
グラフィックス
サウンド
アニメーション
GBDK
制作日記
IT関連
ツール開発
フロントエンド関連
サーバサイド関連
WordPress関連
ソフトウェア設計
おすすめ技術書
音楽
DTM
楽器・機材
ピアノ
ラーメン日記
四コマ漫画
その他
おすすめアイテム
おもしろコラム
  • ゲーム開発
    • Unity
    • UnrealEngine
    • C++
    • Blender
    • ゲーム数学
    • ゲームAI
    • グラフィックス
    • サウンド
    • アニメーション
    • GBDK
    • 制作日記
  • IT関連
    • ツール開発
    • フロントエンド関連
    • サーバサイド関連
    • WordPress関連
    • ソフトウェア設計
    • おすすめ技術書
  • 音楽
    • DTM
    • 楽器・機材
    • ピアノ
  • ラーメン日記
    • 四コマ漫画
      • その他
        • おすすめアイテム
        • おもしろコラム
      1. ホーム
      2. 20220710_01

      【Unity】ML-Agentsで簡単な強化学習を試してみる【RollerBall】

      UnityゲームAIML-Agents機械学習
      2022-07-11

      マイケル
      マイケル
      みなさんこんにちは!
      マイケルです!
      エレキベア
      エレキベア
      こんにちクマ〜〜〜
      マイケル
      マイケル
      今回は、最近行っているオセロAI開発の準備として、
      ML-Agentsを使った強化学習について触っていこうと思います!
      エレキベア
      エレキベア
      ML-Agentsクマか〜〜
      確かに一回触ってみたかったクマ
      マイケル
      マイケル
      オセロAIの学習にはセルフプレイという学習方法を使う予定のため、その使い方まで見ていこうと思っています。
      しかし全部まとめると長くなってしまったので、2記事に分けることにしました・・・。
      マイケル
      マイケル
      というわけで今回は「ML-Agentsを導入し、簡単な強化学習サンプルを作成する」
      ところまで実施していきます!
      今回の目標
      • ML-Agentsを導入して簡単なサンプルを作成する
      • 使い方や機械学習の流れについて理解する
      エレキベア
      エレキベア
      楽しみクマ〜〜〜

      参考資料・書籍

      マイケル
      マイケル
      今回ML-Agentsのサンプルを作成するにあたり、
      基本的に下記の公式ドキュメントを参考に進めました!

      GitHub – Unity-Technologies/ml-agents

      マイケル
      マイケル
      また、それに加えて下記書籍も併用して概要について調べています。
      こちらは日本語ですごく分かりやすいですが、一部古くなっている情報もあるためその点には注意しましょう!

      Unity ML-Agents 実践ゲームプログラミング v1.1対応版

      エレキベア
      エレキベア
      アップデートが頻繁に起こっているのクマね

      ML-Agentsとは

      マイケル
      マイケル
      まずML-Agentsとは何ぞやという話ですが、
      ざっくりと下記のようなものになります!
      ML-Agentsとは
      • Unityで「強化学習」を行うためのプラグイン
      • 学習にはpython環境も用いる
      エレキベア
      エレキベア
      Pythonを用いて学習を行うわけクマね
      マイケル
      マイケル
      そうだね、とはいえただ使うだけならPythonの知識も
      そこまで必要ないため、使ったことない人もご安心ください!

      強化学習

      マイケル
      マイケル
      強化学習がどのような学習法なのかというと、
      行動の主体となる「エージェント」が現在の環境を観察し、より多くの報酬を得られるよう学習していく手法
      になります。
      エレキベア
      エレキベア
      分かるような分からないようなクマ・・・
      マイケル
      マイケル
      分かりやすい例でいうと、Youtuberのこーじさんが上げている人工知能系の動画がまさにこれにあたります!
      ML-Agentsを使った学習の動画をいくつか上げているのでイメージが分からない人はこちらをご覧ください!



      ↑こーじさんの動画(いつも見させていただいてます)

      エレキベア
      エレキベア
      強化学習の面白さが滲み出ていて面白いクマね

      用語と学習サイクル

      マイケル
      マイケル
      ML-Agentsを使うにあたりよく出てくる用語は下記の通りです!
      用語 説明
      エージェント 行動する主体
      環境 エージェントがいる世界
      ポリシー ある状態である行動を行う確率
      状態 エージェントの行動によって変化する環境の要素
      行動 エージェントが環境に行う働きかけ
      報酬 行動の良さを示す指標
      マイケル
      マイケル
      学習のサイクルは下記のようになっていて、
      1. 環境を観察して状態を取得する
      2. 状態に応じて行動を決定する
      3. 行動の結果に応じて報酬を受け取る
      4. 1〜3までの経験からポリシーを更新する
      といった流れで学習を行います。

      ↑学習のサイクル
      エレキベア
      エレキベア
      学習を進めることでポリシーを更新していくクマね
      マイケル
      マイケル
      また、この学習環境の1フレームを「1ステップ」
      訓練一回分を「1エピソード」という単位で表現しています。
      こちらは実際に使用しながら見ていきましょう!

      ML-Agentsの環境構築

      マイケル
      マイケル
      それでは早速環境を構築していきます!
      今回はOSはMacで、下記のバージョンで構築しました。
      バージョン
      Unity 2021.3.1f1
      ML-Agents Release19
      Python 3.7.10

      ↑今回使用したバージョン

      マイケル
      マイケル
      自分が行った環境構築手順について記載していきますがあくまで参考程度にし、
      基本的に環境構築は公式の手順を参照した方がよいです。
      Gitリポジトリ内にインストール手順が記載されているため、そちらを参照しましょう!

      Unity-Technologies/ml-agents – Reference (Release19)
      – Installation

      エレキベア
      エレキベア
      分かりやすくまとめられているクマね
      マイケル
      マイケル
      こちらを参考に、
      ・Python環境の構築
      ・ML-Agentsリポジトリのクローン
      ・ML-Agentsのunity packageをインストール
      といった手順で進めていきます。

      Python環境の構築

      マイケル
      マイケル
      まずはpython環境を構築します。
      ドキュメントには「Python3.6または3.7のインストールをおすすめします」と記述されているため、今回は現時点の3.7の最新である3.7.10をインストールしました。
      マイケル
      マイケル
      またpython環境を初めて構築する場合、複数バージョン管理できる
      pyenvanyenvを使用してインストールすることをおすすめします。
      下記にpyenvを使用したインストール方法の記事のリンクを貼っておくので参考にインストールしましょう!

      MacにpyenvをインストールしてPython環境を構築する

      エレキベア
      エレキベア
      anyenvはマジで便利クマね
      マイケル
      マイケル
      ちなみに自分は必要なものだけ入れたい派なので、基本的にanacondaは入れません!
      Python環境を構築したら、下記コマンドでmlagentsをインストールしましょう。
      python -m pip install mlagents==0.28.0
      マイケル
      マイケル
      必要な依存パッケージも一緒にインストールされるようなのでこれだけで問題ないはず!
      気になる方は pip list コマンドでインストールした内容を確認しましょう。
      エレキベア
      エレキベア
      これだけでPython環境構築は完了クマね

      ML-Agentsリポジトリのクローン

      マイケル
      マイケル
      次に学習やサンプル確認で使用する、ML-Agentsのリポジトリをクローンします。
      インストールしたいブランチを指定して落としましょう。
      git clone --branch release_19 https://github.com/Unity-Technologies/ml-agents.git
      エレキベア
      エレキベア
      訓練用パラメータのサンプル等も用意されているのクマね

      ML-Agentsのunity packageをインストール

      マイケル
      マイケル
      そして次はUnity環境へのインストールです。
      PackageManagerから直接インストールすることもできますが、使用するリポジトリのバージョンと合わせるため、package.jsonを指定したインストールにしておいた方がよいです。
      マイケル
      マイケル
      「Add package from disk」から、「ml-agents/com.unity.ml-agents/package.json」を指定してインストールしましょう。
      ↑インストール後の状態
      エレキベア
      エレキベア
      これでUnity側の環境構築も完了クマね
      サンプルプロジェクトを動かす
      マイケル
      マイケル
      最後に正常にインストールできたかを確認するため、サンプルプロジェクトを開いて動かしてみます。
      ml-agents/Project/Assets/ML-Agents 配下にサンプルが格納されているため、そのままフォルダごとUnityプロジェクトにインポートします。
      エレキベア
      エレキベア
      サンプルプロジェクトもいろいろ用意されているクマね
      マイケル
      マイケル
      しかし、自分の環境だと下記のようにいくつかエラーが出る状態になりました。
      それぞれ対処してもいいですが、今回は面倒くさいのでエラーになっているフォルダは削除して確認します。
      Assets/ML-Agents/Examples/PushBlockWithInput/Scripts/PushBlockActions.cs(15,19): error CS0234: The type or namespace name 'InputSystem' does not exist in the namespace 'UnityEngine' (are you missing an assembly reference?)
      ↑このようなエラーが出た

      今回はエラーとなっている

      Assets/ML-Agents/Examples/PushBlockWithInput
      Assets/ML-Agents/Editor/Tests/SampleExporter.cs
      を丸々削除して解消。

      マイケル
      マイケル
      エラーが解消したら試しに一つサンプルを動かしてみます。
      Assets/ML-Agents/Examples/3DBall/Scenes/3DBall.unity
      を開いて実行すると下記のように動作しました。
      ↑3DBallサンプルを動かした例
      エレキベア
      エレキベア
      学習済の状態で動かせるクマね
      マイケル
      マイケル
      以上で環境構築は完了です!

      RollerBallのサンプルを作る

      マイケル
      マイケル
      環境構築が出来たところで、簡単な強化学習のサンプルを作っていきます。
      こちらも公式チュートリアルに手順が記載されているので、詳細はそちらをご覧ください!

      Unity-Technologies/ml-agents (Release19) Learning-Environment-Create-New.md

      エレキベア
      エレキベア
      球オブジェクトがターゲットに向かって転がっていく動きを学習させるサンプルなのクマね

      プロジェクト構成

      マイケル
      マイケル
      オブジェクトとしてCube(Target)、Plane(Floor)、Sphere(RollerAgent)を作成し、下記のように配置します。
      また、RollerAgentにはRigidbodyもアタッチしておきます。
      ↑オブジェクトの作成と配置
      エレキベア
      エレキベア
      オブジェクトもこれだけでかなりシンプルクマね

      Agentのスクリプト作成

      マイケル
      マイケル
      次に球オブジェクトの学習を行うスクリプトを作成します。
      下記のようにAgentクラスを継承して学習用の関数をオーバーライドし、処理を記述します。
      using Unity.MLAgents;
      using Unity.MLAgents.Actuators;
      using Unity.MLAgents.Sensors;
      using UnityEngine;
      
      namespace RollerBall
      {
          /// <summary>
          /// RollerAgent
          /// </summary>
          public class RollerAgent : Agent
          {
              [SerializeField] private Transform target;
              private Rigidbody _rBody;
      
              /// <summary>
              /// オブジェクト初期化
              /// </summary>
              public override void Initialize()
              {
                  _rBody = GetComponent<Rigidbody>();
              }
      
              /// <summary>
              /// エピソード開始
              /// </summary>
              public override void OnEpisodeBegin()
              {
                  // 床から落下していたら位置をリセットする
                  if (transform.localPosition.y < 0)
                  {
                      _rBody.angularVelocity = Vector3.zero;
                      _rBody.velocity = Vector3.zero;
                      transform.localPosition = new Vector3(0.0f, 0.5f, 0.0f);
                  }
                  // ターゲットの位置をランダムに変える
                  target.localPosition = new Vector3(Random.value * 8 - 4, 0.5f, Random.value * 8 - 4);
              }
      
              /// <summary>
              /// 観察値の設定
              /// </summary>
              /// <param name="sensor"></param>
              public override void CollectObservations(VectorSensor sensor)
              {
                  sensor.AddObservation(target.localPosition);
                  sensor.AddObservation(transform.localPosition);
                  sensor.AddObservation(_rBody.velocity.x);
                  sensor.AddObservation(_rBody.velocity.z);
              }
      
              /// <summary>
              /// ポリシーによって決定された行動に応じて行動を実行する
              /// 結果に応じて報酬取得とエピソード完了を行う
              /// </summary>
              /// <param name="actions"></param>
              public override void OnActionReceived(ActionBuffers actions)
              {
                  // Agentに力を加える
                  // ContinuousActionsを使用した場合(-1.0〜1.0)
                  var controlSignal = Vector3.zero;
                  controlSignal.x = actions.ContinuousActions[0];
                  controlSignal.z = actions.ContinuousActions[1];
                  _rBody.AddForce(controlSignal * 10);
      
                  // ターゲットとの距離に応じて報酬を与える
                  var distanceToTarget = Vector3.Distance(transform.localPosition, target.localPosition);
                  if (distanceToTarget < 1.42f)
                  {
                      AddReward(1.0f);
                      EndEpisode();
                  } else if (transform.localPosition.y < 0)
                  {
                      EndEpisode();
                  }
              }
      
              /// <summary>
              /// ヒューリスティックモードの設定
              /// </summary>
              /// <param name="actionsOut"></param>
              public override void Heuristic(in ActionBuffers actionsOut)
              {
                  // 方向キーで操作する
                  var continuousActions = actionsOut.ContinuousActions;
                  continuousActions[0] = Input.GetAxis("Horizontal");
                  continuousActions[1] = Input.GetAxis("Vertical");
              }
          }
      }
      
      ↑球オブジェクトの学習クラス
      エレキベア
      エレキベア
      この中に学習サイクルの処理が定義されているクマね
      マイケル
      マイケル
      処理内容については後々順を追って説明していきます!
      このスクリプトをRollerAgentオブジェクトにアタッチして下記のように設定します。
      ↑スクリプトのアタッチとパラメータ設定
      マイケル
      マイケル
      MaxStepは1回の学習で行動できるステップ数になります。
      ここでは1000に設定しました。
      マイケル
      マイケル
      そして
      ・Behaviour Parameters
      ・Decision Requester
      の2つもアタッチし、下記のように設定します!
      ↑エージェントの振る舞いを設定する
      エレキベア
      エレキベア
      何の値を設定しているのか分からないクマ
      マイケル
      マイケル
      気になるかもしれないけど、数値の意味についてもこの後流れに沿って説明していきます!
      学習環境の準備としては以上になります!

      強化学習の流れ

      マイケル
      マイケル
      それでは強化学習の流れに沿って、
      スクリプトの内容と設定値について見ていきます!

      ↑学習のサイクル
      エレキベア
      エレキベア
      状態取得→行動→報酬取得 のサイクルだったクマね
      観察状態の取得
      マイケル
      マイケル
      まずは状態取得の部分から!
      こちらはVector Observationの部分が観察値の設定になっています。
      ↑観察値の設定
      マイケル
      マイケル
      浮動小数配列を観察値とするパラメータで、サイズを8に指定しています。
      何故かというと、
      ・Targetの位置(X,Y,Z)
      ・自分の位置(X,Y,Z)
      ・自分の移動速度(X,Z)
      で8つの値を観察値として設定しているためです。
              /// <summary>
              /// 観察値の設定
              /// </summary>
              /// <param name="sensor"></param>
              public override void CollectObservations(VectorSensor sensor)
              {
                  sensor.AddObservation(target.localPosition);
                  sensor.AddObservation(transform.localPosition);
                  sensor.AddObservation(_rBody.velocity.x);
                  sensor.AddObservation(_rBody.velocity.z);
              }
      
      ↑観察値の設定
      エレキベア
      エレキベア
      なるほどクマ
      Vector3は3つ分の値の設定になるクマね
      マイケル
      マイケル
      ちなみにStacked Vectors過去の観察値をスタックする数の指定になります。
      過去の値も含めて観察対象にしたい場合にはこのパラメータを上げましょう!
      行動
      マイケル
      マイケル
      そして次は行動について!
      行動には
      Continuous:連続値(–1.0〜1.0)
      Discrete:離散値(0、1、2…)
      の2種類がありますが、ここではContinuousを使用して行動しています。
      ↑行動として受け取るパラメータの設定
      マイケル
      マイケル
      行動として受け取りたいのはエージェントの速度(X,Z)になるため、
      2つと設定しています。
      こちらはOnActionReceived関数で受け取ることができます。
              /// <summary>
              /// ポリシーによって決定された行動に応じて行動を実行する
              /// 結果に応じて報酬取得とエピソード完了を行う
              /// </summary>
              /// <param name="actions"></param>
              public override void OnActionReceived(ActionBuffers actions)
              {
                  // Agentに力を加える
                  // ContinuousActionsを使用した場合(-1.0〜1.0)
                  var controlSignal = Vector3.zero;
                  controlSignal.x = actions.ContinuousActions[0];
                  controlSignal.z = actions.ContinuousActions[1];
                  _rBody.AddForce(controlSignal * 10);
      
      ・・・略・・・
      
              }
      
      ↑ContinuousActionsを受け取って行動する
      エレキベア
      エレキベア
      学習が進むにつれてこの値の精度が上がっていくクマね
      マイケル
      マイケル
      Discreteを使った場合の学習については後で解説しますので
      そちらはお待ちください。。
      報酬取得
      マイケル
      マイケル
      そして最後に行動した結果に応じて報酬を与えます!
      AddReward関数に報酬値を設定するのですが、1ステップ内の報酬は-1.0〜1.0の間にするのが望ましいらしいです。
              /// <summary>
              /// ポリシーによって決定された行動に応じて行動を実行する
              /// 結果に応じて報酬取得とエピソード完了を行う
              /// </summary>
              /// <param name="actions"></param>
              public override void OnActionReceived(ActionBuffers actions)
              {
      
      ・・・略・・・
      
                  // ターゲットとの距離に応じて報酬を与える
                  var distanceToTarget = Vector3.Distance(transform.localPosition, target.localPosition);
                  if (distanceToTarget < 1.42f)
                  {
                      AddReward(1.0f);
                      EndEpisode();
                  } else if (transform.localPosition.y < 0)
                  {
                      EndEpisode();
                  }
              }
      
      マイケル
      マイケル
      1つの訓練が終わったらEndEpisode関数を呼び出して
      エピソードを終了させましょう!
      このサイクルを繰り返すことで学習していきます!
      エレキベア
      エレキベア
      ペットをしつけている気分になるクマね
      ヒューリスティックモードの設定
      マイケル
      マイケル
      おまけになりますが、
      ・学習モデルを設定していない状態
      ・Behaviour TypeをHeuristic Onlyに指定
      のどちらかの状態で再生すると、手動で動かせるモード(ヒューリスティック)として動作させることができます。
      ↑ヒューリスティックモードの設定
      マイケル
      マイケル
      下記のようにHeuristic関数をオーバーライドして操作を記述することで、
      操作した結果を行動値として渡すことができます。
              /// <summary>
              /// ヒューリスティックモードの設定
              /// </summary>
              /// <param name="actionsOut"></param>
              public override void Heuristic(in ActionBuffers actionsOut)
              {
                  // 方向キーで操作する
                  var continuousActions = actionsOut.ContinuousActions;
                  continuousActions[0] = Input.GetAxis("Horizontal");
                  continuousActions[1] = Input.GetAxis("Vertical");
              }
      
      エレキベア
      エレキベア
      学習開始する前に操作して確かめることができるクマね

      訓練ファイルの作成

      マイケル
      マイケル
      これで準備は整ったので、学習するための訓練ファイルを作成します。
      下記のようなyamlファイルを作成し、ml-agents/config辺りに配置します。
      \behaviors:
        RollerBall:
          # トレーナー種別
          trainer_type: ppo # ppo(オンポリシー) or sac(オフポリシー)
          
          # ハイパーパラメータ
          hyperparameters:
              
            # PPO、SAC共通
            batch_size: 10                 # 勾配降下(適正な値に近づける)の更新1回に使用される経験の数 (Continuousの場合は大きな数、Discreteの場合は小さな数の方がよい)
            buffer_size: 100               # ポリシーの更新を行う前に収集する経験の数(batch_sizeの倍数でなければならない)
            learning_rate: 3.0e-4          # 学習率の初期値 (高いほど学習済とみなして結果を信用する)
            learning_rate_schedule: linear # 学習率をどのように変化させるか (linearは後半になるほど高くし結果を信用する)
            
            # PPO固有
            beta: 5.0e-4             # 行動決定のランダムさ
            epsilon: 0.2             # 勾配降下のポリシー更新比率に対する許容限界の指定 (低くすると安定するが時間がかかる)
            lambd: 0.99.             # GAEを計算するときに使用する正規化パラメータ
            num_epoch: 3             # 勾配降下にポリシー更新時に訓練データを学習させる回数 (小さくすると安定するが時間がかかる)
            beta_schedule: constant  # betaをどのように変化させるか
            epsilon_schedule: linear # epsilonをどのように変化させるか
          
          # ニューラルネットワーク
          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 # 統計情報の保存頻度となるステップ数
      
      マイケル
      マイケル
      学習方法のベースとして大きく
      ・ppo(オンポリシー)
      ・sac(オフポリシー)
      の指定が出来るのですが、ここではppoを指定しています。
      各パラメータはコメントとして書いた内容になりますが、詳細について知りたい方は公式のドキュメントを参照しましょう!

      Unity-Technologies/ml-agents(Release19) ml-agents/Training-Configuration-File.md

      エレキベア
      エレキベア
      いろいろあって分からんクマ・・・
      こればっかりは触って慣れていくしかないクマね

      強化学習実行

      マイケル
      マイケル
      訓練ファイルを配置したら、ml-agentsフォルダ配下で下記コマンドを実行します。
      その状態でUnityプロジェクトのPlayボタンを押下すると学習が開始されます。
      # 学習開始
      # run-idで指定した名前のフォルダに出力される
      mlagents-learn ./config/RollerBall.yaml --run-id=firstRun
      ↑すごい勢いで学習が始まる
      エレキベア
      エレキベア
      何か面白いクマね
      マイケル
      マイケル
      run-idの名前は自由に指定してよいですが、二回目以降は下記のように上書きor再開を指定する必要があります。
      こちらもよく使うと思うので覚えておきましょう!
      # 学習済のフォルダに対して上書きする
      mlagents-learn ./config/RollerBall.yaml --run-id=firstRun --force
      # 学習途中のフォルダに対して再開する
      mlagents-learn ./config/RollerBall.yaml --run-id=firstRun --resume
      マイケル
      マイケル
      学習経過のログやモデルはresultsフォルダ配下に出力されます。
      こちらをtensorboardコマンドとして指定すると学習経過を見ることができます。
      # tensorboardを開く
      tensorboard --logdir results/firstRun --port 6006
      ↑学習経過を見ることができる
      マイケル
      マイケル
      こちらの詳しい見方については下記をご参照ください!
      今回はこちらのCumulative Reward(平均累積報酬)が1に収束してきたらCtrl+Cで学習を停止させましょう。
      するとresults/[run-id]フォルダ配下に学習したモデルが出力されます。

      Unity-Technologies/ml-agents tensorboard

      エレキベア
      エレキベア
      これは中々奥が深そうクマ〜〜

      作成したモデルで推論する

      マイケル
      マイケル
      学習したモデルで動作を確認(推論)してみましょう!
      出力されたモデル(今回はRollerBall.onnx)をUnityにインポートして、Behavior Parametersに指定RollerBall.onnxします。
      ↑学習したモデルを設定
      マイケル
      マイケル
      この状態でPlayボタンを押下すると推論モードとして動作し、
      下記のように学習した内容に沿って動作するようになっているはずです!
      ↑ボールが賢くなりました
      エレキベア
      エレキベア
      おお〜〜なんか生きてるみたいクマ
      マイケル
      マイケル
      以上で学習の一通りの流れは完了です!
      これより先はおまけの内容になるため、興味がある方のみご覧ください!

      その他の知識

      離散値を使用して学習させるパターン

      マイケル
      マイケル
      今回はContinuous(連続値)を行動として指定しましたが、
      Discrete(離散値)を指定した場合も見てみましょう!
      マイケル
      マイケル
      Behaviour Parametersの設定は下記のようになります。
      ↑Discreteを使用する場合の設定値
      マイケル
      マイケル
      今回は
      0:何もしない、1:上移動、2:下移動、3:左移動、4:右移動

      の5つをアクションとして登録しています。
      こうした場合、スクリプトも下記のように修正する必要があります。
              /// <summary>
              /// ポリシーによって決定された行動に応じて行動を実行する
              /// 結果に応じて報酬取得とエピソード完了を行う
              /// </summary>
              /// <param name="actions"></param>
              public override void OnActionReceived(ActionBuffers actions)
              {
                  // Agentに力を加える
                  // DiscreteActionsを使用した場合(branches: 1, branch 0 size: 5)
                  // 0:無し、1:上移動、2:下移動、3:左移動、4:右移動
                  var controlSignal = Vector3.zero;
                  var actionType = actions.DiscreteActions[0];
                  if (actionType == 1) controlSignal.z = 1.0f;
                  if (actionType == 2) controlSignal.z = -1.0f;
                  if (actionType == 3) controlSignal.x = -1.0f;
                  if (actionType == 4) controlSignal.x = 1.0f;
      
                  _rBody.AddForce(controlSignal * 10);
      
                  // ターゲットとの距離に応じて報酬を与える
                  var distanceToTarget = Vector3.Distance(transform.localPosition, target.localPosition);
                  if (distanceToTarget < 1.42f)
                  {
                      AddReward(1.0f);
                      EndEpisode();
                  } else if (transform.localPosition.y < 0)
                  {
                      EndEpisode();
                  }
              }
      
              /// <summary>
              /// ヒューリスティックモードの設定
              /// </summary>
              /// <param name="actionsOut"></param>
              public override void Heuristic(in ActionBuffers actionsOut)
              {
                  // 方向キーで操作する
                  var discreteActions = actionsOut.DiscreteActions;
                  if (Input.GetKey(KeyCode.UpArrow)) discreteActions[0] = 1;
                  if (Input.GetKey(KeyCode.DownArrow)) discreteActions[0] = 2;
                  if (Input.GetKey(KeyCode.LeftArrow)) discreteActions[0] = 3;
                  if (Input.GetKey(KeyCode.RightArrow)) discreteActions[0] = 4;
              }
      ↑Discreteを使用した場合
      エレキベア
      エレキベア
      こっちを使うメリットとしてはどんなものがあるのクマ??
      マイケル
      マイケル
      例えばだけど、攻撃アクションが
      0:ソード、1:ビーム、2:ハンマー
      といった形になっていたとすると、0(ソード)と2(ハンマー)の間は1(ビーム)ではないよね。
      そんな感じで連続じゃない値を行動として指定したい場合に使用するといいよ!
      エレキベア
      エレキベア
      なるほどクマ〜〜〜
      それぞれが完全に分かれている場合があるクマね

      sacを使って訓練するパターン

      マイケル
      マイケル
      次は訓練ファイルについての補足です!
      今回はppoを指定して学習しましたが、sac(オフポリシー)を指定する場合には下記のような設定値になります。
      それぞれ固有のパラメータがあるのと、各パラメータも適正値が異なるため注意しましょう!
      # 詳細な設定範囲については下記を参照
      # https://github.com/Unity-Technologies/ml-agents/blob/release_19_docs/docs/Training-Configuration-File.md
      behaviors:
        RollerBall:
          # トレーナー種別
          trainer_type: sac # ppo(オンポリシー) or sac(オフポリシー)
          
          # ハイパーパラメータ
          hyperparameters:
              
            # PPO、SAC共通
            batch_size: 64
            buffer_size: 12000 # SACの場合、batch_sizeの数千倍に指定する必要がある
            learning_rate: 3.0e-4
            learning_rate_schedule: constant # SACの場合、constantがデフォルト
            
            # SAC固有
            buffer_init_steps: 0                 # 学習開始前に何ステップ分のランダムな行動を経験バッファに埋めるか
            tau: 0.005                           # SACモデル更新中のターゲットの更新の大きさ
            steps_per_update: 10.0               # ポリシー更新に対するステップの平均的比率
            save_replay_buffer: false            # 訓練を終了して再開する際、経験リプレイバッファを保存、ロードする (ONにするとかなりのディスク容量を占有する)
            init_entcoef: 0.5                    # 訓練開始時にエージェントがどの程度探索するか
            reward_signal_steps_per_update: 10.0 # ポリシー更新に対する報酬シグナルのステップ平均比率
          
          # ニューラルネットワーク
          network_settings:
            normalize: false
            hidden_units: 128
            num_layers: 2
             vis_encode_type: simple # これを指定しないと上手く学習できなかった
          
          # 報酬シグナル
          reward_signals:
            extrinsic:
              gamma: 0.99
              strength: 1.0
          
          # 基本設定
          max_steps: 500000
          time_horizon: 64
          summary_freq: 10000
          threaded: true # ステップ実行中にポリシーを更新することで高速化する (ppoのポリシーに反するためそちらではfalseにする)
      
      ↑sacを使用した場合
      マイケル
      マイケル
      オンポリシーが現在のポリシーで得られた経験のみを利用するのに対して、
      オフポリシーは過去の経験も利用して現在のポリシーを予測します。
      学習に必要なステップ数が少なくなる代わりに不安定になりやすいので、学習する内容に応じてどちらを使用するかは決めましょう!
      エレキベア
      エレキベア
      中々難しいところクマね

      学習を効率化したい場合

      マイケル
      マイケル
      そして最後は学習効率を上げるための設定について!
      こちらはアプリ化する等の対処法があるようですが、一つの環境内に複数のエージェントを用意するのが簡単に設定できて効果が高いようです。
      マイケル
      マイケル
      下記のようなイメージになりますね
      ↑複数のエージェントを配置
      エレキベア
      エレキベア
      数回分の訓練を一気に行ってしまおうというわけクマね
      マイケル
      マイケル
      注意点としては、学習させる座標をローカル座標として指定しないといけない点です。
      位置がそれぞれ違うのでそれはそうですよね・・・。
      エレキベア
      エレキベア
      しかしこれは簡単に出来るしいいアイデアクマね

      おわりに

      マイケル
      マイケル
      ML-Agentsの環境導入とサンプル作成については以上になります!
      どうだったかな??
      エレキベア
      エレキベア
      機械学習は難しそうだったクマが、
      触ってみるとイメージが掴めてきたクマ
      マイケル
      マイケル
      パラメータの調整が難しそうだけど、
      使い方自体はそんなに難しくはなかったね
      マイケル
      マイケル
      次の記事ではオセロAI開発に向けて、セルフプレイを駆使した学習について
      進めていこうかと思います!
      お楽しみに〜〜〜!!
      エレキベア
      エレキベア
      クマ〜〜〜〜

      【Unity】ML-Agentsで簡単な強化学習を試してみる【RollerBall】〜完〜

      ※次回の記事はこちら!

      UnityゲームAIML-Agents機械学習
      2022-07-11

      関連記事
      【Unity】Timeline × Excelでスライドショーを効率よく制作する
      2024-10-31
      【Unity】Boidsアルゴリズムを用いて魚の群集シミュレーションを実装する
      2024-05-28
      【Unity】GoでのランキングAPI実装とVPSへのデプロイ方法についてまとめる【Go言語】
      2024-04-14
      【Unity】第二回 Wwiseを使用したサウンド制御 〜インタラクティブミュージック編〜
      2024-03-30
      【Unity】第一回 Wwiseを使用したサウンド制御 〜基本動作編〜
      2024-03-30
      【Unity】第二回 CRI ADXを使用したサウンド制御 〜インタラクティブミュージック編〜
      2024-03-28
      【Unity】第一回 CRI ADXを使用したサウンド制御 〜基本動作、周波数解析編〜
      2024-03-28
      【Unity】サウンドミドルウェアに依存しない設計を考える【CRI ADX・Wwise】
      2024-03-27