2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ついに強化学習を体験してみる備忘録

Last updated at Posted at 2023-10-11

ついにやります強化学習

https://github.com/Unity-Technologies/ml-agents/blob/release_20/docs/Learning-Environment-Create-New.md
GitHubを参考にやっていきます。また英語ですね。
当然ですが英語が基本なので、もう諦めて英語頑張って解読しましょう。

UnityProjectの作成とパッケージマネージャーのインストール

ML-agentsがインストールされたUnityProjectを作成してください。
ここまでは前回やりましたね。
わからなくなったら前回の記事を参照してください。
ML-Agentsの環境構築の備忘録(privateなので現状Mokoしか閲覧できませんが)

Unityのオブジェクト配置

image.png
上の状態を目指して作成していきます。
Unityに慣れているひとなら朝飯前かもしれませんが、念の為少しだけ記述しておきます。

1.空(から)のオブジェクト(TrainArea)を作成。(position = (0,0,0))
2.Planeを作成
3.Cube(name = Target),Sphere(name = Agent)を作成(位置情報は("自由",0.5,"自由")にしておくと見やすいです)
4.AgentにはRigidbodyをコンポーネントを追加しておいてください。
5.緑色と赤色のMaterialを作成し、Cubeには緑、Sphereには赤をアタッチ
6.Target,Agent,PlaneをTrainArea(からのオブジェクト)の子オブジェクトに設定

以上です。本当に念の為って感じですね。
先に少し話しておくと、Positionは正直なんでもいいです、スクリプトで上書きするので。
強いて言えば空のオブジェクトはしっかりVector3.zero = (0,0,0)に設定しておくべきかもしれません。

C#スクリプトを書いていく

やっとコーディングができますね。結構長い道のりだった気がします。
コードの完成形?のようなものは最初に挙げたGitHubにあるのでそれを参照に作るのが手っ取り早いですが、英語文献なので少しだけ自分なりの解釈を書いておこうと思います。
ちなみにAgentオブジェクト(Sphere)(赤色の球体)にスクリプトをアタッチします、とりあえず切りの良いところまで書いてからアタッチすることをおすすめします。
(理由としては、Agentクラスを継承した状態のスクリプトをアタッチすれば、Behavior ParametorというML-Agentsを使うために必要なコンポーネントがAgentオブジェクトに自動で追加されるからです。もしも先に追加してしまったら、コンポーネントを追加からBehavior Parametorを検索して追加してください。)

スクリプトの全容を先に提示しておきます。

RollerAgent.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//MLAgentを使うために必要なライブラリをインポート
using Unity.MLAgents;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Actuators;

public class RollerAgent : Agent
{
    //Update()関数は排除するが、Start()関数は残しておく。
    Rigidbody rb;
    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    public Transform target;

    public override void OnEpisodeBegin()//繰り返す初期地点。リスポーン状態にするための関数Startに近い
    {
        if(this.transform.localPosition.y < 0)
        {
            this.rb.angularVelocity = Vector3.zero;//回転速度状態を0に初期設定
            this.rb.velocity = Vector3.zero;//速度情報を0に初期設定
            this.transform.localPosition = new Vector3(0,0.5F,0);//ボールの位置を初期設定
        }

        target.localPosition = new Vector3(Random.value * 8 -4,0.5F,Random.value * 8 -4);
        //Random.range(-4.0F,4.0F)と同じコーディング
    }

    public override void CollectObservations(VectorSensor sensor)//何をブレインに送信するかの関数
    {
        //TargetとAgentの位置情報を観測し追加。
        sensor.AddObservation(target.localPosition);//データ数は座標なので3つ
        sensor.AddObservation(this.transform.localPosition);//上同様にデータ数は3つ

        //Agentの移動情報(速度情報)を観測し追加。
        sensor.AddObservation(rb.velocity.x);
        sensor.AddObservation(rb.velocity.z);

        //累計8つのデータを送信する必要がある→Space Sizeを8に変更(Behavior Parametor)
    }

    public float forceMult = 10F;
    public override void OnActionReceived(ActionBuffers actions)//どんな動きをするか、そしてその行動に対してどのような点数(報酬)を与えるかの関数
    {
        //rbのx,zの2つの情報を操作したいのでContinuous Actionの数字を2に設定しておく(Behavior Parametor)
        //Vector3を使用しても良い。Vector3 controlSignal.x = actions.~~~[0]のように。(ただしVector3は初期化すること。)
        float x = actions.ContinuousActions[0];//Continuousは小数などの細かい値も連続的に取ってくるイメージ。離散的なものも存在するらしい。
        float z = actions.ContinuousActions[1]; 
        
        //実際に動かす。
        rb.AddForce(new Vector3(x,0,z) * forceMult);

        //targetとの距離を観測
        float dist = Vector3.Distance(this.transform.localPosition,target.localPosition);

        if(dist < 1.42F)//距離が一定以上に縮まったら、1.0という報酬を与える。
        {
            SetReward(1.0F);
            EndEpisode();//報酬を与えたらその実験を終了
        }
        else if (this.transform.localPosition.y < 0)//落下したらということ
        {
            EndEpisode();//報酬を与えず終了
        }
    }

