Unity 機械学習を実装するまでの具体的な流れ

Unity
この記事は約12分で読めます。

Unityで機械学習をしてみたい・・・

ML-Agentsのサンプルシーンは動かせたけど、その先何をすればいいのかわからない・・・

 

こんな疑問を解消したい!そんな思いでこの記事を書きました。

この記事では、UnityでML-Agentsを利用し機械学習をするまでの具体的な流れをまとめていきます。

 

 

現時点で以下のようなシーンを作れるようになったので、そこで学んだ実装までの流れを解説します。

同様の機能は、以下のリンク先のシーンを再現したものになります。

https://github.com/Unity-Technologies/ml-agents/blob/master/docs/Learning-Environment-Create-New.md

 

 

この記事の目標は、機械学習するためのコードの書き方を学ぶことです。

どこから手を付けていいかわからない人はぜひ学んでいってください!

ML-Agentsをインストールし、サンプルシーンを機械学習できている状況から話を始めます。

まだインストールができてない方は、以下の記事を参考にML-Agentsの設定をしてきてくださいね。

【unity】機械学習する環境を設定してみた

【unity】ml-agentsv0.6.0で機械学習をしてみた

 

 

スポンサーリンク

■Unity 機械学習実装までの流れ

ML-Agentsを利用して機械学習を実装するまでの具体的な流れを解説します。

機械学習に必要なのは、「Academy」、「Brain」、「Agent」の3つです。この順で、作成していきます。

それぞれの中身はどんな風になっているのか、詳しく見ていきましょう。

 

1.「Academy」を作成

まず一番初めにつくるのが、「Academy」です。

Academyは機械学習の方法や設定を決めることができます。つまり、Academyは機械学習の枠組みだと考えて差し支えないと思います。

結論だけ言いますと、既にML-Agentsに含まれているクラスを引き継ぐことだけしておきましょう。

 

ここら辺がややこしいのですが、ML-Agentsには「Academy」という名前のクラスが既に作成されています。

機械学習をする際は、この「Academy」クラスを継承するだけで、簡単なものなら動かせます。

 

 

具体的には、以下のメソッドをオーバーライド(上書き)することができます。

メソッド 説明
public override void InitializeAcademy(){} 環境の初期化時に呼ばれる
public override void AcademyReset(){} 環境のリセット時に呼ばれる
public override void AcademyStep(){} 各ステップ開始時に呼ばれる

 

<Academy作成>

1.空のGameObject作成→名前を「プロジェクト名Academy」に変更。(プロジェクト名:BallならBallAcademy)

 

2.新規C#スクリプトを作成 名前は「Academy」にしないように注意「例 BallAcademy」

 

3.スクリプトを開き、以下のように記述する。:Academyが必須!

using UnityEngine;
using MLAgents;

public class FightAcademy : Academy {

    public override void InitializeAcademy()
    {
        base.InitializeAcademy();
    }

    public override void AcademyReset()
    {
        base.AcademyReset();
    }

    public override void AcademyStep()
    {
        base.AcademyStep();
    }
}

 

4. 2.で作成したスクリプトを1.で作成したGameObjectへ割り当てる

 

これでAcademyは作成完了です。公式サンプル程度のものなら、ここから何もいじらなくても動かせます。

お次は「Brain」を作成していきましょう。

 

2.「Brain」を作成

「Academy」の次は、「Brain」を作成します。

Brainはその名の通り「脳」の役割を持ちます。与えられた情報から最適な行動を決定するための部分です。

 

具体的には、後述する「Agent」にて決められた行動から報酬が最大となるように、最適な行動を選択、実行します。

 

Brainには、以下の3種類があります。

Brain 説明
Heuristic Brain スクリプトから行動を選択できる
Learning Brain 学習用Brain 機械学習する際に使ったり、学習したデータから推論したりすることができる
Player Brain 開発用Brain 開発者自身がAgentを動かすことができる 開発時にはこちらを使い、正常に動くか確認してから機械学習を行う

Brainには以上の3つあるわけですが、機械学習に必須なのはLearning Brainだけですね。

 

Player Brainは実際に自分が動かすことができるので、シーンが正常に機能するかを確認することができます。

Heuristic Brainはまだ使ったことがないのでわかりません。申し訳ない…

 

 

具体的なBrain作成方法は以下の通りです。

<Brain作成>

1.[Assets]>[Create]>[ML-Agents]>[Brain]から作成したいBrainを選択。まずはPlayer Brainを作っておきましょう。

2. [Player Brain]の設定

重要な設定項目

Brain Parameters>Vector Observation>Space Size 機械学習時に学習するデータの数を指定 後述のAgentスクリプトでSpace Size分のデータ数を定義する Learning BrainのSpace Sizeも同じ値にする
Edit the discrete inputs for your actions 開発者がAgentを動かす際のキーコマンドを定義(例 Key:W Branch Index:0 value:1 Wキー(Key)を押すと1(value)に割り振られたアクションを実行できる)

後述のAgentスクリプトにてvalueごとのアクションを定義する

Learning Brainも同時に作っておきましょう。Space SizeはPlayer Brainと同じにしておかないとエラーがでますので注意してください。

 

3.「Agent」を作成

「Academy」、「Brain」ができました。最後に「Agent」を作成します。

Agentは、アクションを行うオブジェクトのことを指します。Agentを機械学習することで最適な行動をとらせるように訓練していくわけですね。

 

Agent作成の具体的な流れは以下のようになります。

<Agent作成>

