← ラボノート

決定論的なゲームはネットワークに屋上の走り方を教えられるか?

Skyline Runには決定論的な屋上の地区がありますが、機械による完璧なクリアが証明できるのは、ルールと形状が一致していることだけです。プレイヤーが教訓を読み取れるかまでは分かりません。前回の制作記録ではそのクリアを計測しました。今度は、方法を教えなくてもプレイできる何かが必要です。

そこで、Skyline RunAIラボを作ります。選択可能な技能段階を持つニューラルネットワークがブラウザ内で地区を学びます。遺伝的アルゴリズムまたは深層Q学習で訓練し、1×から最高速度まで動きを観察できるほか、表示を完全に隠して訓練を高速化できます。

ところが、最初のネットワークが走る前に環境のほうが動きました。チェックポイント、最難関の隙間、スタミナ回復が変わり、整然とした訓練計画は、観測と報酬がまだゲームを正しく表しているかを問う検証へ変わりました。

以下の数値は、計測値と明記したものを除き、最初の訓練前に私が選んだ値です。後半の地区再調整に関する節は、全体が計測結果です。この区別によって、計画がどこで終わり、証拠がどこから始まるかを示します。

半透明のシアンのワイヤーフレームで描かれたランナーが、ネオンの屋上街区のさまざまな地点に散らばり、ジャンプ中の個体や倒れた個体が、同じ街区へ挑むエージェントの集団を表しています。
一つの世代が同時に街区を走りますが、その大半は最初の数秒で失敗します。

このサイトとAI Maker Labチャンネルは私が所有し、制作しています。これは制作記録であり、第三者による独立したレビューではありません。

エンジンはすでに訓練環境だった

エンジンには、機械学習にとって最も重要な性質がすでにあります。そして偶然そうなっています。step(state, input, level)は、固定したDT = 1/60で動く純粋関数です。新しい状態を返し、引数を一切変更せず、DOMにも触れません。ゲームプレイ用のタイマーはすべて整数のティックカウンターです。

これは強化学習環境です。決定論的で、レンダリングに依存せず、CPUが許す限り速く進められます。レンダラーは状態を描画する独立したモジュールであり、状態を生成するためには一切必要ありません。このエンジンで訓練するために、ゲーム側を何も変更する必要はありません。この点は明言する価値があります。「AI用のフックを追加する」という誘惑こそが、エンジンを腐らせるからです。

その土台の上に、次の要件があります。

  • 複数の技能段階を持つエージェント。目的は最適なランナーを一体作ることではなく、プレイヤーを模擬することだからです。
  • ページの応答性を保つため、Web Worker内で実行するブラウザ内訓練。
  • 強化学習と遺伝的アルゴリズムという二つの訓練方式。両者は異なる形で失敗し、その比較が興味深い部分だからです。
  • ファイルとしてダウンロードし、再び読み込めるモデル。
  • 速度を制御できる表示モードと、何もレンダリングしないヘッドレスモード。
  • 損失、適応度、報酬、進行度のリアルタイム分析。

調査によって三つの推測が消えた

推測するのではなく調べる価値があった問いは三つです。Q-learningを安定させる方法、ニューロエボリューションの個体群をどの程度の規模にするか、そしてエージェントがどの程度の頻度で判断できるようにするかです。

Q学習には二つの補助が必要で、どちらも譲れません。 一つ目は経験再生です。過去の遷移を蓄えたバッファから再抽出し、最新の一手だけで学ばないようにします。そのバッファからランダムなミニバッチを抽出すると、参照実装の表現では「データ間の相関がなくなり、データ効率が向上します」。二つ目はターゲットネットワークです。予測目標に使う複製をゆっくり更新し、訓練が自分自身を追いかけないようにします。この複製はCステップごとの更新まで固定します。同じ調査から、追加コストなしで採用できる点がさらに二つ得られました。バッファに少なくとも一つのバッチが蓄積するまで勾配更新を行わないこと。そしてDouble DQNを使うことです。稼働中のネットワークで行動を選び、ターゲット側の複製で評価すれば、一行のコードで系統的な過大評価を取り除けます。

