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 3 years have passed since last update.

物理エンジンで機械学習① 物体追跡 2021年最新版

Last updated at Posted at 2021-02-25

はじめに

こんにちは。陰キャ大学生です。

前置きはさておき、Pythonを使って機械学習していると、「物理エンジン使ってやってみたいなぁ」なんて思う時があります。ありません
そこで今回は、Unityのために作られた機械学習ライブラリ__ML Agents__ を使って物理エンジンで機械学習してみました。
実はすでにQiita上には多くのMLAgentsの記事が上がっています。

【ML-Agents】UnityとPythonのTensorFlowをつかって機械学習させてみた(v0.11β対応)

しかし、このMLAgents、__バージョンアップが頻繁なうえに、バージョン変わると関数やメソッド名も変わる__というなんともQiitaライター泣かせな仕様となっています。

そこで今回は、現在(2021年2月25日)最新であるRelease13 について記事を書きます。
おそらく数か月後には古くて使い物にならない記事になると思いますが、今この瞬間にMLAgentsを使いたいんだ!!という人に届いてほしいと思います。

#MLAgentsについて

こちらの記事が大変わかりやすく参考になりますので、ぜひご覧ください

Unityで体感する強化学習【ML-Agents】

環境

MLAgentsの推奨環境

  • Unity (2018.4以降)
  • Python (3.6.1以降)

今回私が使用した環境

  • Unity (2019.4.15f1)
  • Python (3.7.9) Anaconda

推奨環境を満たしていれば大丈夫だと思いますが、Unityはバージョン等によりUIが変わる可能性があるのでご容赦ください。

前準備

MLAgentsのダウンロード

こちらのサイトから、__Release13__をダウンロードしてください。
ダウンロードされたZIPファイルを任意の場所に展開してください。

PythonとUnityのダウンロード&インストール

参考記事がわかりやすくまとめてくださったので引用します。参照されてください。

【ML-Agents】UnityとPythonのTensorFlowをつかって機械学習させてみた(v0.11β対応)

準備

Pythonの環境構築

Pytorchのインストール

ターミナルで以下を実行します

pip install torch~=1.7.1 -f https://download.pytorch.org/whl/torch_stable.html

image.png
完了

関連ライブラリのインストール

__展開したディレクトリに移動__して、以下を実行

pip install -e ./ml-agents-envs
pip install -e ./ml-agents

実際、pip install mlagentsでもインストールできますが、この際は常に最新版がインストールされますので、バージョンの整合性をとるためにもダウンロードしたSetup.pyから参照することをお勧めします。

__0.24.0__がインストールされたことを確認してください

Unitでプロジェクト作成

Unity Hubを開いて、プロジェクトの作成をします
image.png

上のメニューから、Window>Package Managerの順に進んで、左上の+マークから、Add Package from disk...を選択して、<展開したフォルダ>/com.unity.ml-agents/package.jsonを選択します。
image.png

インポートが始まり、In ProjectML Agents 1.8.0があれば大丈夫です。
image.png

今回は、箱をボールが追いかけるAIを作成します。(詳しくは記事の最後を見てね)
Unityの詳しい説明等はここでは省略します。

ステージの作成

GameObject>3D Object>Planeを選択し、Stageに改名、Positionを(0, 0, 0)Scaleを(1, 1, 1)に設定
image.png

箱の設定

GameObject>3D Object>Cubeを選択し、Targetに改名、Positionを(3, 0.5, 3)Scaleを(1, 1, 1)に設定
image.png

ボールの設定

GameObject>3D Object>Sphereを選択し、RollerAgentに改名、Positionを(0, 0.5, 0)Scaleを(1, 1, 1)に設定

Inspector下部のAdd Componentから、Physics>Rigidbodyを追加 👈これめちゃ大事です!!!
image.png

後で複製できるように、グループ化しておきます。
GameObject>Create Emptyを選択し、__Stage、Target、RollerAgentをドラッグしてグループ化します__名前は何でもいいです。
image.png

ボールのスクリプト作成

UnityのProject内にScriptsフォルダを作り、その中にRollerAgent.csを作成します
image.png

中身をお好きなエディタで以下のように書き換えてください。
解説は適宜コメントで挿入してあるので見てみてくださいね。

RollerAgent.cs

// 使用ライブラリのインポート
using System.Collections.Generic;
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Actuators;

// Agentクラスを継承し、必要なところだけ書き換えていきます
public class RollerAgent:Agent
{
    Rigidbody rBody;
    // スタートしたときに呼び出される関数
    void Start () {
        // ボールの物体を変数に格納
        rBody = GetComponent<Rigidbody>();
    }