1.GameObjectを作成→名前を「プロジェクト名Agent」へ変更(しなくても大丈夫です)

2.C#スクリプトを作成→名前を「プロジェクト名Agent」へ変更(Agent以外ならOK)

3.プロジェクト名Agentスクリプトをコーディング

4. 2.を1.へ割り当てる

 

まずはAgentクラスの継承を忘れずにしておきましょう。

using UnityEngine;
using MLAgents;

public class FightAgent : Agent {}

 

BallAgentスクリプトには以下のようなメソッドを定義します。

メソッド 説明
public override void InitializeAgent(){} Agentの初期化時に呼ばれる GameObjectの定義などはこのメソッド内で行う
public override void CollectObservations(){} State(機械学習するためのデータ)を定義する BrainのSpace Size分のデータ数を定義
public override void AgentAction(float[] vectorAction, string textAction){} Agentの行動(アクション)を記述
public override void AgentReset(){} Agentリセット時に呼ばれる

 

下記コードが私の作成した球を転がすAgentスクリプトのコードになります。サンプルシーンの「PushBlock」を参考に作成しました。

using UnityEngine;
using MLAgents;

public class FightAgent : Agent {

    GameObject fightAgent;
    Academy academy;
    public GameObject target;
    private Rigidbody targetRb;
    Rigidbody fightAgentRb;

    public override void InitializeAgent()
    {
        base.InitializeAgent();
        academy = FindObjectOfType(typeof(FightAcademy)) as FightAcademy;
        targetRb = target.GetComponent<Rigidbody>();
        fightAgentRb = this.GetComponent<Rigidbody>();

    }


    public override void CollectObservations()
    {
        base.CollectObservations(); //Stateを定義(今回は7つ)
        AddVectorObs(this.transform.position.x);//x座標 +1
        AddVectorObs(this.transform.position.z);//z座標 +1
        AddVectorObs(target.transform.position -this.transform.position);//ターゲットとの相対座標 +3(x,y,z)分
        AddVectorObs(fightAgentRb.velocity.x);//速度のx成分 +1
        AddVectorObs(fightAgentRb.velocity.z);//速度のz成分 +1
        
    }

    public void MoveAgent(float[] act) //移動アクション用メソッド
    {
        Vector3 dirToGo = Vector3.zero;
        Vector3 rotateDir = Vector3.zero;

        int action = Mathf.FloorToInt(act[0]); //value=0になる

        switch (action)
        {

            case 1: //Brain内のvalueが1のとき(Wキー)のアクション
                dirToGo = new Vector3(0.0f,0.0f,1.0f) * 1f;
                break;
            case 2://Brain内のvalueが2のとき(Sキー)のアクション
                dirToGo = new Vector3(0.0f, 0.0f, 1.0f) * -1f;
                break;
            case 3://Brain内のvalueが3のとき(Dキー)のアクション
                dirToGo = new Vector3(1.0f, 0.0f, 0.0f) * 1f;
                break;
            case 4://Brain内のvalueが4のとき(Aキー)のアクション
                dirToGo = new Vector3(1.0f, 0.0f, 0.0f) * -1f;
                break;
        }
        
        fightAgentRb.AddForce(dirToGo*30f);//力を加えて移動させる
    }
    
    int hit =0;
    public void OnCollisionEnter(Collision col)//当たり判定
    {
        if (col.gameObject.tag == "target") {
            hit = 1;
        }
    }


    public override void AgentAction(float[] vectorAction, string textAction)//アクションを定義 報酬などもここに記述する
    {
        SetReward(-0.001f);
        MoveAgent(vectorAction);

        if (hit == 1)
        {
            Done();//Done();でそのステップ終了
            SetReward(1.0f);
            Debug.Log("addreward");
            hit = 0;
            AgentReset();
        }
        else if(this.transform.position.y < -2.0f)
        {
            Done();
            this.transform.position = new Vector3(0.0f, 0.25f, 0.0f);
            fightAgentRb.velocity = Vector3.zero;
            AddReward(-1.0f);
        }
        else if(target.transform.position.y< -2.0f)
        {
            AgentReset();
            Done();
        }

    }

    public override void AgentReset()//リセット時の処理
    {
        target.transform.position = new Vector3(Random.Range(-4.0f, 4.0f),
                                     0.5f,
                                     Random.Range(-4.0f, 4.0f));
    }
}

 

ここまででできたら、Player Brainで動作の確認をし、サンプルシーンを機械学習させるのと同様の手順で学習できます。

CollectObservationsメソッドによるState定義と、報酬の与え方が機械学習に大きな影響を与えるので、そこら辺を最適に設計することが大切です。

 

 

スポンサーリンク

■まとめ

いかがでしょうか。ML-Agentsで機械学習を実装する流れが少しでもイメージできたらすぐ試してみてください。

私はサンプルシーンを自分で再現できるようになりました。次回は自作の機能も作ってみたいですね。

 

 

ML-Agentsは2017年にベータ版が公開されたばかりなので、この記事を書いている2019年3月時点でも、まだまだ情報は少ない印象を受けます。

この記事がお役に立てば幸いです。

 

私が参考にしたのは、「Unity ML-Agents実践ゲームプログラミング」という書籍とサンプルシーンです。

こちらの書籍を読めば、Brainの設定内容などが理解できるので、サンプルシーンを読み進めていくことができます。

ML-Agentsについて書かれている書籍は、2019年3月時点でこの本だけですね。

 

最後まで読んでいただきありがとうございました。

タイトルとURLをコピーしました