ここでニューロエボリューションは正当な代替手段であり、玩具ではありません。 勾配を使わない遺伝的アルゴリズムは、Atariや人型の移動課題で、深層ネットワークの重みを競争力のある水準まで進化させられることが示されています。この制作で魅力を感じた構造上の要点は、ニューロエボリューションでは「ネットワークの訓練は各フレームではなく、エピソードの間にだけ行われる」ことです。これは個体発生的、つまり一度の生涯で学ぶ手法ではなく、系統発生的、つまり世代をまたいで学ぶ手法です。ブラウザ内のラボにとって、この性質は大きな利点です。一世代すべてを同期してシミュレーションし、集団として描画できるからです。個体数の経験則は50–200体付近に集中しています。良いゲノムを不運な偶然で失わないよう、エリート保存では上位の個体を変異させずに残すべきです。また、変異確率には上限があります。ある研究では、変異率の上昇とともに性能が向上した後、およそ0.03を超えると低下すると報告されています。一方、適応型の方式は5%前後です。

判断頻度は、そうでなくなるまでは無料の高速化です。 フレームスキップでは、エージェントがkフレームごとに観測し、その間は同じ行動を繰り返します。これは「実効的なホライズンを比例して短く」し、高水準の操作を、指数関数的に起こりにくいものではなく、ランダム探索でも到達可能なものにし、順伝播の回数を減らします。ただし、既知の失敗もあります。スキップしすぎると行動を続けすぎ、正確な狙いが必要な課題の性能が落ちます。k = 4が一般的に挙げられる妥協点です。

明白に見える選択に逆らったのは、数学ライブラリだけです。 ブラウザ内の機械学習ならTensorFlow.jsが標準的な答えで、WebGLバックエンドは確かに強力です。テンソルをテクスチャとして、演算をシェーダーとして扱います。しかし、この規模では利点になりません。後から実際のコンストラクターを実行して計測すると、[119, 48, 8]ネットワークのパラメーター数は正確に6,152でした。内訳は119×48 + 48 = 5,760、続いて48×8 + 8 = 392です。演算ごとのディスパッチにかかるオーバーヘッドが計算量を上回り、シミュレーション上の1秒につき数十回、順伝播のたびにGPUとの往復を行うことは、かえって性能を悪化させます。このラボでは、Float32Arrayによる手書きの行列演算、手動の誤差逆伝播、Adamを使います。この規模ではより速く、依存関係がなく、workerへ容易に移せます。保存モデルには生の重みを格納するため、この判断は後から戻せます。将来ライブラリへ置き換えても、変更するのは二つのファイルだけで、ファイル形式は変わりません。

訓練の契約を数値で決める

観測の契約は、地区全体を見せずに役立つ局所情報を与え、前方を重視したタイルウィンドウと移動状態を119個の浮動小数点数にまとめます。

観測。 119個の浮動小数点数を、判断のたびに再利用するバッファへ再構築します。そのうち108個は、プレイヤーの中心タイルを囲む12×9のタイルウィンドウです。後方2タイル、前方9タイル、上方4タイル、下方4タイルを含みます。各タイルは一つのスカラー値に符号化します。固体は1、一方向の足場は0.5、チェックポイントは0.25、ゴールは0.75、危険物は-1、空白は0です。レベルの下端より下はすべて-1として読みます。穴も棘も同じ信号に値するからです。向きに応じてウィンドウを反転させることはしません。この街区ではゴールが常に右にあり、反転させると、レベルには存在しない対称性を装うことになります。

残りの11個は、タイルウィンドウだけでは表せない状態です。水平速度と垂直速度、接地フラグ、コヨーテカウンター、ダッシュタイマー、ダッシュのクールダウン、ダッシュエネルギー、向き、タイル内のxとyのオフセット、ゴールまでの正規化した距離です。二つのタイル内オフセットが必要なのは、16 pxのグリッド上にいる12×20 pxのプレイヤーが、同じ一つのセル内でも実質的に異なる位置に立てるためです。

