ゲームAI・人工生命

(MindRender, Unity)

2021年度の演習のページ

最新の情報ではないため注意してください.→2022年度の演習課題

概要

Unity/C#を用いたAI学習用ソフトMindRender環境内で、車の自動運転・ジャグリングなどの課題に取り組んでもらいます。

よりチャレンジングな課題に取り組みたい学生には、サンプルプログラムを参考に、自分で考えた課題へのAI応用に取り組んでもらいます。


導入方法

教科書に記載されている通りです。


サンプルプロジェクトのダウンロード

・パスワードは授業内で公開します。

・教科書に載っているサンプルプログラム一覧

https://www.dropbox.com/sh/qf80upevau14jr5/AADvfkJ8uqS-_blaFxG63kPEa?dl=0


Couzinのアルゴリズム

https://univtokyo-my.sharepoint.com/:u:/g/personal/7751510781_utac_u-tokyo_ac_jp/EXb1gQY7dRtAmgQjTtLMna4B2yEuizONrREdvlPkfOktDA?e=0uZnZE


Unityについて

MonoBehaviourを継承したクラスは、Update・FixedUpdate関数が一定間隔で実行されます。ここにシミュレーションの処理を書いていくことになります。Start・Awake関数はシミュレーション開始時に実行されます。初期化などの処理をここに書きます。

GameObjectにアタッチされたスクリプトのpublic変数、および[SerializeField]と宣言された変数はUnity側から編集できるようになっています。

