Unityのパッケージであるml-agents
を使用した強化学習の備忘録です.以下のことについて説明します.
- 環境構築
- とりあえず学習させる
- Continuous ActionとDiscrete Action
- InputSystemでのHeuristic()の定義
環境構築
公式のGitHubを確認するのが一番正確でわかりやすいです.はまりポイントは特にありません.
やることは(大体の記憶ですが)以下でした.
- pythonのインストール,仮想環境作る,python環境のセットアップ
- 仮想環境はpython3の
venv
でもいけます.anaconda
は過剰かなー?と思う方はぜひ.
- 仮想環境はpython3の
-
ml-agents
リポジトリのクローン
参考ですが,使用した諸々のバージョンは以下です.
- Unityのエディタ: 2022.1.1f1
- python: 3.9.13
- pytorch (1.7.1) とmlagents (0.28.0) はGitHubで指定されているもののままです.
とりあえず学習させる
これも公式のGitHubを確認しましょう.こちらもはまりポイントは特にありません.RollerAgent
を作る以下の記事の各ステップを正しく実施すれば,確実に学習済みモデルが作成されます.
学習を途中でやめる際は,Unityのエディタのプレイボタン ▶
を押した後,ターミナルでCtrl + C
で大丈夫っぽいです.
学習済みモデル(*.onnx
)はUnityエディタの適当な場所に放り込んで,インスペクタのBehavior Parameters
のModel
の部分に放り込みましょう.その後Unityエディタのプレイボタン▶
で学習済みモデルを動かせます.
Continuous ActionとDiscrete Action
RollerAgent
のサンプルでは,エージェントの行動にContinuous Action
のみが使われていました.それに対して,Discrete Action
なるものも存在します.
Continuous Action
はゲームパッドのスティック入力のような,連続値をとるような場合に使用するようです.例えばゲームパッドの左スティック,左右(水平)の操作だけを学習の対象にしたければ,インスペクタのBehevior Parameters
,Continuous Actions
の数値は1にすべきようです.RollerAgent
のように上下左右への行動を観測の対象にさせたくば,Behevior Parameters
,Continuous Actions
の数値は2とするようです.
Discrete Action
はゲームパッドでいえばボタン入力,またキーボード入力のような,離散値をとるような場合に使用するようです.
Discrete Action
はインスペクタでの設定が少々難儀します.以降は完全に理解していないので参考程度に読んでください.まずインスペクタ上のDiscrete Branches
を操作すると,インスペクタ上のBranch
の項目自体が増えます.一つのBranch
は一つの排他な行動セットを意味するようです.排他な行動セット(※この名前は今適当に決めました)とは,例えばWASDでの移動を考えたとき,上に進みながら下に進む,という行動は定義できないはずです.つまりWとSは排他といえます.簡単のためWASDそれぞれを排他と考えたとき,このWASDの4つの行動は,排他な行動セット,と考えて良いでしょう.このような行動を学習させたい場合,Branchの値は5 (= 4 + 1)とします.この+1の行動は,何もしないという行動です.
また,プレイヤーがWASDで移動しながら,スペースキーでジャンプするような場合を一括で学習させたい場合,Discrete Branches
= 2 にして,一つ目のBranchは5, 二つ目のBranchは2(ジャンプするという状態,何もしないという状態)とすることで,移動とジャンプと同時に学習させることが可能になるようです.
InputSystemでのHeuristic()の定義
学習のために作成した環境がうまくできているかどうかを,エージェントをマニュアルで操作して確かめることができます.そのためには,Heuristic()
にユーザの操作でのエージェントの動作を記述する必要があります.
Unityではユーザの入力を受け付けるとき,従来のInput Manager
(Input.GetAxis
やInput.GetButtonDown
等)と,新しい入力システムであるInput System
のいずれかを選択することができます.RollerAgent
のサンプルでは,より簡便なInput Manager
が使用されていましたが,Input System
を使いたい場合もあると思います.そのときの答えは以下のページに書いてありました.
重要な部分を抜粋すると,以下になります.
public override void Heuristic(in ActionBuffers actionsOut) {
controls.Enable();
actionsOut[0] = controls.Player.Move.ReadValue<Vector2>()[0];
actionsOut[1] = controls.Player.Move.ReadValue<Vector2>()[1];
}
ここで,変数controls
は,InputSystemのインスタンスです.Player
であったりMove
であったりは既に定義している前提です.
同様に,ジャンプのような入力は,以下のコードで取り出せるはずです.
actionsOut[0] = controls.Player.Jump.IsPressed() ? 1 : 0;
おわりに
ちょっと図がないのでわかりにくいですが,まあ備忘録ということで.
間違いがあったらごめんね,参考程度に読みましょう.