Kaggle · Pokémon TCG AI Battle

ポケカコンペで
始める強化学習

羽鳥冬星
6,807 teams · 33rd
01 / 27

コンペの概要

Intro

本物のポケモンカードのルールを実装した対戦シミュレータの上で、参加者のプログラム同士を戦わせる。主催は The Pokémon Company。順位はスコアではなく、参加者どうしを自動で戦わせ続けて算出するレーティングで決まる

6,807

終了した Featured コンペ313本のうち3番目に大きい

5.8倍

エージェント同士を戦わせる形式では歴代最大。2位は Lux AI の1,178

2週間

提出を締めたあとも自動対戦が続き、その時点のレーティングで確定する

締切時点の順位は、最終順位ではない。この最後まで動き続ける性質が、あとで出てくる評価の難しさに全部つながる

02 / 27

ルールと、提出するもの

Intro

勝ち負けの決まり方だけ押さえておく。サイドを6枚取ったほうが勝ちで、この枚数があとで報酬を作るときの手がかりになる

1
ワザで相手のポケモンにダメージを与える
→
2
きぜつさせたらサイドを1枚取る
→
3
先に6枚取り切ったほうが勝ち
シミュレータ(ポケカのルール)
自分のプログラム(提出するもの)
いまの盤面と、選べる手のリストを渡す
▶
◀
その中から番号を1つ返す
ポケモンカード対戦のリプレイ
公式ビューアで見た実際の対戦。
サイドを取り切って決着する瞬間
×約90回

1試合でこのやりとりが自分の側で約90回。合計600秒(CPUのみ)を超えたり、エラーを出すと負け

03 / 27
01
Part I

強化学習の用語

状態、行動、報酬、方策を、ポケカの盤面に置き換える

04 / 27

強化学習の用語

Part I

やってみて、うまくいったやり方を増やす。出てくる言葉は4つだけで、3つは普段の教師あり学習にそのまま対応する

用語
状態 s
いま目の前に見えているもの
場のポケモン、残りサイド、自分の手札。相手の手札は見えない
特徴量。1件ぶんの入力
行動 a
いま選べる手のうち、どれをやるか
「ワザを使う」「エネルギーをつける」など、ルール上できる手から1つ選ぶ
推薦モデルでいう item
報酬 r
うまくいったら◯、だめなら✕
勝ったら +1、負けたら −1。試合が終わるまでもらえない
教師ラベル。ただし1件ごとには付かない
方策 π
「この場面ならこの手」という作戦。打ち方
モデルそのもの。盤面を見て、選べる手それぞれに点数をつける
モデルそのもの

対応が崩れるのは報酬だけである。教師あり学習ならデータ1件ごとに教師ラベルが付くが、こちらは1つも付かないまま試合が終わる

05 / 27

取れる手とモデルの関係

Part I

モデルは手を思いつかない。できる手の一覧はルール側が作る。モデルはその一覧に点数をつけて1つ選ぶだけである

自分のアクティブ:リザードン HP 180
ベンチ:2匹
手札:炎エネルギー、ボール、進化カード
相手のアクティブ:HP 60
残りサイド:自分 4、相手 3
→
ワザ「かえんほうしゃ」を使う
0.12
炎エネルギーをつける
0.61
ボールでポケモンを探す
0.18
ベンチのポケモンを進化させる
0.07
番を終わる
0.02

点数はそのままその手を選ぶ確率になる。学習中はサイコロを振って選び(たまに新しい手を試す)、本番では一番高い手を選ぶ

反則の手はそもそも一覧に入らないので、原理的に出せない。候補は平均13個、多いときは19個以上。学習とは、この点数を動かすこと

06 / 27

教師あり学習との違い

Part I

前のページの4つのうち、素直に対応しなかったのは報酬だった。そこから違いが2つ出てくる

1
正解が存在しない

画像分類なら「これは猫」と答えがついている。ポケカの盤面に「この手が最善」という答えは誰も持っていない。環境が返してくるのは、約90手を打ち終えたあとの勝ち負け1つだけである

強い人の手を正解とみなして真似ることはできる。ただし、その人の上限まで
2
学習データが、
自分の打ち方から生まれる

教師あり学習のデータセットは、学習しても中身が変わらない。こちらは自分で対戦して初めてデータになる。打ち方が変われば出会う盤面も変わるので、集め直し続けることになる

だから、一度に大きく変えられない

