Categories: ML-Agents

ML-Agents公式サンプル集解説2 ~3DBall~

こちらのページでは、ML-Agentsの公式サンプルに入っています、「3DBall」についての解説ページになります。

「3DBall」は「Agent」(Unityマークの付いた平板)の傾きを上手く調節して「Ball」を落とさないようにキープしよう!というゲームになります。前回ご紹介しました「Basic」のサンプルに比べると繊細な操作が要求され、ルールはシンプルですが自分で遊んでみても意外と難しく、これを機械学習するとどんな感じになるのか…??というゲームになっています。

ちなみに、パッと画面を見ると12個の同じゲームが並んでいて???となるかもしれませんが、これは1つのBrainに複数(今回は12個)のAgentが紐づいており機械学習時に効率良く学習するためにこうなっております。

なお、本ページはML-Agents(ver0.5)に基づいて解説していきます。2018年12月17日に、ML-Agents(ver0.6)が新規にリリースされました。ver0.6では、Brain Typeの設定方法が大きく変更されております。設定方法についてはこちらのページにまとめましたので、ML-Agents(ver0.6)でサンプルをいじる際は本ページと併せて参考にして下さい。

まずは自分で遊んでみよう

とりあえず、どんなゲームかを体感するために自分で遊んでみましょう。右図は「Ball3DAcademy」の子オブジェクト「Ball3DBrain」の設定画面になります。自分で遊ぶ場合は「Brain Type:Player」でしたね。操作キーは右図にあるように、

・「↑」:vectorAction[1]に値「1」を返す

・「↓」:vectorAction[1]に値「-1」を返す

・「←」:vectorAction[0]に値「1」を返す

・「→」:vectorAction[0]に値「-1」を返す

です。やはりこれだけでは何のことかさっぱり分かりませんが、後で解説しますようにスクリプト(Ball3DAgent.cs)を見ると、以下のように対応していることが分かります。…と言っても、パッとスクリプトを見るだけでは、どのように動くのか正直分かりづらいと思います。キチンと考えたい方は右図の平板の座標系を参考にして下さい(赤矢印:x軸緑矢印:y軸青矢印:z軸です)。

・「↑」:「Agent」(平板)が少し奥に傾く(←平板のx軸中心に+2°回転)

・「↓」:「Agent」(平板)が少し手前に傾く(←平板のx軸中心に-2°回転)

・「←」:「Agent」(平板)が少し左に傾く(←平板のz軸中心に+2°回転)

・「→」:「Agent」(平板)が少し右に傾く(←平板のz軸中心に-2°回転)

また、上でも書きましたように1つのBrainに12個のAgentが紐づいているので、「Brain Type:Player」の場合は、12個のAgentを同時操作することになります。ただ、スクリプトを読むと分かりますが、ボールが最初に落ちてくる位置は完全にランダムで、12個のゲーム中でもバラバラな位置に落下してきます。なので、人力では12個ともボールをキープするのは不可能です。なので、本気で遊ぶ場合も1個のゲームに対してだけ集中して遊びましょう(笑)。

ちなみにスクリプトより、ボールを落とすと報酬-1、ボールをキープし続けると各ステップ報酬+0.1、が入る仕組みになっており、これからいかに長い時間ボールを落とさずキープし続けられるか、というゲームになっていることが分かります。

実際プレイしてみた感じはいかがでしょうか?私ワガハイは10秒ももちませんが下手くそなのでしょうか(笑)?だって、板に摩擦とか無いからボールがツルツル滑るんですもの…orz

次に、機械学習させてみよう

では次に、「Brain Type:External」にしてこのゲームを機械学習させてみましょう(実行のための詳細手順はコチラのページを参照)。

機械学習の最初の方では↓のように、ボールをボロボロ落としまくっております。ワガハイの方が上手いやんけ!(傲慢)