    public override void Heuristic(in ActionBuffers actionsOut)//人がテストするときに用いられる関数
    {
        //Huristic Onlyで使えるようになるっぽい。(Behavior Parametorの設定)
        var continuousActionsOut = actionsOut.ContinuousActions;
        continuousActionsOut[0] = Input.GetAxis("Horizontal");//OnActionReceivedとは逆でユーザの入力を参照している。
        continuousActionsOut[1] = Input.GetAxis("Vertical");
    }
}

追加するデータの数だけAgentオブジェクトにアタッチされているBehaviorParametorのSpaceSizeを変更しなければならない。
image.png
他にもアクション(動く部分(変数))の数も指定しなければならない。
今回はRigidbodyのx,zの2つを操作するので、Continuous Actionの数字を2に設定しておく。
image.png
Heuristic Onlyを使うときは、Decision Requesterをアタッチしてください。そしてPeriodを10にしておいてください。まぁなんでもいいですが、数字が小さいほど感度が高いです。1なら毎フレームかな?
image.png
Heuristic Onlyにするのを忘れずに
image.png

学習に関するパラメータの設定を行う。

ML-Agentsのインストール先(前回全て展開した場所)から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

この情報をコピペしてください。
ちなみにこの情報は学習に関するパラメータです。
Configの中のppoフォルダのなかにはサンプルシーンのパラメータがあります。それを見てみるのもおもしろいです。
ファイル名はなんでもいいですが、RollerConfigにしました。
そしたら拡張子を.yamlにしてください。
image.png
ファイル名拡張子オプションをONにしておくと、拡張子を変更しやすいです。

そしたらUnityを開いて、AgentオブジェクトのBehavior Parametor のBehavior Nameを"RollerBall"にしてください。これは先程の.yamlファイルの上から二番目の名前と一致しています。
image.png

Anaconda Promptで操作する

Anaconda Promptを開いてください。
そしたら以下のコマンドを打ってください。

conda activate mlagents
cd "~~~~~/ml-agents-release_20"//全て展開をした場所に移動してください。
mlagents-learn config/RollerConfig.yaml --run-id=RollerBall

config/"この部分"は自分で別の名前にしている人は自分でそこは変えてください。
そしたら以下のような画面になると思うので、
image.png
UnityProjectを再生すると動き始めます。学習開始です。

Anaconda Navigaterから新しいプロンプトを作成してください。
image.png
mlagentsからOpen promptして、

tensorboard --logdir results --port 6006

を実行してください。
そしたら、httpから始まるところへWebサイトで飛んでください
するとグラフとかが見れると思います。

そしたらAnacondaPromptからctrl+cで一旦止めましょう。
あと先程のコマンドにあったidは重複存在できないため、おなじIDを使いたいときは、

mlagents-learn config/RollerConfig.yaml --run-id=RollerBall --force

をすればよいですが、毎回上書きされるので、Idを変えるのが効果的ではあります。
ただ今は練習ですし、いちいちIdを変えていたら面倒なので、--forceオプションで強制上書きします。

このままでは学習速度が非常に遅いため、Prefab化してたくさん同時並行で学習させます。

Prefab化して学習速度を高速化

TrainAreaをPrefabにします。
プロジェクトにドラックアンドドロップしてください。そうしたら青くなると思うのでそれでOKです。
TrainAreaを選択して、ctrl+D(下にコピー)してください。
何個作るかは自身のPCのスペックに依存すると思うので少しずつ増やすとかでもいいです。
X軸、Z軸を15くらいずつずらして並べてください。
自分は16個ほど作成しました。
image.png
image.png

そしたら先程と同じように実行してください。
image.png
こんな感じになりました。
適当に実行させて、終了させたらmlagentsのフォルダからresultsへ行って、今回指定したIDのフォルダへ行くと、.onnxという拡張子のファイルが生成されていると思います、それが今後使用できる結果になります。

学習済みモデルの使用

さっきの.onnxという拡張子のファイルをUnityProjectのAssetsにコピペしてください。
TrainAreaのPrefab設定へ行って、BehaviorParametorのModelにアタッチしてください。
そしたら学習済みモデルが作成できたということになります。
再生すれば動くと思います。(unityの再生のみでOK)

参考文献

2
2
0

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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?