1つめには採点の基準を自分で作って手当てし、2つめには更新の幅に上限を置いて手当てする

07 / 27

学習の段取り

Part I

学習は2段構えで、使うデータが段ごとに違う

1
公式が毎日公開する
上位プレイヤーの対戦リプレイ
同じ盤面で同じ手を選べるように当てる練習
(模倣学習)
上位プレイヤー並みに打てる
(その人の上限まで)
2
そのモデル同士を戦わせて
自分で作る対戦記録(自己対戦)
勝った試合の打ち方を増やす
(強化学習)
真似を超えるモデル

他人のリプレイを使うのは1段目だけ。2段目の記録は全部自分の対戦から作る(=自己対戦。この練習相手の集まりを、あとで「リーグ」と呼ぶ)

08 / 27

学習の一周

Part I

2段目でやることは、この一周を繰り返すだけである。①と②で対戦の記録を作り、③でその記録を1手ずつ採点し、④で方策を更新する

①
自己対戦する
いまの方策どうしで約1,000試合
→
②
記録がたまる
盤面、打った手、勝ち負け
→
③
critic
1手ずつ採点する
どの手が good でどれが bad か
→
④
PPO
方策を更新する
good な手の確率を上げ、bad を下げる
→
⑤
少し強い方策
これで①に戻る
▲
一周ごとに記録は捨てて作り直す。方策が変わると、前の記録は当てにならなくなる

難しいのは③である。勝ち負けしか返ってこないのに、どう1手ずつ採点するのか

そして④。方策をどれだけ動かしてよいのか

09 / 27

1手ずつの採点

Part I

教師あり学習なら、データ1件ごとに教師ラベルが付く。ポケカの1手には付かない。返ってくるのは、約90手を打ち終えたあとの勝ち負け1つだけである

1手目
基本エネルギーをつける
2手目
たねポケモンをベンチに出す
39手目
「博士の研究」を使う
(本当は悪手)
…
約90手
最終手
ワザで倒す
勝ち
→ 全部 +1
1手目
基本エネルギーをつける
2手目
たねポケモンをベンチに出す
39手目
「ナンジャモ」で引き直し
(本当は好手)
…
約90手
最終手
倒される
負け
→ 全部 −1

1つ1つの箱が打った手。勝ち負けは試合単位でしか返ってこないので、同じ点数が全部の手に配られる。勝った試合にも悪手はあり、負けた試合にも好手はある

1手ごとに分けて教えたい。ただし「この手が最善」という教師ラベルは誰も持っていない

だから教師ラベルの代わりに、何を良しとするかを自分で決める。それが報酬である

10 / 27

報酬をどこに置くか

一周の ②  /  Part I

教師ラベルが付けられないので、外から与えられるのは報酬だけになる。何を良しとするかの定義が、そのまま方策の目標になる。本命は勝ち+1、負け−1で、これは試合が終わる最後の1手にしか入らない

手 1
−0.05
取られた
+0.05
サイドを1枚取った
+0.05
+0.05
+1
試合終了。6枚取り切って勝ち
(負けなら −1、引き分け 0)
途中点はサイドが動いた手に
勝敗は終局の1手にだけ

勝敗だけだと、序盤の手が良かったのか悪かったのかを言う材料がない。サイドが動いたところで小さく点を入れておく

途中点は「増えた分 − 減った分」の形なので、試合を通した合計は0。成績の出方が早くなるだけで、目指すゴールはずれない

11 / 27

報酬の配合

一周の ②  /  Part I

学習が最大化するものを1本の式で書くと、こうなる。足しているのは4つで、そのうち3つが報酬、残る1つだけ位置が違う

J(θ) = 𝔼[ Σt γt ( ①zt − ②0.002 + ③0.3(γΦ′ − Φ) ) ] − ④β · KL( πθ ‖ πBC )
𝔼[ ] は多数の試合にわたる平均、Σt は1試合の全部の手にわたる和
z は勝ち +1、負け −1、引き分け 0
Φ =(相手の残りサイド − 自分の残りサイド)/ 6、終局では 0。Φ′ は1手あとの値
γ = 0.997 は割引率。t 手あとの報酬を γt 倍に縮めて数える(先の報酬ほど軽い)
①勝敗
±1

入るのは試合の最後に1回だけ。学習では、この1つが割引されながら手前の手にも配られる

②ターン数
−0.002

