Help us understand the problem. What is going on with this article?

【Unity強化学習】自作ゲームで強化学習

More than 1 year has passed since last update.

※2018年6月、ML-Agents v0.4に対応するように修正いたしました。

Unity ML-Agents

Unity ML-Agents というUnityを使って強化学習できるライブラリがあります。

公式のほうにチュートリアルも載っているのですぐ試してみることができます。

チュートリアルをやってみると、ボールを落とさないように板を動かす学習モデルができると思います。

ML_Agent_3DBall.gif

今回は自分でゲームを作ってUnity ML-Agentsで強化学習していきたいと思います。

作るゲームは強化学習では王道ともいえる倒立振子です。
棒を倒さないようにするやつですね。

ML_Agent_CartPole.gif

ゲームを作る

公式の方から、ML-Agents をダウンロードしてきます。

unity-environmentをUnityで開きます。

SnapCrab_NoName_2018-2-25_15-16-59_No-00.png

CubeとCylinderを作ります。名前はCartとPoleに替えます。
適当に色を付け、Transformは次のように設定します。

SnapCrab_NoName_2018-2-25_15-34-39_No-00.png

SnapCrab_NoName_2018-2-25_15-34-24_No-00.png

SnapCrab_NoName_2018-2-25_15-28-16_No-00.png

それぞれにRigidbodyをとりつけ、CartはIs Kinematicにチェックを入れ、PoleはDragを0.5にします。

Poleを選択し、Component>Physics>Hinge Jointを付けます。

SnapCrab_NoName_2018-2-25_15-49-2_No-00.png

Connected BodyにCartを入れ、他の設定は画像にようにします。

ML-Agents

ML_Agents.png

ML-Agentsでは画像のようにAgent,Brain,Academyで制御し、外部のPythonを利用して学習を行っていくようです。

Unity Hierarchyで空のゲームオブジェクトを3つ作り、Game,CartPoleBrain,CartPoleAcademyと名付けます。
そして、画像のように配置します。

SnapCrab_NoName_2018-2-25_19-42-19_No-00.png

ML-Agents>Template>ScriptsにTemplateAcademy,TemplateAgentsが入っているので、それらをCartPoleAcademy,CartPoleAgentsに変更、内部のクラス名も同じように変えて、HierarchyのCartPoleAcademy(オブジェクト)とCart(オブジェクト)にそれぞれ取り付けます。

SnapCrab_NoName_2018-2-25_19-55-57_No-00.png

SnapCrab_NoName_2018-2-25_20-1-31_No-00.png

ML-Agents>ScriptsにBrainがあるのでこれをCartPoleBrain(オブジェクト)に取り付けます。

Cart Pole Agents

CartPoleAgentsのスクリプトを以下のように書き換えます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MLAgents;

public class CartPoleAgent : Agent
{
    public GameObject pole;
    Rigidbody poleRB;
    float angle_z;
    float cart_x;
    float anguVelo_z;

    public override void InitializeAgent()
    {
        base.InitializeAgent();
        poleRB = pole.GetComponent<Rigidbody>();
    }

    void FixedUpdate()
    {

    }

    public void StateTransition()
    {

        //ポールの角度が-30~30度の時、報酬+0.01、それ以上傾いたら報酬-1
        if (-30f < angle_z && angle_z < 30f)
        {
            AddReward(0.01f);
        }
        if ((-180f < angle_z && angle_z < -30f) || (30f < angle_z && angle_z < 180f))
        {
            AddReward(-1f);
            Done();
        }

        //カートの位置が-3~3の範囲を越えたら報酬-1
        if (cart_x < -3f || 3f < cart_x)
        {
            AddReward(-1f);
            Done();
        }
    }

    public override void CollectObservations()
    {
        AddVectorObs(cart_x);
        AddVectorObs(angle_z);
        AddVectorObs(anguVelo_z);
    }

    public void MoveAgent(float[] act)
    {
        //0-Left, 1-Right
        int action = Mathf.FloorToInt(act[0]);

        if (action == 0)
        {
            transform.Translate(-0.05f, 0, 0);
        }
        if (action == 1)
        {
            transform.Translate(0.05f, 0, 0);
        }
    }