タイルグリッド上の小さな長方形のプレイヤーに半透明の観測ウィンドウを重ね、後方2タイル、前方9タイル、上方4タイル、下方4タイルまでを示しています。
エージェントは前方へ重みを置いた周囲12×9タイルと、グリッドでは表せない11個のスカラー値を観測します。

行動。 独立した四つのボタンではなく、八つの離散的なフレームを使います。待機、右、右+ジャンプ、右+ダッシュ、ジャンプ、左、左+ジャンプ、右+ジャンプ+ダッシュです。Qネットワークには離散的な集合が適しており、この八つで街区の操作語彙を網羅できます。一つの影響は意図したものです。エンジンは前のフレームに対するジャンプ入力の立ち上がりを検出するため、エージェントがもう一度ジャンプするには、判断の間にジャンプを離さなければなりません。ボタンを永遠に押し続けても、繰り返しジャンプすることはできません。これは人間の手にもある制約です。

判断間隔:3 ticks。 引用したk = 4よりわずかに短くしています。定数はCOYOTE_TICKS = 6BUFFER_TICKS = 7ですが、後から実行して計測すると、どちらにも実際に使える猶予は5 ticksありました。コヨーテジャンプは足場を離れて5 ticks後なら成功し、6で失敗します。一方、バッファ入力は着地の5 ticks前なら成功し、6で失敗します。3-tick間隔なら、理想的な任意のティックに対して最大でも2 ticks遅れるだけであり、計測したどちらのウィンドウ内にも3-tickの余裕が残ります。1秒あたり20回の判断は人間の入力頻度に近く、それでも順伝播の回数を3分の2減らします。

技能段階は、訓練に組み込むハンデです。 この判断には疑問が向けられると予想しているため、理由を説明します。弱いAIを作る安易な方法は、強い方策を一つ訓練してから、その出力を壊すことです。それでは下手なプレイヤーではなく、けいれんする上手なプレイヤーができます。代わりに、各段階を訓練中から存在する環境の性質にします。FIFO入力キューで実装する反応遅延と、ランダムな行動へ置き換える確率です。

段階反応遅延行動ノイズ
初心者9 ticks10%
一般5 ticks5%
熟練2 ticks2%
達人0 ticks0%

初心者のネットワークは、150 ms遅れて反応し、10回に1回は入力を誤りながらプレイを学びます。壊した達人の行動ではなく、より慎重で、隙間を越えるタイミングが悪いといった、その制約を生き残る行動を身に付けるはずです。本当にそうなるかが、最初に計測する価値のある点です。

遺伝的アルゴリズム。 個体数は64です。文献で挙げられた50–200の範囲内であり、集団として描画できる程度に小さくしています。上位4個のゲノムは変異させずに残します。親は3者トーナメントで選びます。子の75%は一様交叉、残りはクローンです。その後、子の各重みに0.08の確率でσ 0.12のガウス分布から得た値を加えて変異させ、±4に制限します。変異率は、ある研究が報告した0.03の上限より高く、適応型方式の5%に近い値です。未調査の問題に対する最初の実行では探索を重視するという意図的な偏りであり、最初に下げると予想しているハイパーパラメーターでもあります。

適応度は、最も遠くまで進んだ距離に、チェックポイントごとに250、クリアで1,500、さらに3,600 ticksの上限までに使わず残った各ティックの半分を加え、死亡ごとに100を引きます。進行度には現在位置ではなく、常に最高進行度を使います。死亡して再開したことが、後退として評価されないようにするためです。

深層Qネットワーク。 ここでは即時の更新より安定性を優先します。γ 0.99、学習率1e-3、バッチ64、再生容量20,000、1,000遷移が保存されるまで勾配更新なし、訓練500ステップごとにターゲットをハード同期、εを50,000判断かけて1.0から0.05まで線形に減衰、選択した行動の出力だけにδ 1のHuber損失を適用します。Huber損失は、誤差がゼロに近いときは二乗誤差を使い、誤差が大きくなると線形へ切り替わるため、外れ値に支配されません。すでに勾配を制限するので、別のクリッピング処理は行いません。