1手ごとに定額で引く。90手なら合わせて 0.18 ほど(割引ぶん少し小さい)。同じ勝ちなら短いほうがよい

③サイドの残り枚数の差
±0.05

係数 0.3 をサイド6枚で割るので、1枚動くと 0.05。勝敗がつく前からサイドを多く取ったほうがよいと伝わる

④お手本への引き綱
β=0.05 → 0

模倣学習の打ち方から離れすぎたら引き戻す。最終の run では最初から 0

①〜③だけが記録に書き込まれる。この合計が、次に出てくる critic の予想の的になる。③は足すと打ち消し合う形なので、係数をいくつにしても最適な打ち方は変わらない

④は期待値の外にいる。報酬としてではなく、重みを更新するときに引く罰則である(式にはもう1つ、探索を促す項も足すが、何を良しとするかには関わらない)

12 / 27

勝ちやすさの見立て

一周の ③  /  Part I

モデルにもう1つ出口を付け、盤面を見て「ここから最後までに入る報酬の合計はどれくらいか」を答えさせる。この係を critic と呼ぶ。報酬の大半は勝敗なので、実質は勝ちやすさの見立て。手を打つ前と後で、その予想がどう動いたかを見る

45%
criticの見立て:
やや不利

ワザで相手のポケモンを倒す
打った後の盤面 → 72%
+27
この手は good

「ナンジャモ」で手札を引き直す
打った後の盤面 → 38%
−7
この手は bad

この動いた分が、その1手の成績である。これをアドバンテージ A と呼ぶ。試合に1つしか付かない勝ち負けが、criticの見立ての差を通して、1手ごとの点数に置き換わる

criticは予想が外れるほど直され、記録の報酬に合うよう一緒に学習する。この A が、次の④でそのまま「上げるか下げるか、どれだけか」に掛かる

13 / 27

成績を教師の代わりにする

一周の ④  /  Part I

教師あり学習の「この場面の正解はこの手」に当たるラベルはない。できるのは、記録に残っている手を選ぶ確率を上げるか下げるかだけである。どちらに動かすかを、③で出た成績 A の符号が決める

L(θ) = − Σt At · log πθ( at | st )
st は t 手目の盤面、at はそこで実際に打った手(正解の手ではない)
πθ(at|st) はその盤面でその手を選ぶ確率そのもの。はじめに見た「モデルが候補につけた点数」である
log をとるのは、1試合ぶんの確率の掛け算が足し算になるから。Σt は記録に残った全部の手にわたる
ボールでポケモンを探す
+0.6
critic の見立てより良かった。同じ場面でこの手を選ぶ確率が上がる
炎エネルギーをつける
−0.05
ほぼ critic の見立てどおり。ほとんど動かない
ワザ「かえんほうしゃ」を使う
−0.5
critic の見立てより悪かった。同じ場面でこの手を選ぶ確率が下がる
正解の手は最後までわからない。わかるのは、打った手が critic の見立てより良かったか悪かったかだけである

教師ラベルとの違いは符号にある。ラベルは「この手に近づけ」としか言えないが、A は「近づけ」と「遠ざけ」の両方を言える

ただし、この記録を打ったのは更新前の方策である。更新するほど、手元の記録はいまの方策のものではなくなっていく

14 / 27

更新幅の上限(PPO)

一周の ④  /  Part I

記録がどれだけ古くなったかは、その手を選ぶ確率が記録時の何倍になったかで測れる。この倍率に上限を置き、届いた手はそこで打ち止めにする

0.8倍
元のまま
1.2倍
ワザ「かえんほうしゃ」を使う
0.12
−0.5
0.10
打ち止め
炎エネルギーをつける
0.61
−0.05
0.59
ボールでポケモンを探す
0.18
+0.6
0.22
打ち止め
ベンチのポケモンを進化させる
0.07
+0.15
0.08
番を終わる
0.02
−0.15
0.018
素直に動かすと行きたい先
実際に止まる所

枠に届いた手はそこから先へ進まない(更新を戻すのではなく勾配が0になる)。学習率=1歩の大きさ、上限=行ける距離で、代わりにならない

min( r·A, clip(r, 0.8, 1.2)·A )
最終run:1イテレーション 96,000手/ミニバッチ 1,024/使い回し 1回/学習率 1e-4
15 / 27
02
Part II

コンペでの実装

モデルの中身、模倣での出発、持ち込むデッキ、自己対戦、そして速さ