次に、5万ステップ程学習した後の動きを見てみましょう。↓のようになります。「Agent」はゲームの目的を充分理解しており、さらにちゃんとボールをキープ出来ております。すごいバランス感覚ですね…(・0・。)(たまにこぼしてるのはご愛嬌…(笑))。

スクリプトの中身について

この「Basic」には、4つのスクリプト(Ball3DAcademy.cs、Ball3DAgent.cs、Ball3DDecision.cs、Ball3DHardAgent.cs)が付いております。各スクリプトの概要についてはサンプル集解説0にて書いた通りですが、今回のスクリプトの主役は「Agent」に実装している「Ball3DAgent.cs」になりますので、これの中身を解説していきます。

今回もそこまで複雑なスクリプトではありませんので、やはりML-Agents特有のクラス「Agent」の基本に重点を置いて解説していきます!

サンプル集解説0にて書きましたが、「Agent」に付けるスクリプトは「Agent」クラスを継承しており、5つの(オーバーライド)メソッドを持っているんでしたね。では、各メソッドの詳細を見ていきましょう。

<①void InitializeAgent()メソッド:初期化時呼び出し>

今回は、GetComponentメソッドでRigidbodyコンポーネントにアクセスしております。やはり、通常のUnityで出てくるMonoBehaviorクラスのStartメソッドのような使われ方ですね。

<②void AgentReset()メソッド:エピソード終了時呼び出し>

エピソード終了時(④よりBallが落下した時に対応)に呼び出されます。今回も、エピソード終了時には場面がリセットされ、各オブジェクトが初期配置に戻される手続きがなされています。ただし、ボールの初期位置と平板の初期傾き具合はランダムに設定されるようですね。どんな初期配置にも対応出来るように機械学習させたい!という意図でしょうか…?

<③void CollectObservations()メソッド:State取得時に呼び出し>

④のメソッドで「Agent」が行動した結果の状態をAddVectorObs()メソッドを使ってBrainに教えるメソッドでしたね。今回のゲームでは、「Agent」(平板)の状態だけでなく、Ballの状態もBrainに返しています。

機械学習を上手に行うには、どういう状況でゲームが上手く進み(=報酬がプラス)、どういう状況だとゲームが上手く進まない(=報酬がマイナス)のかをAI様がきちんと理解しておく必要があります。AI様は人間のように目を使ってゲーム全体を把握しているしている訳では無いので、AddVectorObs()メソッドを介した情報以外のことは何も知りません

確かに、「Agent」(平板)の状態だけ分かっても、Ballがその上に乗っているか落下しているかでゲームの成功or失敗は大きく変わりますよね。ですので、Ballの状態も知ることが機械学習には必須になります。

public override void CollectObservations()
{
    AddVectorObs(gameObject.transform.rotation.z);
    AddVectorObs(gameObject.transform.rotation.x);
    AddVectorObs(ball.transform.position - gameObject.transform.position);
    AddVectorObs(ballRb.velocity);
}

具体的には、上のように「板のz軸周り回転角」「板のx軸周り回転角」「板に対するBallの位置座標(相対座標)」「Ballの速度」で、float値を合計1+1+3+3=8成分返しています。右下図の「Space Size」が「8」になっているのはこれが理由です。

<④void AgentAction(float[] vectorAction, string textAction)メソッド:ステップ毎に呼び出し>

本メソッドではまず、「Agent」の行動を決定していきます。右図の設定画面中の下側(Vector Action以下)より「Space Size:2」となっていますので、スクリプト中にはvectorAction[0]と[1]が使用出来ます。「Brain Type:External」の場合、vectorAction[0]にも[1]にも任意のfloat値が入り(未確認ですが、おそらくこう?)、「Agent」の行動が決まります。今回の場合、以下のスクリプトより、最初に説明しました通り、vectorAction[0]に0~1が入ると左に、-1~0が入ると右に傾き、vectorAction[1]に0~1が入ると奥に、-1~0が入ると手前に傾きますね。また、各方向の傾き具合には限界値が設定されていますね。

