エアホッケー

概要

エアホッケーでは, スマッシャーと呼ばれる器具を用いて盤上のパックを打ち合い, 相手のゴールに入れて得点を競い合います. 今回はAIにスマッシャーをコントロールさせます.
配布されているプログラムでは, 自分の位置, パックの位置, 敵の位置を入力とし, 自分の動作(速度ベクトル)を出力としたニューラルネットワークを差分進化で学習させます.

drawing

目次

ダウンロード

Google Driveのリンクからダウンロードし, 適当なフォルダで展開してください. その後, Unity HubのOpenから展開した.projフォルダを開いてください.

Google DriveにはUnityのライブラリは上げていませんが, Unity Hubで開く際に自動的に生成されます.

macOS, Unity 2021.3.1f1以外で開く際には警告が出ますが, 警告に従ってバージョンの変更やパッケージのインストールなどをすれば以下の環境では動作することを確認しています.

動作確認

macOS Monterey 12.4
Windows 10
Windows 11
Unity 2021.3.0f1
Unity 2021.3.1f1
Unity 2021.3.3f1

アルゴリズムの説明

差分進化(Differential Evolution, DE)は1995年に発表されたメタヒューリスティクスであり, 最適化手法の中でも強力な方法のひとつとして知られています. 差分進化では以下のようなアルゴリズムを用います.

  1. 個体をランダムな値で初期化します.

  2. Mutation
    親となる個体x1\vec{x_1}をランダムに選びます. また, 個体をもう2つランダムに選んで x2\vec{x_2}, x3\vec{x_3} とします.

  3. Crossover
    差分ベクトル F(x3x2)F (\vec{x_3} - \vec{x_2}) を計算し, 親 x1\vec{x_1} にこの差分ベクトルを足したものを子供とします.

    xchild=x1+F(x3x2)\overrightarrow{x_{child}}=\vec{x_1}+F(\vec{x_3}-\vec{x_2})

    ここで、FFはスケーリングパラメータと呼ばれる定数です.

    2.と3.を繰り返し, 決められた個数の子供を生成します.

  4. Selection
    親と子を比較し, 優れている方を残します.

  5. 1.~3.を繰り返します.

スケーリングパラメータFFが大きいと大ぶりな探索となり, 探索は早くなりますが収束が不安定になります. 差分進化について詳しくは参考文献などを参照してください.

ソースコードの概要

このプログラムでは個体それぞれが行動を決定するニューラルネットワーク(NN)を持っています. また, NNは1列の実数の配列(DNA)としても保存されています. このDNAをベクトルとして上記のCrossoverなどの演算をしています.

差分進化の管理はDEEnvironmentが行っています.

Mutation, Crossover

まず, DEEnvironmentが個体1, 個体2, 個体3をランダムに選びます. それぞれのDNAをx1\vec{x_1}, x2\vec{x_2}, x3\vec{x_3}とします. DEEnvironmentNNBrainx1\vec{x_1}, x2\vec{x_2}, x3\vec{x_3}を送り, NNBrainxchild=x1+F(x3x2)\overrightarrow{x_{child}} = \vec{x_1} + F (\vec{x_3} - \vec{x_2})を計算します. これが子供のDNAとなります.

なお, この実験では交叉率crossrateが定められており, その割合の子供が新しいDNAを持ちます. その他の子供は親のDNAをそのまま引き継ぎます.

これを繰り返し, 子供を生成していきます. 現在は100個の子供を生成する設定になっています.

対戦 (Selection)

DEEnvironmentHockeyAgentを呼んでボードの状態やプレーヤーの位置などの情報を取得し, その情報をNNBrainに送ります.

NNBrainは個体のNNの情報を持っており, 受け取ったボードの状態と個体のNNを使ってプレーヤーが次に取るべき行動actionを計算して返します. このプログラムでは, actionはプレーヤーの速度ベクトルとして伝えられます.

DEEnvironmentは返ってきたactionHockeyAgentに送り, 実際にその行動を取るように指示します.

HockeyAgentは受け取ったactionHockeyPlayerに送り, 実際にUnity上でプレーヤーの位置を移動させます.

最後に, HockeyAgentはボードの状態をもとに個体に対して報酬を与えます. 報酬の値は現在以下のように決まっています.

この操作を繰り返すことで対戦が進んでいきます. 時間切れになると対戦が止まり, 2つの個体の報酬値が決まります. これを繰り返し, 全ての個体についての報酬値が決まります.

最後に, 全ての個体について親と子の報酬値を比較し, 子供の方が高い場合は子供, そうでない場合は親のDNAを残します.

各コードについての詳細

Unity Editor上での操作説明

Sceneの実行

ProjectタブのAssets > ScenesからHockeyGameをダブルクリックして開きます.

gameinterface

画面上部の再生ボタンを押すと学習が始まります. 学習中にはGame画面に表示されるスライダでプログラムの実行速度を調整できます. コンピュータへの負荷を少なくしたい場合は、描画をオフにすることもできます。

gameinterface

ManualPlay

ManualPlayがオフであればPlayer1とPlayer2が対決しそれぞれが学習します(Populationが2ずつ増えるのはこれが理由です)。ManualPlayをオンにすると, その時点までに学習したNNのうち最も成績が良かったNNが制御するComputerPlayerとプレーヤーがキーボードなどで操作するManualPlayerが対決します.

パラメータの設定

Hierarchy > Environmentを選択すると, 以下の画面が表示されます.

パラメータ 説明
Total Population 1世代ごとの個体数
Mutation Scaling Factor スケーリングファクターF(上述)
Cross Rate 交叉率(上述)
Input Size 入力レイヤの大きさ(6)
- 自分のx座標
- 自分のz座標
- 自分とパックのx座標の差
- 自分とパックのz座標の差
- 相手のx座標
- 相手のz座標
Hidden Size 隠れレイヤの大きさ
Hidden Layers 隠れレイヤの数
Output Size 出力レイヤの大きさ(2)
- 移動の速度ベクトルのx成分
- 移動の速度ベクトルのz成分
N Agents 2 (同時に対戦するプレーヤー数, 2で固定)
Waiting Flag
Restart Flag
Manual Mode Flag
Agentによって試合の管理に利用される変数です

また, Hierarchy > Player1, Player2を選択すると, 以下の画面が表示されます.

パラメータ 説明
Max Speed プレーヤーの動くことができる速さの上限です.
Max Battle Time 試合時間の上限です

困ったら

参考文献