16 / 27

盤面と手を読むTransformer

Part II

入口が2つ(盤面と候補の手)、出口が2つのモデルである。約1,790万パラメータ。出口の1つ目が方策で、候補の手ごとに点数を出す。2つ目がさきほどの critic で、こちらは手ごとではなく盤面ごとに1つの値を返す

Encoder · 盤面を読む
25語の観測
アクティブ2、ベンチ16、手札、山、スタジアム…
Self-Attention × 4
d=192 · 6 heads · 位置符号なし
価値ヘッド = critic
25語を平均プール → tanh → 盤面ひとつに1値 [−1, 1]
→
Decoder · 手を採点する
N個の候補手
各手も特徴の和で1トークン。N個まとめて通す
Cross-Attention × 4
各候補が盤面を参照する(候補どうしは見ない)
方策ヘッド
候補ごとに1 logit → softmax = π(a|s)

候補の数は毎回変わるので、「出口が固定N個」の形にはできない。手を1つ1トークンにして盤面との相性を見る形なら、候補が何個でも1回の推論でまとめて採点できる。1手を選ぶのに CPU で約5ms

17 / 27

模倣で出発点を作る

Part II

何も知らない状態から対戦を始めると、まともな試合になるまでがとても長い。まずうまい人の真似から入る

公式が毎日公開する対戦記録を使い、「この場面で人はどの手を選んだか」を当てる練習をする(模倣学習、Behavior Cloning)。これは答えのある普通の分類問題

このときcritic も一緒に育つ。同じ胴体に付いた「勝ちそう度」の出口も、リプレイの勝敗を当てるように学ぶので、自己対戦を始める時点で勝敗予測の AUC は 0.8 前後。一周の③が最初から機能する

模倣の上限は教師の強さ。ここを出発点にして、強化学習で超える

日次エピソードデータ · 10日ぶん
教師の絞り込み:対戦時レートで足切り
両席ぶんの(盤面, 選んだ手)を抽出して重複除去
Transformer を交差エントロピーで学習
761万
(盤面, 手) ペア · 教師506人
0.82
検証の正解率(意味的等価を含む)
18 / 27

デッキも提出物

Part II

提出物は打ち手のプログラムと、60枚のデッキの2つ。同じプログラムでも、持たせるデッキが違えば別のエージェントになる。だからモデルはデッキごとに1つずつ育てる

手を選ぶ
プログラム
+
ドラパルトex カミツオロチex メガルカリオex

デッキを差し替えれば、使えるワザも、引けるカードも、勝ち筋も変わる。同じ重みのまま別のデッキを持たせても、うまく打てない

マリィのオーロンゲ フーディン シロナのガブリアス 57% 64% 59%

上位帯の実測である。マリィのオーロンゲはフーディンに勝ち越し、フーディンはシロナのガブリアスに勝ち越し、シロナのガブリアスはマリィのオーロンゲに勝ち越す

輪が閉じているので、「一番強いデッキ」は決まらない

決まるのは、いま多い相手に強いデッキだけである。この「いま何が多いか」をメタと呼ぶ

19 / 27

金圏で当たる相手を測る

Part II

金メダル圏の試合だけを取り出して、相手が実際に持ってきたデッキを数える。この分布が、そのまま自己対戦の相手になる

ドラパルトex
38.0%
ドラパルト
カミツオロチex
19.2%
カミツオロチ
メガガルーラex
12.3%
メガガルーラ
フーディン
8.0%
フーディン
メガルカリオex
7.7%
メガルカリオ
マリィのオーロンゲex
4.0%
マリィのオーロンゲ

多いデッキが強いデッキとは限らない。デッキを乗り換えた人を追って打ち手の腕を揃えて比べると、ドラパルトは勝率が平均より +8.2ポイント、席数最多だったマリィのオーロンゲは −4.0ポイントだった

最終提出はこの2本。ドラパルト(一番当たる相手で、腕を揃えても強い)と カミツオロチ(2番手で、まだ伸びている)

20 / 27

自己対戦リーグとPFSP

Part II

練習相手が自分だけだと、自分にしか強くならない。大会でよく当たるデッキを使う相手をたくさん用意して順番に対戦する

学習者(BCの重みから開始)
金圏メタ
8デッキの
クローン
過去の自分
(スナップ
ショット)
BC
アンカー
 