Unityについては提供する本の他にも公式(https://learn.unity.com/)や他のWebサイトにも多くの資料があります。


サンプルプログラムについて

各プログラムに共通の説明

〇〇.proj/Assets/Scriptsフォルダにプログラムを動かすC#ファイルがあります。

プログラムは大まかに、UnityのGameObjectを動かし環境を観察するAgentクラス、現在の状態を入力として受け取り行動を出力するBrainクラス、AgentとBrainを組み合わせ学習のループを回すEnvironmentクラスの3つに分けられます。


Agent

CollectObservation関数で現在の状態を取得します。

AgentAction関数ではUnityのGameObjectを動かし、必要に応じてエージェントに報酬を与えます。

UnityのScene内では、車/ヘリコプターのオブジェクトにスクリプトがアタッチされています。

Brain

現在の状態を入力とし、ニューラルネットワーク/Qテーブルによってエージェントが次にとるべき行動を返します。

Environmentスクリプト内で生成されます。

Environment

NEEnvironmentでは学習の高速化のため、並行して複数のAgentをシミュレートしています。そのため、GameObjectを生成します。

UnityのScene内では、Environmentオブジェクトにスクリプトがアタッチされています。


タスクとソースコードのコード依存関係

基本的に、Agentの部分はタスクに依存するので、取り組む課題によって書き換える必要があります。(何が入力で、何が出力なのかが変わるため。)

一方で、同じタスクでも学習手法を変更したい場合は、BrainやEnvironmentの部分を書き換える事になります。これらの関係を示しているのが下の図です。


課題について(以下現在、加筆修正中)

(1)アリのフェロモントレイルの改良(主な担当TA:森 )

<概要>

アリはフェロモンを使って情報をやり取りし、行列を作って餌を巣に持ち帰ります。このプログラムではアリの行動やフェロモンについて簡単なモデルを仮定してシミュレーションを行います。

(モデルや実装について詳しく書かれているテキストを用意しています。)

<ソースコードの概要>

シーン1は障害物がありません。シーン2では中央に1つの大きな障害物が、シーン3では小さな障害物が複数配置されています。

他のプログラムと構造が異なるので注意してください。主なコードは以下のようになっています。

  • AntController.cs

Antオブジェクトにアタッチされています。アリの移動、状態遷移、フェロモンの放出や検知を行います。

  • CollisionDetection.cs

Antオブジェクトにアタッチされています。餌巣との接触判定や接触時の処理を行います。

  • AntGeneration.cs

アリを巣から生成します。フェロモンに対して異なる感度を持ったアリを生成することができます。

  • PheromoneController.cs

フェロモンオブジェクトにアタッチされています。時間経過によってフェロモンの濃度が下がるようになっています。


<課題の進め方>

  • まずはテキストを読んだり、シミュレーションを動かしたりしながら概要を把握する。

  • 各種パラメーターや地形、餌などに変更を加え、挙動を確認する。

  • 自由に改良(改造)する。パラーメターの自動調整、環境に制約を追加する、全く別の群知能シミュレーションを作ってみる、など


(2)boidの改良(主な担当TA: 片山)

<概要>

魚の群れ行動を再現した、boidのアルゴリズムというものがあります。ここではそのアルゴリズムを改良し、魚の面白い動きを作ってもらいます。

例としては、魚の群れに捕食者が来たときの動きを再現するFishattackや、その捕食者が複数になった場合のシミュレーションなどが考えられます。

<ソースコード>

本実験ではURL1で公開されているコードまたは、それを片山が改良したURL2のコードをgitを用いてcloneして使ってください(改良版は地形を複雑化させて魚をリアルな見た目にしただけなのでコードの構造は基本的に同じです。あとはコードに少しコメントが入っています)。URL1のsimulationの参考動画がURL3にあります。

  1. https://github.com/SebLague/Boids/tree/master

  2. https://github.com/sk161717/Boid2

  3. https://www.youtube.com/watch?v=bqtqltqcQhw&ab_channel=SebastianLague

コードの説明は以下のようになっています。

  • Boid.cs

boidの個体一つ一つにアタッチされています。周りの状況に関する変数をもとに、魚の速度や進む方向を決定します。

  • BoidManager.cs

boidの全個体の情報を管理しています。その情報をBoidComputeに投げることで、各個体の周りの状況に関する変数を毎フレーム計算しています。

  • BoidHelper.cs

障害物のない方向を探知するためのrayのvectorを作成します。

  • BoidSetting.cs

シミュレーションのパラメータを一括で管理しています。

  • BoidCompute.compute

BoidManagerから各個体に関する情報を渡され、それぞれのboidの周辺環境(群れの中心など)を計算します。計算処理が重いためこのcompute shaderに処理が分離され ています。

  • Spawner.cs

Boidの初期個体を生成します。


なお、fishattackを実装する上では

http://www.iba.t.u-tokyo.ac.jp/iba/Swarmlec/rep2021.html

が参考になります。


また,boidのアルゴリズムを少しばかり複雑にしたような”Couzinのアルゴリズム”のプログラムもサンプルとして提供しています.詳しい説明は,ファイルに入っているREADMEをご覧ください.

(3) 自動運転プログラムの改良(主な担当TA : 須田)

<概要>

サンプルコードにはニューロ進化またはQ学習で各コースを走れるよう進化・学習するというものがありますが、現状ではQ学習で一部のコースを走れるようになっていて、ニューロ進化ですべてのコースを走れるようになっています。そのため、この課題ではニューロ進化を用いる場合、ただ単にコースを走りきるだけではなく障害物を避けたりするなど走る+αの動作を車ができるようになることが期待されています。


<ソースコード>

教科書(Mind Render AI Drill)の3, 4, 5章にサンプルコードが何をしているかがわかりやすく書いてあるのでそちらを読んでいただきたいと思います。

シーンファイル:

・Challenge 1(./self-driving.proj/Assets/Scenes/Challenge1.unity)

・Challenge 2(./self-driving.proj/Assets/Scenes/Challenge2.unity)

・Challenge 3(./self-driving.proj/Assets/Scenes/Challenge3.unity)


<設定されているChallengeについて>

この課題ではあらかじめChallengeが設定されています。もちろん必ずしもこのChallengeに沿って課題を進める必要はありませんが参考にしてみてください。

Challenge1: コース上に数個の岩が設置されるのでその岩に当たらずにコースを一周できるように進化・学習させる。(岩の位置は固定)

Challenge2: Challenge1と同じくコース上に数個の岩が設置されるのでその岩に当たらずにコースを一周できるように進化・学習させる。(岩の位置は固定ではなくランダム)

Challenge3: 坂の上から岩が転がり落ちてくるのでその岩に当たらずにコースを一周できるように進化・学習させる。

Challenge4: コース上に一定間隔で岩が置かれていて近づくと転がり落ちてくる。岩の大きさや速度はランダム。


<各Challenge Sceneの動かし方について>

各Challenge Sceneはダウンロード時にはテスト用になっているのでこれらを学習環境にする方法をここでは述べます。

  1. まず始めにEnvironmentをNE/stage1のようにNE以下のシーンからコピーして持ってきます。

  2. EnvironmentのNEEnvironmentのAgent PrefabにCar@Blueをアタッチして、その下のUI ReferencesにはText@Population(text)をアタッチする。

  3. Car@Blue内のCarAgentにあるisLearningにチェックを付ける。

  4. 最後にExcutorを削除する。

2021年度の実験で配布している環境では既にNEEnvoirnmentが入っているのでこの操作は不要(Dropboxのchallenge Sceneには入っていないためそちらを使う場合には必要)


<Challenge3について>

Challenge3は坂の上から岩が転がり落ちてくるのですが、現状では真ん中からしか落ちてこないことに加えて意図しないところで岩がリセットされるという学習には向いていない環境になっています。そこで落ちてくる位置をランダムにして、なおかつ岩が下まで落ちてからリセットするように変更するための手順をここでは紹介します。

  1. Asset/Scripts/Waypointsを授業内で配布するWaypointsで置き換える。

  2. ResetPointにおいてTriggerObserverを削除して、新たにAddComponentでAsset/Scripts/Waypoints/Obstacle_stage3.csを追加する。追加したObstacle_stage3のComponentでList is Emptyとなっているところに+ボタンがあるのでそれで追加し、None(Object)となっているところにWaypointsをアタッチしてno functionのところにはObstacleControllerからSetForceを選択する。そうするとその下にNone(Transform)と出てくるので、そこにはForcePointを選択する。

  3. ForcePointにおいてSphere colliderを10から15へと変更する。ResetPointでObstacle_stage3を設定した際と同様にTriggerObserverを変更する。ただし、ここではfunctionにSetForceではなく、ObstacleControllerのResetAndForceを選択し、その他はResetPointでのObstacle_stage3と同様。

  4. 最後に、Waypoints/Rockにあるobstacle.csのTargetにForcePointを設定する。

2021年度の実験で配布している環境では既に上記操作は適用済みなのでこの操作は不要(新たなWaypoint.csも配布していません)

(4)ゲームAI/パズルAIの実装(主な担当TA: 水上)

<概要>

この課題では、(完全情報)ゲームをプレイするAIまたはパズルを解くAIの構築・改良を目指します。

ゲームについては新たなゲームを実装しても良いですし今あるコードを改良して頂いても構いません。

パズルについては、自分で新たなパズルをUnity上に作成してそれを解くようなアルゴリズムを実装するというタスクになっています。


サンプルプログラムでは以下の二つが実装されています。

  • ミニマックス法を用いてオセロをプレイするAI

  • 現在の盤面(状況)から有望そうな手を中心に探索を広げてゆくA*アルゴリズムを用いて倉庫番・15パズルを解くAI


<ソースコード(オセロ)>

シーンファイルには、AI同士の対戦を行うAIvsAI.unityと、AIと人間の対戦を行うAIvsHuman.unityの2つがあります。

主なスクリプトは以下の4つです。

  • OthelloAIForAIvsAI.cs

    • AI同士の対戦を管理します。AIの評価関数が実装されています。

  • OthelloAIForAIveHuman.cs

    • AIと人間の対戦を管理します。AIの評価関数が実装されています。

  • Board.cs

    • 盤面の状態を管理します。手数などの、盤面に関する情報を返す関数が実装されています。

  • PlayerInformation.cs

    • 人間なのかAIなのかや、AIである場合の評価関数のパラメータといった、プレイヤーに関する情報を管理します。

<ソースコード(パズル)>

・シーンファイル :

・倉庫番(./astar.proj/Assets/Scenes/Sokoban*.unity)

・15パズル(./astar.proj/Assets/Scenes/15Puzzle.unity)

・主に編集すべきスクリプト :

・倉庫番(./astar.proj/Assets/Scripts/Sokoban/SokobanSolve.cs、 ./astar.proj/Assets/Scripts/Sokoban/SokobanSolveField.cs)

・15パズル(./astar.proj/Assets/Scripts/15Puzzle/PuzzleController.cs)

<改良の例(オセロ)>

  • ミニマックス法の改良版として、アルファ・ベータ法を実装してみましょう。

  • ゲームの終盤では、評価関数を用いて手を選ぶのではなく、全探索を行い最も石数が大きくなる手を選ぶようにしてみましょう。


<参考までに課題の進め方(パズル)>

ステップ0. 教科書第6章を読んで、プログラムの動作を理解しよう。

ステップ1.A*アルゴリズムなどの盤面探索アルゴリズムを応用できそうなパズルをUnityで実装しよう。

ステップ2. サンプルプログラムを応用して、実装したパズルを解くことのできるAIを作ろう。

ステップ3. A*アルゴリズムのヒューリスティック関数を改良するなどし、AIの性能を向上させてみよう。

ステップ3-α. ヒューリスティック関数にニューラルネットを用いると、どのような結果が得られるか試してみよう。

(5)サンプルプログラムを参考に、新しい課題にAI学習を適用する。 (担当TA : 全員)

以下の条件の下、サンプルプログラムを元に、面白いものを作成してください。

配布するサンプルプログラムは以下の通りです。

  • 倒立振子

  • 自転車の形状進化

  • ジャグリング

条件1. サンプルプログラムと同じ環境下で動作すること。

条件2. AIのプログラムであること。


(5-1) 倒立振子

<概要>

台車の上に立てられた棒を,台車を左右に動かして倒さないようにする問題です.

台車が1軸上を左右に動けるものと平面上を自由に動けるものが用意されています.

配布されているプログラムでは,台車の座標や棒の角度を入力として,台車に加えるべき力の大きさが出力となるようにニューラルネットワーク(多層パーセプトロン)を,誤差逆伝播法(Back-Propagation)を用いて学習させています.


<ソースコードの概要>

Scenesフォルダ内のStage1が,台車が1軸上を左右に動けるもの,Stage2が平面上を自由に動けるものです.

Stage0では1軸上を動くものをキーボードの矢印キーの左右で操作できます.


自動運転プログラムなどと同様にAgent, NNBrain, NNEnvironment の3つのクラスで基本的に構成されています.(一部関数の名前が違ったりAgentが報酬を返さなかったりしますので注意してください.)

Agentが観測できる状態は,台車の座標・速度,棒の角度・角速度の4次元(Stage2では8次元)です.

Agentが取れる行動は,台車に力を加えることです.加える力は,-1~1の範囲の実数の1次元(Stage2では2次元)で指定できます.

棒が倒れてしまうか台車が範囲外に出てしまうとゲームオーバーです.

プログラム全体の流れは,NNEnvironment.csを見て,出てくるクラスや関数の実装をそれぞれ見ていって,コメントなども読めばわかりやすいと思います.

また,Stage2では教師信号の与え方が良くないので台車が範囲内にとどまるようには学習できません.

これを改良することをまず目指せば,プログラムの全体がつかめると思います.


注意.
配布プログラムでは学習前にニューラルネットワークの事前学習を行っています.実行環境によってはプログラムの開始をしてから画面が動き始めるまで時間がかかるかもしれません.その場合はBrainオブジェクトのEnablePreTrainのチェックを外すか,PreTrainNumの値を小さくしてください.


(5-2) 自転車の形状進化

<概要>

遺伝的アルゴリズム(GA)を用いて、凹凸のある道を走破する車を設計するタスクです。

車はタイヤに常にトルクが加えられることで前進しますが、一定時間前に進めていなときに行動を終了します。より遠くまで進むことのできる車を生成するためにGAを用います。

車体の形状、タイヤの位置、タイヤの大きさ、タイヤに加えるトルクを遺伝子情報として与え、走行能力が高くなる組み合わせをGAによって探索します。


<ソースコードの概要>

EnvironmentとAgentは他のプログラムと似ていますが、Brainの代わりに遺伝子を表すGeneクラスが定義されています。そして、GeneOperatorクラスによってGeneクラスに対する処理を記述します。

主なスクリプトは以下の4つです。

  • GAEnvironment.cs

    • GA全体の流れを管理しています。他のプログラムにおけるNNEnvironment.csとおおよそ同様です。

  • CarAgent.cs

    • 車についての処理が実装されています。適応度の計算や個体の行動の終了判定、遺伝子に応じた車体の変形処理の呼び出しがなされています。

  • CarGeneOperator.cs

    • 交叉や突然変異など、Geneに対する遺伝的操作が実装されています。

  • GroundGenerator.cs

    • 学習が始まる前に凸凹道を生成します。


(5-3) ジャグリング

<概要>

手を模したキューブを動かして、ボールを落とさずに投げ続けることを学習します。

ニューロ進化とQ学習が実装されていますが、ニューロ進化推奨です。

投げるボールの数が1~3個でレベル分けされています。


<ソースコード>

自動運転と同じように、Agent、Environment、Brainで構成されています。

  • 状態(入力)

    • 両手の位置(4次元)

    • ボールの位置、速度({4 × (ボールの数)}次元)

  • 行動(出力)

    • 両手の速度(4次元)

    • 両手の掴むor放す(2次元)

※Q学習ではそれぞれの状態・行動を離散化します。


  • 主に編集すべきスクリプト(Assets/Scripts/)

  • JugglingAgent.cs

    • 観測できる状態・行動・報酬体系を変えたいときなど

  • Ball.cs

    • ボールから取得する状態を変えたいときなど

  • HandController

    • 手から取得する状態や行動の仕方を変えたいときなど

  • NEEnvironment.cs

    • (NE)エージェントから取得する情報やテキストに表示する情報を変えたいとき、個体の生成の仕方を変えたいときなど

  • QEnvironment.cs

    • (Q)エージェントから取得する情報やテキストに表示する情報を変えたいときなど

  • NEBrain

    • (NE)突然変異の仕方を変えたいとき、交配を実装したいときなど

  • QBrain

    • (Q)学習率など各種パラメータを変えたいときなど


<レベル>

レベルごとにシーンファイルを分けてあります。(Assets/Scenes/)

  • NE_Level1.unity ...... ボールが1個の場合で投げ続ける学習

  • NE_Level2.unity ...... ボールが1個で、間に高い仕切りがある場合で投げ続ける学習

  • NE_Level3.unity ...... ボールが2個の場合で投げ続ける学習

  • NE_Level4.unity ...... (発展)ボールが3個の場合で投げ続ける学習


自動運転(Python連携)について (担当TA : 須田)

できること

 ・基本的に現状でできることはPython連携していないものと同じです。

 ・ニューラルネットの計算部分・重みの更新部分をPythonで書くことができます。

 (・ニューラルネットワークの入出力の定義などは通常版と変わらずC#で書く事になります。)


試してみると良いこと

 ・ニューラルネットワークの部分をPytorchというライブラリで実装しているので、RNNやLSTMといった特殊な構造を持ったニューラルネットワークを構築しやすくなっています。

 ・まだ実装されてはいませんが、誤差逆伝播法(Back-Propagation)を用いた高度な学習も工夫次第で実装できます。


導入方法

 ・Unity側は、他のプロジェクトと同じようにダウンロードUnity上で起動してください。

 ・ターミナルでPythonのプログラムを起動するために、必要なPythonライブラリをインストールしてください。

・必要なライブラリとは、Numpy, PyTorch, asyncio-dgramです。


動かし方

 ・./self-driving-python.proj/Assets/Scenes/PythonNE/以下のシーンファイルを、Unity上で選択し、読み込んでください(まだ実行はしない)。

 ・ターミナルでPythonのプログラム(./self-driving-python.proj/env/src/PyNECommunicator.py)を起動してください。

 ・Unity上でシーンファイルを実行してください。

Unity等をインストールする際のトラブル例

  • Unityインストール時にライセンス認証ができない -> PCの日付設定が正しいか確認

  • External Toolsにvisual studio codeが出てこない -> Browseから探す

  • MacBook Airでうまく動かない -> バージョンを変更したらうまくいった例もある

  • Unity hubにプロジェクトを読み込めない -> 一回空のプロジェクトを作ってから読み込むとうまくいく