概要

Unity ML-Agentsで強化学習させるのに、これまでサンプルを利用していたのですが、Agentや報酬をどうやって設定すればよいのか、いまいち理解できてなかったので、自分でゲームを作ってみました。

ちなみにゲーム開発経験はありません。
なので、ベースとなるゲームについては下記チュートリアルをほぼそのまま参考にさせていただきました。感謝!

【Unity入門】60分で作るシューティングゲーム 第1回
http://nn-hokuson.hatenablog.com/entry/2016/07/04/213231

実際に強化学習させている様子です。


 

仕様

ゲームの仕様です。まだ実装できてないものもあります。
強化学習をさせてながめてて面白くなりそうな仕様にしました。

  • 2D
  • シューティング
  • ゲームオーバーなし
  • 自機からミサイルたくさん発射される
  • 自機は左右に移動できる
  • 自機が移動すると勝手にミサイルが発射される
  • 隕石的なものがランダムに落ちてくる
  • 隕石は大きさと質量がランダム
  • 隕石にミサイルが当たると破壊できる
  • 隕石の質量によって破壊に必要なミサイル数が変わる
  • 隕石にミサイルが当たると得点が入る
  • 自機に隕石が当たるとマイナス得点が入る
  • 獲得した得点によって隕石の量が増える
  • 獲得した得点によってミサイルの発射頻度が変わる
  • 得点が画面上部に表示される
  • 得点はリセットされず、維持される
  • 得点の桁数が増えると画面表示量が増えて邪魔になる

手順

GitHubに作成したゲームを置いてます。READMEを参照ください。(なげやり

https://github.com/kai-kou/endless

強化学習させるのにしたこと

本題です。ゲームを作成するところまでは良かったのですが、Unity ML-Agentsで強化学習させるのに、試行錯誤したので、ポイントをまとめてみます。
Unity ML-Agentsのバージョンは0.4.0になります。

オブジェクトの配置とスクリプト

AcademyオブジェクトとBrainは親子関係になるようにGameObjectを新規作成して配置します。
Brainにはml-agents/unity-environment/Assets/ML-Agents/Scripts/Brain.csを紐つけます。

Academyにはml-agents/unity-environment/Assets/ML-Agents/Examples/Template/Scripts/TemplateAcademy.csをコピペしてファイル名とクラス名を変更したコードを紐つけます。

RocketオブジェクトにはチュートリアルだとRocketControllerスクリプトを用意して紐付けれているけれど、これをml-agents/unity-environment/Assets/ML-Agents/Examples/Template/Scripts/TemplateAgent.csをコピペして紐つけなおします。

状態取得

下記記事にあるRayPerception を利用して、隕石の位置を検知しようとしましたが、2Dには対応していませんでした。

【Unity ML-Agents】強化学習で物体を避ける
https://qiita.com/God_KonaBanana/items/e56fcee3ae544be7dfca

なので、泥臭くロケットと隕石の位置を自前で取得してAddVectorObs で設定しています。

状態数は固定である必要があるので、最後に足りない分を0で埋めてます。うーん泥臭い。
隕石オブジェクトを取得するにはオブジェクトにTagを設定しています。

RocketAgent.cs

 public override void CollectObservations()
    {
        AddVectorObs(transform.position.x);
        AddVectorObs(transform.position.y);
        var rockCount = 1;
        foreach (var rock in GameObject.FindGameObjectsWithTag("Rock"))
        {
            AddVectorObs(rock.transform.position.x);
            AddVectorObs(rock.transform.position.y);
            AddVectorObs(rock.GetComponent<RockController+gt;().endurance);

            if (rockCount++ >= 20)
            {
                break;
            }
        }
        for (int i = rockCount;i <= 20;i++)
        {
            AddVectorObs(0f);
            AddVectorObs(0f);
            AddVectorObs(0f);
        }
    }

報酬設定

RocketAgent内で報酬設定するにはAddReward をそのまま呼べるのですが、隕石を破壊した際にも報酬を設定したい。となると玉オブジェクトに実装があるので、どうしようと考えて、以下のようにRocketAgentsにpublicなメソッドを追加して対応しました。

RocketAgent.cs

  public void Rocket_AddReward(float reward)
    {
        AddReward(reward);
        if (reward < 0)
        {
            Done();
        }
    }

BulletController.cs

 GameObject.Find("Rocket").GetComponent<RocketAgent>().Rocket_AddReward(3f);

スピード設定

Academyオブジェクトで学習時のスピードを指定できますが、なにも対応していないと、隕石の発生頻度はあがりつつも、落下スピードはそのままで、超大量の隕石が発生。。。とか挙動が面白くなります。

なので、速度設定している箇所にTime.timeScale を追加して対応しました。

RockController.cs

 void Start () {
        this.fallSpeed = (0.01f + 0.01f * Random.value) * Time.timeScale;
        this.rotSpeed = (5f + 3f * Random.value) * Time.timeScale;
        this.endurance = 1f + Random.value * 5f;
    }

というわけで、強化学習させるための2Dシューティングゲームを作ることができました。
ただ、学習をさせてみると、まだ報酬設定やハイパーパラメータの設定がいまいちなようで、まだまだ詰めが必要な状況です。
興味がある方はぜひここからチューニングしてみてくださいね^^

元記事はこちら

Unity ML-Agentsで強化学習できる2Dシューティングゲームをつくってみた