if (brain.brainParameters.vectorActionSpaceType == SpaceType.continuous)
{
    var actionZ = 2f * Mathf.Clamp(vectorAction[0], -1f, 1f);
    var actionX = 2f * Mathf.Clamp(vectorAction[1], -1f, 1f);

    if ((gameObject.transform.rotation.z < 0.25f && actionZ > 0f) ||
        (gameObject.transform.rotation.z > -0.25f && actionZ < 0f))
    {
        gameObject.transform.Rotate(new Vector3(0, 0, 1), actionZ);
    }
    if ((gameObject.transform.rotation.x < 0.25f && actionX > 0f) ||
        (gameObject.transform.rotation.x > -0.25f && actionX < 0f))
    {
        gameObject.transform.Rotate(new Vector3(1, 0, 0), actionX);
    }
}

また、本メソッド中での報酬が与えられる仕組みは次のようになります。AddReward(○○)で○○の報酬を「Agent」に与えるんでしたんね。これを見ると、最初に書きましたように、ボールを落とすと報酬-1、ボールをキープし続けると各ステップ報酬+0.1、であることが分かります。

Done()はエピソードの完了を表しAgentReset()メソッドが発動、でしたね。下のスクリプトからも、Ballが落下する(又は板から大きく離れる)とエピソード完了であることが分かりますね。

if ((ball.transform.position.y - gameObject.transform.position.y) < -2f ||
    Mathf.Abs(ball.transform.position.x - gameObject.transform.position.x) > 3f ||
    Mathf.Abs(ball.transform.position.z - gameObject.transform.position.z) > 3f)
{
    Done();
    SetReward(-1f);
}
else
{
    SetReward(0.1f);
}
<⑤void AgentOnDone()メソッド:エピソード完了時に呼び出し>

今回は使用していません。

3DBallHardについて(参考)

なお、このゲームにはハード版があります。Sceneのフォルダーを見ると、「3DBallHard.unity」なるファイルがありますよね。何がハードなのかと言いますと、別にゲーム自体の難易度が上がっている訳では無く、機械学習の難易度が上がっているんです。下のスクリプト(Ball3DHardAgent.cs)抜粋をご覧下さい。

public override void CollectObservations()
{
    AddVectorObs(gameObject.transform.rotation.z);
    AddVectorObs(gameObject.transform.rotation.x);
    AddVectorObs(ball.transform.position - gameObject.transform.position);
}

上と違うのは、「Ballの速度」が無くなりましたね。もしかしたら、上の③CollectObservationsメソッドの所で「Ballの速度情報なんている??」と思われた方がいらっしゃるかもしれませんが、例えば「板の端っこでBallが超スピード」な状況と「板の端っこだけどBallは止まりかけ」な状況では前者の方が絶望感がスゴいですよね(笑)。なので、Ball速度情報は無くても良いですが、有った方がより効率的に機械学習できるということです。

ただ、Hardの方ではBrainに返す数の種類が減りましたが、その代わり、右図のように、「Stacked Vectors:5」に設定されています。今までは(3DBallも通常版は1になっています)1つ前の情報だけで学習していましたが、ここの値を2以上にすることで、もう少し以前の情報も機械学習の使えるようになっております。

r_yoshi

Share
Published by
r_yoshi

Recent Posts

ゲーム「ワガハイ式テトリス」 制作手順4-2

監督スクリプトを記述しよう(ブ…

5年 ago

動的配列(List型)のご紹介と活用法

こちらのページでは、Unity…

5年 ago

ゲーム「ワガハイ式テトリス」 制作手順4-1

監督スクリプトを記述しよう(ブ…

5年 ago

ゲーム「ワガハイ式ビリヤード」 制作手順2-5

監督スクリプトを記述しよう こ…

5年 ago

ゲーム「ワガハイ式テトリス」 制作手順2-1

テトリミノに付けるスクリプトを…

5年 ago

ゲーム「ワガハイ式ぷよぷよ」 制作手順3-2

各ぷよに付けるスクリプトを記述…

5年 ago