    public override void AgentAction(float[] vectorAction, string textAction)
    {
        //行動
        MoveAgent(vectorAction);
        //カートの位置、ポールの角度と角速度
        cart_x = transform.localPosition.x;
        angle_z = pole.transform.localRotation.eulerAngles.z;
        //angle_zを-180~180度に変換
        if (180f < angle_z && angle_z < 360f)
        {
            angle_z = angle_z - 360f;
        }
        anguVelo_z = poleRB.angularVelocity.z;
        //状態の遷移
        StateTransition();
    }

    public override void AgentReset()
    {
        //エージェントの状態をリセット
        transform.localPosition = new Vector3(0f, 0f, 0f);
        pole.transform.localPosition = new Vector3(0f, 1f, 0f);
        pole.transform.localRotation = Quaternion.Euler(0f, 0f, 0f);
        poleRB.velocity = new Vector3(0f, 0f, 0f);
        //ポールにランダムな傾きを与える
        poleRB.angularVelocity = new Vector3(0f, 0f, Random.Range(-0.5f, 0.5f));

    }

    public override void AgentOnDone()
    {

    }
}


Brain, Agentを次のように設定します。

SnapCrab_NoName_2018-5-19_15-55-42_No-00.png

SnapCrab_NoName_2018-5-19_15-53-57_No-00.png

きちんと動いて、角度が一定以上になったらリセットされればOKです。
そしたらGame(オブジェクト)を複製して16個にしましょう。

SnapCrab_NoName_2018-2-25_20-52-0_No-00.png

これで学習準備が整いました。

ビルドして学習

1.CartPoleBrainのBrainTypeをExternalにする
2.画面上部のバーから Edit > Project Settings > Player

Resolution and Presentation > Run in Background がチェックされていることを確認
Resolution and Presentation > Display Resolution Dialog がDisabledににセットされていることを確認

3.File > Build Settingsから内容を確認してビルド。保存先は公式からダウンロードしたml-agents-master > pythonです。名前はCartPoleにしておきましょう。

pythonフォルダでAnacondaプロンプトを開き、次のように入力します。

python learn.py CartPole --train

trainer.configというファイルを開くとハイパーパラメータなどの設定ができます。

SnapCrab_NoName_2018-5-19_16-14-18_No-00.png

基本的にデフォルトのままで、max_stepsだけ20万回にしました。

学習が完了すると、python/models/ppo/ フォルダにCartPole.bytesというファイルが生成されています。
これをUnityのAssetsに持っていきます。

Edit > Project Settings > Player の Other Settings欄へ行き、
Scripting Runtime Version を Experimental(.NET4.6Equivalent)にする
Scripting Define Symbols に ENABLE_TENSORFLOW と入力する

SnapCrab_NoName_2018-2-25_22-17-39_No-00.png

また、Using TensorFlowSharp in Unity (Experimental)
こちらからTensorflowSharpのUnityPackageをダウンロードして、環境にインポートしましょう。
これは、Unity環境でTensorflowを使うためのプラグインです。

SnapCrab_NoName_2018-5-19_16-28-26_No-00.png

CartPoleBrain(オブジェクト)のBrain Type をInternalにする
先ほどのCartPole.bytesファイルをGraph Modelにセット。

SnapCrab_NoName_2018-5-19_16-34-24_No-00.png

これで実行してみましょう。

結果

CartPole.gif

20万回学習した結果、倒れることはなくなりました。

参考

  1. Unityで強化学習していたAgentのソースコードを読む話
  2. Unityで強化学習するけど脱サンプルするためにサンプル以下の物を作った話
  3. 【Unity】Unityで機械学習する「ML-Agent」を色々と試して得た知見とか
  4. Unityが機械学習のライブラリを公開したので使ってみる (和訳付き)
  5. プルプルしている倒立振子を安定させる話
God_KonaBanana
強化学習に興味があります。現在Unity ML-Agentsにハマってます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away