Zenn
👾

kaggle Lux AI Season 3 強化学習ソリューションまとめ+振り返り

に公開
2
1

はじめに

はじめまして!くるぴーといいます。

私は2024/12~2025/3の期間で、データサイエンスコンペティションのプラットフォーム kaggle で行われたシミュレーションコンペである Lux AI Season 3 に参加していました。
強化学習に興味がありゼロつく4で勉強していたこともあり、強化学習で銅メダル以上を目標としていました。かなりリソースを割いたのですが強化学習では全く歯が立たず、終了1週間前にルールベースに握り替えてなんとか銅メダルに滑り込むことができました。。

この記事では、簡単に本コンペの概要を説明し、公開されているソリューションのうち強化学習にフォーカスを当てて自分なりにまとめたのち、コンペ参加について振り返り次回の抱負(作戦?)を書きました。

コンペ概要

ルール

2位解法[1]の説明を引用し一部追記しています。

  • 各プレイヤーは最大16隻の艦隊を操作し、24x24のマップ上を移動してポイントを生成する遺物ノードを探します。

    対戦するマップ。青・赤が敵味方の艦隊

  • ゲームの目的は、3つのマッチで最初に勝利することです。各マッチの勝者は、100ステップ後に遺物ノードから最も多くのポイントを獲得したプレイヤーです。

  • フォグ・オブ・ウォー(戦場の霧)があり、各艦の周りの小さなエリア以外は見えないため、敵の動きを把握することはできません(自艦の近くを除く)。

    マップにおける青チームの視界。ユニットの周辺Nマスの視界が与えられます。Nはゲームごとにランダムに設定されます。

  • 艦隊は上下左右に動くか攻撃することができます。エネルギーを持ち、移動したり攻撃する/されるとエネルギーを失います。エネルギーがゼロになると、初期位置(左端 or 右上)に戻されてしまいます。

  • 各タイルにはエネルギーが -10~+10の値で設定されており、通過することでエネルギーを獲得もしくは失います。

  • 小惑星ノード(黒)は壁です。動くことができません。

  • 星雲ノード(紺色)はプレイヤーの視界を遮ります。また滞在するとエネルギーを失います。(失う視界の大きさやエネルギーはゲームごとにランダムに設定されます)

  • 小惑星ノード、星雲ノードは一定周期で右上か左下に1マスシフトします。また、エネルギー設定は一定周期で変更されます。(この周期はそれぞれゲームごとにランダムに設定されます)

  • 遺物ノード(中心が黄色で塗りつぶされたノード)の周辺2マスにはポイントノードがあります。

    • 遺物ノードは最初の3マッチの前半で1つずつ出現し、最大3つの遺物ノードが出現します。1つしか出現しない場合もあります。
  • ポイントノード(ノードの枠が黄色線)に艦隊が滞在することでポイントを得られます。ポイントノードはマップ上には表示されないため、獲得したポイントからポイントノードの位置を推定する必要があります。

    黄色で真ん中が塗りつぶされたノードが遺物ノード、ノードの枠が黄色線で囲われているのがポイントノード。遺物ノードの

  • 艦隊は次の3つの方法で、自艦隊のエネルギーを消費して敵の艦隊に攻撃することができます。

    • 敵艦隊と同じマスに止まる
    • 敵艦隊の隣のマスに止まる。
    • SAP。艦隊の周辺Nマスにビームが打てます。対象のマスには消費したエネルギーと同じダメージを、周辺1マスには消費したエネルギーに対して係数(0.25, 0.5, 1がランダムで設定)をかけたダメージが与えられます。

      赤艦隊が青艦隊にSAPを打っている。
  • ゲームごとにランダムに設定されるconfigの一部はプレイヤーに公開されません。自分でconfigを特定する必要があります。


銅solution(くるぴー)のゲーム

解法サマリー

  • 解法のバリエーション
    • 金圏は強化学習と模倣学習(Imitation Learning, LBに表示される上位プレイヤーのリプレイを取得しプレイングを学習する)で占めており、公開されている範囲ではルールベースアプローチはありませんでした。
    • 公開されている範囲で最も上位のルールベースは20位でした。
  • ルールベースが多かったLuxAI Season 2 と比較してルールがシンプルだったので、強化学習と相性が良かった、という意見もありました。[2]

解法

強化学習を使ったソリューションに絞って、解法を確認していきます。

強化学習アルゴリズム