判断ごとの報酬は、新しく進んだタイル数、チェックポイントごとにプラス2、クリアでプラス20、死亡でマイナス2、時間コストとして判断ごとにマイナス0.01です。エピソードは、クリア時、3,600 ticks、8回の死亡、または360 ticksの間に最高進行度が4 px以上伸びなかったときに終了します。最後の条件が停滞検出です。これによって、見込みのない64体の一世代にかかる時間を、数分ではなく数秒にできます。

アーキテクチャ。 一つのworkerがトレーナーを持ちます。メトリクスイベントは常に送信し、フレームのスナップショットは表示モードのときだけ、16 msにつき最大一つ送信します。速度制御はworker側のペーシングです。固定倍率では、実時間のアキュムレーターに対して速度 × 60 ticks毎秒を目標にします。最高速度では、12 msの処理を連続して実行します。ヘッドレスモードは「レンダリングを省略する」という意味ではありません。workerはフレームを一切送りません。エンドツーエンドテストではフレーム数が正確にゼロであることを検証します。性能向上モードを名乗りながら、密かに状態をシリアライズし続けるのは嘘だからです。

二つの抽象的な訓練過程を並べ、一方では多数の同じ姿が波のように同時に前進し、もう一方では一つの姿から出たフィードバックループが自分自身へ戻っています。
遺伝的アルゴリズムは一世代全体を同期して評価し、Qネットワークは自分自身の再生された遷移から学びます。

モデルは、aml.skyline-run-aiというタグとバージョン1を付けたJSONとして保存します。アルゴリズム、技能段階とそのパラメーター、観測の形状、行動数、各層のサイズ、生の重み、訓練の累計を保持します。読み込み時にはすべてを検証し、不一致なら、もっともらしく見える誤った答えを出すのではなく、エラーとして拒否します。異なる形状の観測ウィンドウでも数値としては問題なく読み込めますが、その動作はノイズになります。

訓練開始前に地区が変わった

上記の判断は最初の訓練を実行する前に確定しました。その記録を書いた後、訓練開始前にゲームが変わりました。この節のすべては後から行った計測であり、別の選択値ではありません。スタミナは現在、接地して走っている間は48 grounded running ticksごとに1目盛り回復し、接地して待機している間は96 grounded idle ticksごとに1目盛り回復します。列116に新しいチェックポイントが設置されました。連続ダッシュで越える隙間は10 tilesから9 tilesへ狭まりました。計測した決定論的な最適クリアは2218から1304 ticksへ短縮しました。

観測ホライズンの結果が最も重要です。タイルウィンドウは前方9 tilesまで届きます。プレイヤーの中心タイルが列121になる発進タイルからは、列130までを覆います。着地側の足場で最初の固体タイルは列131にあり、ウィンドウの外です。最前列の1309セルすべてが0として符号化され、何もない空間とまったく同じです。

足場が初めてウィンドウに入るのは、中心タイルが列122に達したときです。隙間に1タイル進み、プレイヤーはすでに空中です。再調整前は足場が列132から始まり、中心タイルが列123、つまり隙間に2タイル進んだ時点で初めて見えました。街区で最も難しい操作は、着地先が見えないまま確定します。再調整によって、その見えない余白は2 tilesから1へ縮まりました。前方の到達距離を広げる修正には代償があります。保存モデルの観測メタデータに組み込まれているため、変更すればこの契約で既に訓練したすべてのモデルが無効になります。

チェックポイントは停滞検出の意味も変えます。以前の列80のチェックポイントから発進タイルへ戻るには276 ticks、つまり360-tickの停滞ウィンドウの76.7%がかかります。リスポーンを含めると294 ticks、つまり81.7%です。新しい列116のチェックポイントから戻るには36 ticks、つまり10.0%がかかり、リスポーンを含めると54 ticks、つまり15.0%です。maxPxはこれまでの最高進行度であるため、帰路のどこでも増えません。エージェントがまさに正しい行動を取っている間も、停滞タイマーはずっと進み続けます。見込みのないエージェントを打ち切るための検出器が、街区で最も難しい操作では、それを学びつつあるエージェントまで打ち切りかねない状態でした。