    // Targetをグローバルに宣言
    public Transform Target;
    // エピソード(学習のステップ)が始まった時に呼び出される関数
    public override void OnEpisodeBegin()
    {
        // ボールのY座標が0=落下したとき
        if (this.transform.localPosition.y < 0)
        {
            // 初期化
            this.rBody.angularVelocity = Vector3.zero;
            this.rBody.velocity = Vector3.zero;
            this.transform.localPosition = new Vector3( 0, 0.5f, 0);
        }

        // ターゲットをランダムな位置に
        Target.localPosition = new Vector3(Random.value * 8 - 4,
                                            0.5f,
                                            Random.value * 8 - 4);
    }

    // 観測データ(この場合で言うと学習に必要な数値)の取得
    public override void CollectObservations(VectorSensor sensor)
    {
        // ボールと箱の座標(x, y, z) x 2
        sensor.AddObservation(Target.localPosition);
        sensor.AddObservation(this.transform.localPosition);

        // ボールのスピード(x, z)
        sensor.AddObservation(rBody.velocity.x);
        sensor.AddObservation(rBody.velocity.z);
        
        // トータルで入力次元は8次元になる
    }

    // 力を加えるときの乗数
    public float forceMultiplier = 10;
    // アクションが起きたときに呼び出される関数
    public override void OnActionReceived(ActionBuffers actionBuffers)
    {
        // XとZ軸の入力に合わせてボールに力を加える
        Vector3 controlSignal = Vector3.zero;
        controlSignal.x = actionBuffers.ContinuousActions[0];
        controlSignal.z = actionBuffers.ContinuousActions[1];
        rBody.AddForce(controlSignal * forceMultiplier);

        // 箱とボールの距離
        float distanceToTarget = Vector3.Distance(this.transform.localPosition, Target.localPosition);

        // 箱にボールが到達したとき
        if (distanceToTarget < 1.42f)
        {
            // 報酬を1に設定
            SetReward(1.0f);
            // エピソードを終了
            EndEpisode();
        }

        // ボールが落下したとき
        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にドラッグします。

RollerAgent (Script)Targetに、Target(ゲームオブジェクト)をドラッグ

Add Componentから、ML Agents>Behavior Parametersを追加
Vector Observation>Space Size8 に変更
Actions>Continuous Actions2 に変更
Behavior nameRollerBall に変更

Add Componentから、ML Agents>Decision Requesterを追加
Decision Period10 に変更

最後はこんな感じになります
image.png

テスト

Behavior ParametersBehavior TypeHeuristic Onlyに変更

中央上部のプレイボタンを押して、矢印キーで遊べるか確認してみてください
test.gif

学習

__<展開したディレクトリ>/config/rollerball.yamlを作成__して、以下を書き込みます

rollerball.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
    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: 1000

Behavior ParametersBehavior TypeDefaultに変更

__展開したディレクトリに移動__して、以下を実行

mlagents-learn config/rollerball.yaml --run-id=RollerBall

image.png

Listening on port 5004. Start training by pressing the Play button in the Unity Editor.

この文言がでたら、Unityに戻って、プレイボタンを押すと、学習が始まります。
最初のうちはボールがオロオロ動くのがなかなかに可愛いです笑

学習並列化

物理エンジンのいいところは、モデルを複製して同時に学習を進められるところです。
先ほどグループ化したものをプレハブ化し、複製してみましょう。(特にコード等変える必要はありません)
image.png

さて、改めて学習してみましょう。
test2.gif

ログはこのようになります。Mean Rewardが1に近づけばうまく学習が行われています。
終了したいときは、CTRL+Cで止められます。その時のモデルデータを自動的に保存してくれます。

image.png

また、バックボーンはTensorFlowなので、別ターミナルでコマンドを実行することで、TensorBoardも確認することができます。

tensorboard --logdir results --port 6006

image.png

学習モデルでテスト

<展開したディレクトリ>/results/RollerBall/RollerBall.onnxを、Unityプロジェクト内のAssetsにドロップしたのちに、RollerAgentのInspector内ののBehavior Parameters>Modelにドロップ。

プレイボタンを押すと、学習されたモデルでボールが動く様子を見ることができます。
床から落ちることなく箱を一生懸命追っている姿が確認できますね。可愛い。

test3.gif

最後に

たびたびバージョンの変わってしまうMLAgentsですが、使い方によっては機械学習の世界が広がると思います。
僕も早くコマンドラインで学習できるようにならないかなぁ

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?