【Unity】ディープラーニングを触ってみよう (ML-Agents v0.8.1)

07/02/2019

ディープラーニングってなんだろね?

最近、よく聞くキーワードですよね。人工知能に仕事を奪われるなどなど。センセーショナルなキーワードで好き勝手に書き立てる記者の皆さんはよくご存じなのでしょうが、自分はなんとなくイメージがあるだけであまり理解できていません。
なので、勉強をしてみようと思いますが、人工知能とは??でぐぐったり、本を読んでも抽象的すぎて、眠くなってしまいます。・・・そうなると、やっぱ実践してみましょう。
調べたら、Unityには、Unity Machine Learning Agents(ML-Agetns】機械学習用のライブラリがあります。ML-Agentsは、本格的なAIライブラリTensorFlowを使っているみたいです。


特徴
・PythonからのUnity環境制御
・10以上のサンプルUnity環境
・複数の環境構成とトレーニングシナリオのサポート
・深層強化学習を用いた記憶強化エージェントの訓練
・簡単に定義できるカリキュラム学習シナリオ
・教師あり学習のためのエージェント行動の放送
・模造学習のための組み込みサポート
・オンデマンド意思決定による柔軟なエージェント制御
・環境内のネットワーク出力を視覚化する
・Dockerを使った簡単なセットアップ
・ジムとしての学習環境を包む
・Unity推論エンジンを利用する
・同時Unity環境インスタンスを使用したトレーニング

Windows10/ML-Agents v0.8.1を使ってやってみます。

ざっとマニュアル読んでみましたが、原理はぜんぜん理解できないです。ですが「習うより慣れろ」ですよ。ますはドキュメントを読むながら、チュートリアルをやってみます。
ドキュメントは、下記になります。

準備 インストールについて


GitHubのマニュアル通りに行えば大丈夫だと思いますが、詳細に手順を紹介してくれている日本語サイトがあるので参考にしてみてください。
インストールが終わったら、ドキュメントどおり、Getting Started with the 3D Balance Ball Environmentをやりましょう。ML-Agentsが正常に機能していることがわかります。
今回は、インストールが完了していることが前提となります。まだ完了していない方はインストールをがんばりましょう。

今回のゴール

Making a New Learning Environmentチュートリアルを実践します。
下記のドキュメントを実践します。作業自体は、Unityに慣れている方であれば30分もあれば十分終わります。


球がキューブを探して接近する。この内容を機械学習します。なるべくチュートリアル通りにセッティングし動作させます。

Unityプロジェクトを設定します

1.Unity Editorを起動して、"RollerBall"という名前の新しいプロジェクトを作成します。Unity2018.4.2を使います。

2.Scripting Runtime Version が.NET 4.xに設定されていることを確認します。unity 2018.3以降のデフォルトです。

3.サイトからml-agents-master.zipをダウンロードします。今回使うのはML-Agents v0.8.1 です。..\ml-agents-master\UnitySDK\Assets\よりML-AgentsとGizmosフォルダをコピーします。

地面OBJECTを作成します

ヒエラルキーにて、右クリックをして3Dオブジェクト→平面を作成します。(日本語EDITORを利用してますので、日本語で説明します。)

オブジェクト名称をFloorに名前を変更します。床のマテリアルは適当に変更します。

ターゲットキューブを追加します

ヒエラルキーにて、右クリックをして3Dオブジェクト→キューブを作成します。

お疲れ様ですマテリアルは適当に変更します。トランスフォームの位置をY:0.5 XとZは邪魔にならないように適当に設定します。

Agentの球を追加します

1.ヒエラルキーにて、右クリックをして3Dオブジェクト→スフィアを作成します。マテリアルは適当に変更します。
2.トランスフォームの位置をX:0 Y:0.5 Z:0 に設定します。(中心にします)

3.オブジェクト名称をRollerAgentに名前を変更します。
4.リジットボディコンポーネントを追加します。

Academyを設定します

1.Academy用の空のオブジェクトを作成します。オブジェクトの名称をAcademyとします。
2.C#スクリプトを作ります。名前をRollerAcademyとします。
3.記述を下記のようにします。

using MLAgents;
public class RollerAcademy : Academy
{
}

Brainオブジェクトを追加します

1.Brainsのフォルダーを作って、Brainオブジェクトを作ります。

Player BrainをRollerBallPlayer Learning BrainをRollerBallBrainと名称を変更する。

AgentのC#スクリプトを設定します

1.C#スクリプトを作ります。名前をRollerAgentとします。
2.下記のように書き換えます。AgentReset()に初期化する動作を記述しています。RollerAgentオブジェクトがFloorから落ちた時、中央に戻し速度を0にしています。

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

public class RollerAgent : Agent
{
    Rigidbody rBody;
    void Start () {
        rBody = GetComponent<Rigidbody>();
    }

    public Transform Target;
    public override void AgentReset()
    {
        if (this.transform.position.y < 0)
        {
            // If the Agent fell, zero its momentum
            this.rBody.angularVelocity = Vector3.zero;
            this.rBody.velocity = Vector3.zero;
            this.transform.position = new Vector3( 0, 0.5f, 0);
        }

        // Move the target to a new spot
        Target.position = new Vector3(Random.value * 8 – 4,
                                      0.5f,
                                      Random.value * 8 – 4);
    }
}

3.次の記述を追加します。Brainに渡す値を設定しています。

public override void CollectObservations()
{
    // ターゲットの座標とRollerAgentの座標
    AddVectorObs(Target.position);
    AddVectorObs(this.transform.position);
    // RollerAgentのvelocity
    AddVectorObs(rBody.velocity.x);
    AddVectorObs(rBody.velocity.z);
}

Target.positionは、Vector3のX,y,z の3パラメータがBrainオブジェクトに通知されます。this.transform.positionも同様に3パラメータ。次の2行にてrBody.velocity.xとrBody.velocity.zの2パラメータを渡します。
つまり、Brainには8パラメータを通知します。このため、BrainオブジェクトのBrainParameters:VectorObservation:SpaceSizeに8を設定します。

4.次の記述を追加します。Brainから思考結果をもらいます。

Vector3 controlSignal = Vector3.zero;
controlSignal.x = action[0];
controlSignal.z = action[1];
rBody.AddForce(controlSignal * speed);

action[0]とaction[1]に思考結果が返ってきます。ここでは、X軸とZ軸に対してAddForceしています。2個の思考結果が必要なため、BrainParameters:VectorAction:BranchesSizeに2を設定します。
また、SpaceTypeをContinuousにします。Discreteは、配列にて複数の値を受け取ることになるようです。

5.次の記述を追加します。Brainの思考結果に対する評価をします。評価は-1~+1の範囲で設定します。値が高いほど、高評価です。

float distanceToTarget = Vector3.Distance(this.transform.position,
                                          Target.position);
// Reached target
if (distanceToTarget < 1.42f)
{
    SetReward(1.0f);
    Done();
}

今回は、距離が1.42以内の場合に評価します。ちなみにDone()で初期化します。
// Fell off platform
if (this.transform.position.y < 0)
{
    Done();
}

上記のコードでFloorから落ちた場合も初期化します。

5.最終的なRollerAgentコードは下記になります。

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

public class RollerAgent : Agent
{
    Rigidbody rBody;
    void Start()
    {
        rBody = GetComponent<Rigidbody>();
    }

    public Transform Target;
    public override void AgentReset()
    {
        if (this.transform.position.y < 0)
        {
            // If the Agent fell, zero its momentum
            this.rBody.angularVelocity = Vector3.zero;
            this.rBody.velocity = Vector3.zero;
            this.transform.position = new Vector3(0, 0.5f, 0);
        }
        // Move the target to a new spot
        Target.position = new Vector3(Random.value * 8 – 4,
                                      0.5f,
                                      Random.value * 8 – 4);
    }
    public override void CollectObservations()
    {
        // ターゲットの座標とRollerAgentの座標
        AddVectorObs(Target.position);
        AddVectorObs(this.transform.position);
        // RollerAgentのvelocity
        AddVectorObs(rBody.velocity.x);
        AddVectorObs(rBody.velocity.z);
    }

    public float speed = 10;
    public override void AgentAction(float[] vectorAction, string textAction)
    {
        // Actions, size = 2
        Vector3 controlSignal = Vector3.zero;
        controlSignal.x = vectorAction[0];
        controlSignal.z = vectorAction[1];
        rBody.AddForce(controlSignal * speed);

        // Rewards
        float distanceToTarget = Vector3.Distance(this.transform.position,
                                                  Target.position);

        // Reached target
        if (distanceToTarget < 1.42f)
        {
            SetReward(1.0f);
            Done();
        }

        // Fell off platform
        if (this.transform.position.y < 0)
        {
            Done();
        }
    }
}

動作確認の設定

すべての要素がそろいましたので、各オブジェクトの設定をします。
1.BrainをAcademyオブジェクトに追加します。

2.RollerAgentオブジェクトにRollerAgentスクリプトを追加します。Brainに操作するためのRollerBallPlayerを割り当てます。Decision Intervalを10にします。Decision Intervalは、Decision Frequencyと同じ意味だと思います。
RollerAgentのAgentAction()が1Stepに10回動作することだと思います。<---あまり自信がありません。

3.RollerBallPlayerのインスペクターを確認します。Key Continuous Player Actionsを設定することによって、自分で操作して動作確認ができます。
WSADキーで操作できます。

4.PLAYボタン押下で動作します。WSADキーで操作できます。

機械学習をしてみる

1.Academy オブジェクトのControlにチェックをつける。

2.RollerAgentのBrainオブジェクトをRollerBallBrainに変更する。

3.RollerBallBrainの設定をちゃんとする。

4.Pythonを起動します。
Anaconda3/Anaconda Promptを起動します。activate ml-agentsと入力します。

インストールしたフォルダに移動し下記のコマンドを入力します。

mlagents-learn config/trainer_config.yaml –run-id=firstRun –train

5.Unity PLAYボタンを押下する。
機械学習が始まります。


学習してる様子です。眺めて終わるのを待ちます。

赤い枠に結果のファイルが表示されています。

機械学習の結果を見る

1.下記のファイルをアセットに取り込みます。Anaconda Promptからmodel_path:./models/firstRun-0/RollerBallBrainのファイルを参照します。

2.Brainオブジェクトにセットします。

3.AcademyオブジェクトのControlにチェックを解除します。

4.Unity PLAYボタンを押下する。
学習結果でGameが始まります。

頑張って接近しますが、離れて行ってしまいます。どうやら学習時間がたりないとと言うわけでもなく学習方法に問題がありそうです。

まとめ

非常に興味深いジャンルでした。この記事書くのに脱線しまくっていろいろな資料を読みました。非常に難解な資料が多いのですが、ML-Agentsはわかりやすく記述されています。ただし、英語wwww 翻訳して読んでください。
今回は機械学習の入口にたどり着いた所だと思いますが、すこしだけ機械学習・人工知能をわかった気がします。
次回は様々なパラメータを勉強しながら学習精度を上げていきたいと思います。

スポンサーリンク