計測項目再調整前再調整後
完全クリア時のGA適応度6,315.677,022.67
GAの速度成分6911,148
エピソード上限 / 最適経路1.62×2.76×
最適経路でのクリアごとのDQN判断回数740435
最適経路でのDQN累積時間コスト-7.40-4.35

完全クリア時のGA適応度は707、つまり11.2%上昇しました。追加したチェックポイントによる増加が250、クリアの高速化による増加が457です。追加したチェックポイントはDQNのクリアごとに+2の価値を持ち、判断回数の減少によって表の時間コストも小さくなります。再調整前後の適応度は比較できません。難度緩和前のベースラインはすべて無効です。

回復方法の変更は隠れ状態を導入します。11個のスカラー値にはダッシュエネルギーがsp / SP_MAXとして含まれますが、回復アキュムレーターは含まれません。以前の一律72-tickルールでは、この省略によって一定の時計が隠れていました。二つの回復速度を使うルールでは、アキュムレーターの進む速さが、エージェント自身の直近の入力によって決まります。実行した結果、アキュムレーター値が094でありながら、ビット単位で同一の119-float観測になる状態が得られました。このエンコーダーはアキュムレーターをまったく読み取らないため、値だけが異なる任意の二つの状態は衝突します。094は次のスタミナ1目盛りまでそれぞれ96 idle ticks2 idle ticks、つまり94 engine ticks離れています。極端な095ではそれぞれ96 idle ticks1 idle tickとなり、差は95 engine ticksです。これはゲーム設計の変更によって生じた部分観測性であり、記憶もフレームスタッキングもないフィードフォワードネットワークからは見えません。正直な選択肢は、アキュムレーターを12番目のスカラー値として追加して保存モデルの観測契約を破るか、それを省いたまま、ネットワークから見えない行動を手掛かりにスタミナのタイミングを推測しなければならないと受け入れるかです。

設計で証明できたことと訓練で確かめること

まだ何も訓練していません。元の意思決定値は、文献とエンジンで計測した定数から定めた出発点のままです。前回の制作記録を残した主な理由は、慎重に根拠を考えた三つの値が、実際に動くシステムへ触れた途端に誤りだと分かったことでした。修正が必要になると予想しているものは、引き続き変異率、3-tickの判断間隔、報酬の時間コストです。観測ウィンドウの前方到達距離も、すでに反証となる計測結果を伴って、その一覧に加わりました。

最初に検証したい具体的な主張は、技能段階に関するものです。ハンデの下で訓練すれば、同じプレイを一律に悪化させたものではなく、見て分かるほど異なるプレイが生まれるはずです。初心者ネットワークの走りが、途切れを加えた達人の走りに見えるなら、設計が間違っています。段階ごとの差はノイズだけでなく、構造的なものにする必要があります。

すでに、解決せず受け入れている既知の制限が二つあります。タイムアウトまたは停滞検出で終わったエピソードは、終端遷移として保存します。厳密には正しくありません。これらは打ち切りであり、そこからブートストラップした価値推定はわずかに悲観的になります。また、レベルは一つしかありません。一つの街区をクリアするエージェントは、一つの街区を記憶しただけです。失敗できる二つ目の街区ができるまで、汎化は検討の対象になりません。

このラボはプレイヤー調査でもありません。測るのはルールを学習できるかであり、人がルールを理解できるかという問いより狭く、機械的です。計測は前回と同じ理由で残します。次の仮定が崩れたとき、何が変わったかを示すためです。

したがって、出発点の値が正しいと決めたわけではありません。決めたのは、決定論的なエンジン、明示した訓練契約、計測済みの留保によって、その正否を検証できるということです。次のトレーナーを教える:報酬を手調整せず進化させるでは、私が係数を手で回す代わりに、進化そのものに報酬を調整させるべきかを問います。

出典

このサイトとAI Maker Labチャンネルは私が所有し、制作しています。これは制作記録であり、第三者による独立したレビューではありません。

あわせて読む