主に3つのアルゴリズムが使われているようでした。

  • PPO (2nd[1:1])
    • 高い gamma値 (0.9999 ~ 1.0) を採用していたようです。
  • PPO with BPTT (Backpropagation Through Time) (10th[3])
  • IMPALA (1st[4], 6th[5])

memo

  • IMPALAはLux AI Season 1の1st solution[6]でも採用されています。(このチームのメンバーは本コンペでも2位)
  • 上位プレイヤーはライブラリを使わずスクラッチで実装しているようでした。(2nd[1:2], 10th[3:1])

報酬設計

最終的な勝敗を報酬とすることを基本として、学習の初期段階のみ追加の報酬を与えているチームもありました。

また、

  • 報酬が[-5, +5]に収まるように、過去バッチの報酬の平均から調整していたようです。 (1st[4:2])
    • ポイントの取得など学習の段階によって大きく変動する報酬があるためだそうです。(ただ、最終的にはポイント取得の報酬は採用していないので結局あまり意味がない?)

memo

  • 1st[4:3]はポイント獲得や敵へのダメージ、視界取り、等に対して様々な報酬を試したそうですが、最終的にはマッチ勝率のみの報酬設計になったようです。
  • 報酬をゼロサムにすることが重要なようでした。

ネットワーク

アーキテクチャ

  • ResNet + ConvLSTM + Transformer (1st[4:4])
    • アーキテクチャ図はsolutionを参照
  • ResNet (2nd[1:3], 6th[5:2])
  • 10th[3:3]は、SelfAttention, LSTM, Conv2d を使った複雑な構成を採用していました。
    • アーキテクチャ図はsolutionを参照
  • どのチームも初期は小さいネットワーク(~1M params)で試し、最終的には大きなネットワーク(1M~100M params)で学習して提出していたようです。
    • 単純に大きくすればするほど良いというわけでもなく、学習step数とパラメーター数のトレードオフを考えていたようです。
  • Transformerを使うことで学習の効率が上がったというコメントも見られました[1:4]

入力(特徴量エンジニアリング)

主に、ゲーム情報、チーム情報、マップ情報の3つが特徴量として入力されたようです。

  • ゲーム情報
    • ゲームステップやマッチステップ
    • ゲームコンフィグ
  • チーム情報
    • 敵味方の保有ポイント
  • マップ情報
    • ノード情報(遺物、星雲、エネルギー、etc...)
    • 敵味方の位置
      • 過去数ステップの情報も含む
  • 1st[4:5]は、既存情報から相当な特徴量エンジニアリングを行っていたようです。最終的には各タイルごとに1000以上の特徴量になったようです。
    • タイル上のユニットの所属チーム、敵を最後に観測したタイムステップ、タイルがレリックノード領域に属しているか、あるタイルを最後に観測してからの経過ステップ数、あるタイルで敵を最後に観測してからの経過ステップ数、など
    • 連続値については、正規化した連続値とbinningしたone-hotベクトルの両方でエンコードしたようです。
  • マップは点対称だったため、反転してすべてplayer0目線で学習させていたようです。(1st[4:6], 6th[5:3])

出力

各ユニットごとに、移動(上下左右+stayで5通り)と、SAP(最大周辺7マスに打てるので、15*15=225通り)の選択肢がある複雑な行動空間でしたが、上位プレイヤーは上手に設計していたようです。

  • 取れないアクションにmaskする処理(action masking)は全チーム行っているようでした。
    • 視界が取れていないところへのSAPを打たないmaskをしていたが、1stは視界が取れていなくても上手にSAPしていたことから、制限を弱めて「確実に無意味なアクションのみをmaskする」方がよかったかもしれないと語っていました (2nd[1:5])
  • 移動+SAPのアクションを決めるheadと、SAPが選ばれたときのみ使うSAP位置(15*15)を決めるheadから構成 (1st[4:7], 2nd[1:6], 10th[3:4])
  • 各タイルについて次ステップの予測を出力し、これを次のアクションヘッドに渡していました。(1st[4:8])
    • 敵ユニットがそのタイルにいる確率や敵の視野を予測対象としていました。
    • この学習は教師あり学習によって行われたようです。
  • シンプルに(16, 230)のアクション空間で学習を進めているチームもありました (6th[5:4])