勝敗から方策と価値を更新(PPO)→ リーグに戻す
PFSP · 対戦相手の重み
w = max( 0.05, 1 − 勝率 )2

PFSP=「苦手な相手と多めに練習する」。勝率が低い相手ほど当たる回数を増やす(2乗なので、かなり偏らせる)。自分との対戦は最大50%

21 / 27

リーグを強くしていく

Part II

練習相手も育てる。1つのデッキの強化学習が終わるたびに、その強い版を相手の席に入れて次のデッキを回す

模倣学習が操縦(弱い)
強化学習ずみが操縦
学習者は マリィのオーロンゲ。相手は全員、模倣学習の操縦
15.8億手まで回したマリィのオーロンゲを相手の席へ。学習者は次のデッキに移る
マリィのオーロンゲex
7つのうち6つが強化学習ずみ。自分のデッキとは強い版どうしのミラー戦
ドラパルトexカミツオロチexメガガルーラexメガルカリオexマリィのオーロンゲexメガミミロップex

弱い相手に勝てても本番では通じない。相手を強くしてから測り直すと、もう伸びないと思っていた壁の位置が動いた。1デッキあたり 5〜16億手

22 / 27

強化学習の高速化

Part II

1デッキに5〜16億手を積むには、7日間回し続けることになる。ところが実測は毎秒345手で、7日でも2億手にしか届かなかった。効率的な学習に必要なチューニングを繰り返した

1件ずつ
CPUで推論していた
1決定 5,678µs のうち 4,617µs(81%)が、1件だけをCPUに流すニューラルネットの推論だった
多数の対局をまとめて1回のGPU推論にする。256件まとめると 43,279決定/秒(1コアのCPUは220決定/秒)
ワーカーを
毎周つくり直していた
対戦を回すプロセスを一周ごとに全部起動し直していて、その起動だけで46〜49秒。一周の54%
ワーカーを一周をまたいで生かす。新しい重みはファイル経由で渡す
集めるのと学ぶのが
交互だった
重みを更新しているあいだ、対戦を回す側が止まって待っていた。全体の47%が待ち時間
更新している裏で次の一周を先に集める
345手/秒 · 7日で 2億手
4,766手/秒 · 7日で 30億手 · 13.8倍
23 / 27

ラダーのノイズ

Part II

中身がバイト単位で同一の提出を2本、同時に出してみた

957.4
1本目
/
796.7
2本目
160

同じものが、これだけ離れる。これがこのラダーの目盛りの幅

だから手元の指標で候補を選びたくなる。教師との一致率で選んだ4回とも、ラダーでは逆を向いた。レート1100以上に絞った教師の版は手元で勝っていて −71、10日ぶんのコーパスは全エポックで勝っていて −85

結論として、手元の指標は候補の選別には使わないことにした。使い道はバグ探しだけである。判定はラダーだけで、そのぶん読むのに時間がかかる

24 / 27

順位の推移

Part II

提出ごとのレート(TrueSkill、全員600点から開始)。6,807チーム中、2026-09-05 時点の確定値。金圏カットライン自体も 1071〜1148 のあいだで動いた

1200 1000 800 600 400 金圏カットライン(最終 1131) 08-16 締切 07-12 08-01 08-31 424 · ルールベース 668 · 模倣学習の第1版 846 · 上位プレイヤーの模倣 992 · 模倣+詰め探索 211位、銀圏 1024 · 新エンコーダの模倣 76位 1100 · 強化学習の初の本格run 一時 15位。試合数が少ない時点の読み 1130 · 最終提出 カミツオロチ RL 締切時点で19位、カットラインの内側 1105 · 最終 33位(銀) 続きの対戦で少し下がる
25 / 27

まとめ

Wrap-up
1

強化学習は、状態を見て行動し、遅れて届く報酬から方策を直す。ポケカなら盤面、合法手、勝敗、採点ネット

2

ゼロから回さない。まず人の対局の模倣を出発点にして、PPOの自己対戦で教師を超える

3

効いたのはアルゴリズムより設計。誰と戦うか(PFSPとメタ)、何を報酬にするか(サイド差)、どれだけ速く回すか

26 / 27

出典

Appendix
Kaggle「Pokémon TCG AI Battle」(The Pokémon Company)
コンペ配布の Card_ID List(EN / JP)
Kaggle API(competitions leaderboard / submissions、2026-09-05 取得)。締切後も対戦が続くため数字は動く
27 / 27