自己対戦(self play)

  • 最新モデルと旧バージョンモデルからランダムに相手を決定。 (1st[4:9])
    • 最新モデルのみで学習することにより1つのプレイスタイルに過剰適応(過学習)させることを防ぎ、汎化性能を向上させる狙い。
  • 現在モデルと旧バージョンモデルのKLダイバージェンス損失、value headの出力を旧バージョンモデルにそろえる教師ベースライン損失、の2つを導入
    • 過去に学習したスキルの忘却を防止する狙い
  • 外部プレイのクローンとして過去のリプレイデータ(2nd team)を使って模倣学習したモデルと対戦 (1st[4:10])
    • このアプローチが無くても十分な改善が得られたので最終的には未使用だったようです。
  • 両方最新のモデルを使って自己対戦 (2nd[1:7])
  • 優先順位付き仮想自己対戦(PFSP)。旧バージョンのエージェントから対戦相手を選択する際に、現在のエージェントに対して勝率が高い相手を優先的にサンプリングする手法。75%は最新モデル同士で対戦させつつ、25%はPFSPを採用 (10th)
    • 難しい相手に重点的に学習することで停滞を回避する狙い。
    • AlphaStar の手法に着想を得たそうです。

提出モデルに使ったリソース

明記されていたもののみ、以下に記載します。

# solution training time model size training steps hardware
1 1st 3~4日 200M ? 8xH100
2 2nd 8日 300M*2(※) 10M 64GB RAM, AMD Ryzen 9950X, RTX3090+RTX2070Super
3 10th 7日 23B 3.2M 64GB RAM, AMD Ryzen 7950x, RTX4090

(※)自己対戦において両方のログを学習に使ったため

マップ推定

ポイントマップやエネルギーマップは該当のタイルに止まらないとわからず、かつ周期的に変更されるため、アルゴリズムによる推定が必要でした。

  • エネルギーマップは完全なランダムではなく一定の法則性を持ったアルゴリズムによって構成されるため、いくつかのタイルのエネルギーを知ることができればマップすべてのタイルのエネルギーを推定することができたそうです (2nd[1:8])

その他

  • 模倣学習を防ぐことと上位との対戦データを集めることを両立させるために、意図的に弱いモデルを混ぜたりノイズを加えたりしたようです (1st[4:11])
  • ゲーム環境を高速化するために、公式から提供されたゲーム環境コードをRustに書き換えたそうです (2nd[1:9])
    • 環境の計算に加えて、特徴量作成もRustで実装したようです。
    • マルチスレッドで動かすことで、環境の計算時間がほぼ無視できるようになったそうです。(圧倒的熱量を感じました...)
    • またテストも導入しており、ランダムな環境において公式実装と同じように動作するかを確認することで品質を担保していたようです。
    • 最終的なコードは Rust 約10800行, Python 約6500行 となったとか...
  • 上位チームのいくつかは、性能を監視するためにゲーム統計(アクションの頻度など)をwandbによってモニタリングしていました (1st[4:12], 2nd[1:10])

コンペ参戦振り返り

私は初めて強化学習をコンペで使ったので、コンペ参加を振り返っていきます。

良かったこと

  • step by step での検証を行ったことで、学習がうまく行かない時の原因絞り込みを比較的容易にできた
    • 強化学習が初めてだったので、自分で8x8のマップ+ランダムなポイントタイルを定義し、複数の艦隊を操作できることを確認していきました。
    • LuxAIで、敵は操作なし or ランダムにした状態で全情報をオープンにして学習が進むことを確認し、そのあと隠しても学習が進むことを確認した。
  • wandbによるゲーム統計の記録ができた。
    • 学習が進まない時に、なぜ進まないのかを定性的に分析し対策を打つことができた
  • 特徴量エンジニアリング
    • 終盤に 1st が実施しているような様々な特徴量エンジニアリングを試みたが、学習効率が明確に上がった

反省、難しかったこと

  • 初手にStable Baselines3を選んだ。
    • できないこと(selfplay)や計算効率が悪いところがあり、途中でかなりカスタマイズを入れた
    • スクラッチで組んでしまった方がよかったかもしれない…が、強化学習が何もわからない状態でスクラッチで組むと沼にハマりそうだったので仕方なし?
  • 並列処理をあきらめてしまった (致命的。。。)
    • Stable Baselines3 の枠組みだと環境を並列で動かすことが難しく、環境のステップは直列に、actionの推論のみバッチで束ねて行った。環境のステップも並列で行う施策をstable baselines3のフレームの中で1週間くらいちまちまとやっていたが断念してしまった。
    • 結果として、データ収集+学習で 10Mstep/dayくらいしか回収できなかった。上位は200M,300Mstep学習させたソリューションを実現していることから、闘いの土俵にそもそも乗れていない
  • 局所解的な対策を報酬によってコントロールしようとした。例えば、遺物を見つけてくれないから遺物ノードを見つけることに報酬を与えたり、ポイントマスに向かうことに報酬を与えてみたり…
    • 過去のソリューション(Lux AI 1, 2)はこういった細かい報酬を与えているのを読み実験していたが、上位ソリューションを見ると報酬空間はかなりシンプルだった。
    • 細かい報酬の設定は強化学習の可能性をつぶしてしまうと思う(そもそもあなたが設定したその報酬、本当にゲームの勝利に寄与しますか?1位になれますか?)
  • (上記と重複するが)報酬をゼロサムにしなかった。
    • どうやら報酬をゼロサムにするのは大事なよう。
  • 初めての強化学習ということもあり、フォーカスするべきポイントを見失ってしまった
    • 2nd placeのRLかなりシンプルな印象を受けた。ResNet, 普通の自己対戦, 勝ち負けのみの報酬。変に凝らなくてもやるべきことをやれば学習が進むのかもしれない。
    • 一方で、1st placeは様々な工夫が織り交ぜられていた。
  • step by step の step が遅すぎた
    • self-playにたどり着くのが遅すぎた。。
  • agentの性能評価に充てるリソースをケチって、データ収集時に取れる指標だけで性能を見積もっていた
    • データ収集時(=確定的でないアクション)の獲得得点や、selfplayの勝率を見ながら性能評価するにとどまった。
  • マップ推定アルゴリズムでバグを量産した。あちらを直せばこちらがバグるのもぐらたたき開発で無限に時間を溶かしてしまった。。

次のシミュレーションコンペで実践すること

  • RLはスクラッチで組む
  • データ収集効率には限界までこだわる
    • ここが弱いとそもそも勝負の土俵に立てない
    • (とはいえ、Rustで書くほどの覚悟はない...)
  • シンプルなアプローチを試みる
  • 報酬設計でエージェントをコントロールしようとし過ぎない
    • 学習初期のために補助的な報酬を設定するのは良いが、その調整に力を入れすぎない
  • 金圏狙うマインドを持つ
    • 今回は初回ということで成績にこだわらず強化学習を習得することにフォーカスしたが、次こそは・・・🔥
  • 今回のようにゲーム環境から情報を保持・推定する必要があるゲームがコンペになった場合は、ユニットテストを書く(書くくらいのリソースと覚悟がないなら出ない)
  • transformer を採用してみる
    • 1stのsolutionに採用されていた、かつ2ndでも「後半試したら良さそうだったが時間が足りなかった」とコメントがあった
  • 特徴量エンジニアリングは積極的に行う

最後に

強化学習で銅メダルという目標は達成できず悔しい思いをしましたし、バグにまみれて苦しい思いをたくさんしましたが、コンペの題材となったゲームはルールベースで取り組むにしてもとても面白かったです。また、新しいことを学んですぐに実践の場があるのがすごくありがたく、楽しかったです。運営の方には感謝の気持ちでいっぱいです。(何をしたらいいか見当つかなくて、kaggleを始めたての時を思い出しました)
「kaggleの任意のコンペで優勝」というひそかな目標があったのですが、これに加えて「kaggleのシミュレーションコンペで金」という新たな目標ができたので、これらが達成できるように引き続き頑張ります!

参考資料

脚注
  1. Frog Parade's Solution (2nd) ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  2. 2nd place solution の discussion ↩︎

  3. 10th Place Solution – Boey – End-to-End JAX RL ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  4. 1st place approach by Flat Neurons ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  5. EcoBangBang's Approach - Yet Another RL Solution (6th) ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  6. Toad Brigade’s Approach - Deep Reinforcement Learning ↩︎

1

Discussion

HaruiHarui

LuxAIや強化学習に興味を持っていたもののあまり手を動かせてなかった自分にとって、読んでいてすごく刺激的でした!!いいね100個くらいつけたいです😭

くるぴーくるぴー

あたたかいコメントありがとうございます、そういっていただけるととても嬉しいです😆
はじめてのシミュレーションコンペだっとこともあり最初はしんどかったですが、理解できるとめちゃくちゃ楽しくなってくるのでおすすめです。次のコンペでお会いしましょう!!

ログインするとコメントできます