コンテンツにスキップ

2026-07-14 V14 cycle001 promotion 失敗の診断

状況

本書は、V14 の最初の 1000 game self-play cycle で作成した Candidate が Champion との promotion head-to-head に負け越した原因を調査した記録である。現行仕様ではなく、特定 run の分析結果と次の検証計画を扱う。

対象 run:

項目
run name v14-gumbel-iterative-10k
run ID 20260714-005806-cycle001
self-play 1000 games、10 chunks、8 workers、CPU
train 1 epoch、batch 64、AdamW、MPS
Candidate checkpoints/policy_value_v14_gumbel_iterative_10k_20260714-005806-cycle001_best.pt
Champion checkpoints/policy_value_latest_best.pt
MLflow cycle run ID 0ba8addf22fa4b3bab8929424773ce52

2026-07-14 23:10 JST 時点で head-to-head は完了し、Candidate 対 rule-pool 評価は継続中だった。本書の promotion 数値は head-to-head だけを対象とする。

分析方法

この分析は学習処理を再実行せず、保存済み artifact と MLflow の metric history を読み取って行った。集計用の一時コードは artifact を変更しない read-only の Python 処理とし、勝敗は常に Candidate / Champion の向きへ正規化した。

1. 対象 run と checkpoint の特定

次の manifest、checkpoint manifest、学習後 checkpoint を照合し、cycle001 の親子関係を確認した。

  • logs/selfplay-train/v14-gumbel-iterative-10k-20260714-005806-cycle001.manifest.yaml
  • checkpoints/policy_value_latest.yaml
  • checkpoints/policy_value_v14_gumbel_iterative_10k_20260714-005806-cycle001_best.pt

manifest の入力 checkpoint を Champion、学習後の best checkpoint を Candidate とした。ファイル名の latest だけから推測せず、manifest に記録された実体 path と照合した。

2. Promotion head-to-head の集計

次の2つの評価結果を読み、player位置を入れ替えた結果を合算した。

  • data/eval/promotion-gate/v14-gumbel-iterative-10k-20260714-005806-cycle001/head_to_head_forward.json
  • data/eval/promotion-gate/v14-gumbel-iterative-10k-20260714-005806-cycle001/head_to_head_reverse.json

forward では Candidate を player 0、reverse では Candidate を player 1 として勝数を数えた。deck別集計も同様に向きを正規化し、同じ7 decksについて Candidate の勝数を合算した。決着勝率は Candidate wins / finished games、95%信頼区間は二項比率の Wilson interval で概算した。未完了数と Gumbel fallback 数も確認し、評価失敗を負けとして混ぜていない。

3. MLflow training metric の比較

MLflow cycle run 0ba8addf22fa4b3bab8929424773ce52 から MlflowClient.get_metric_history で train metric の履歴を取得し、validation metric はrunの最終値を読んだ。主に次を比較した。

  • total / policy / value loss
  • policy KL と policy top-1 agreement
  • predicted / target policy entropy
  • gradient clipping 前の norm

policyの変化は最初に記録された累積window付近の batch 50 と epoch終了の batch 1820 を比較した。これらはbatch単体値ではなくrunning metricなので、差が小さいことは「改善の証拠が弱い」と解釈し、完全に更新されていないとは断定していない。

4. Deck sampling seed の再現

self-play script とparallel workerのseed生成箇所を読み、当時の式を次のように再現した。

chunk_seed = base_seed + chunk_index
worker_seed = chunk_seed + worker_index

各workerへ割り当てられたgame数と同じ回数だけ、実装と同じdeck候補・重み・乱数順で player 0 / player 1を選んだ。再現したdeck出現数をself-playのgame metricsと比較し、一致したことから、観測した偏りが集計ミスではなくseed系列の重複に由来すると判断した。

分布の確認には、30 decksへ2000 assignmentsが均等に配られた場合の期待値 2000 / 30 = 66.7 を基準にした。全体の最少・最多とpromotion対象7 decksの出現数を比較したが、分布偏りだけで勝敗差を説明しないよう、十分出現したdeckの退行も別に確認した。

5. Game ID とsplitの検査

10個のpart JSONLをstreamで読み、partごとの game_id の最小値、最大値、unique数を集計した。続いてmerged JSONL全体のunique game_id とrecord数を数え、train/validation split summaryと比較した。

part単位:  game_id 0..99、各100 IDs
merged:    122,459 records、100 unique game IDs
split:     total_games=100、train=95、validation=5

同じlocal IDを持つ10 gamesが同じsplit側へ入るため、record単位の即時leakageとは限らない。一方でgame数、replay ratio、game-level集計が誤ることは確認できるため、独立した不具合として扱った。

6. 判断時の制約

  • rule-pool評価は分析時点で実行中だったため、promotionの結論には含めていない。
  • validationは同じcycleのself-playから分割され、Championの学習前baselineがない。このため、低いvalidation lossだけでは能力向上を示せない。
  • gradient norm、target entropy、deck偏りは相関する観測であり、単独原因とは断定していない。
  • Gumbel teacherの良否を判断するには、同一checkpoint・同一dataでVisit、completed-Q、混合targetを比較する必要がある。

結論

Candidate は Champion に 60-80、決着勝率 42.9% で負け、52% の promotion 基準を満たさなかった。未完了と Gumbel fallback はともに 0 であり、評価処理の失敗ではない。

分析では、次の問題を確認した。

  1. chunk と worker の RNG seed が重複し、self-play の deck 出現数が大きく偏った。
  2. 修正前に生成した各 chunk の game_id がすべて 0-99 で、1000 games が downstream では 100 個の game ID として認識された。
  3. 1 epoch を通して policy loss、policy KL、探索 target との top-1 agreement がほぼ改善しなかった。
  4. Gumbel completed-Q target は entropy 0.31 とかなり鋭い一方、モデル予測 entropy は 1.24 で、探索結果を十分に蒸留できていない。
  5. clipping 前 gradient norm は約 10-13 で、gradient-clip-norm: 1.0 によりほぼ全 batch の勾配が強く縮小された。

したがって、この run だけから Gumbel teacher 自体が弱いとは結論しない。まず deck sampling、game identity、学習前 baseline を直したうえで、更新強度と policy target を制御比較する。

昇格判定のための新旧モデル対戦

固定 7 decks、同一 deck mirror、player 位置入れ替えで 70 games を 2 方向実行した。

方向 Candidate Champion 未完了
Candidate p0 / Champion p1 30 40 0
Champion p0 / Candidate p1 30 40 0
合計 60 80 0

Candidate の決着勝率は 42.9% で、Wilson 95% 信頼区間は概算 35.0-51.1% である。両 player 位置で同じ 30-40 だったため、今回の差を先後だけでは説明できない。

Deck 別

Deck Candidate Champion Candidate win rate
Archaludon 9 11 45%
Garchomp 7 13 35%
Dragapult 7 13 35%
Iono / Bellibolt 7 13 35%
Mega Abomasnow 8 12 40%
Starmie 8 12 40%
Mega Lucario 14 6 70%

Lucario だけ改善し、ほかの 6 decks は負け越した。単一の全体 Elo 低下だけでなく、deck ごとの更新方向が異なる可能性がある。

評価 artifact:

  • data/eval/promotion-gate/v14-gumbel-iterative-10k-20260714-005806-cycle001/head_to_head_forward.json
  • data/eval/promotion-gate/v14-gumbel-iterative-10k-20260714-005806-cycle001/head_to_head_reverse.json
  • logs/selfplay-train/20260714-005806-cycle001-promotion-eval.log

MLflow training 分析

train/validation の最終指標:

指標 学習 検証
total loss 1.8300 1.8193
policy loss 1.2380 1.2091
value loss 0.4817 0.5102
policy KL 0.9257 0.9020
policy top-1 agreement 51.2% 51.1%
predicted policy entropy 1.2365 1.2096
target policy entropy 0.3123 0.3072

validation loss は train loss よりわずかに低く、通常の意味での過学習は見えない。ただし、同じ cycle の self-play から game 単位で分割した validation なので、teacher の誤りや過去能力の忘却は検出できない。

Policy はほぼ改善していない

MLflow の running metric を最初の batch window と epoch 終了で比較した。

指標 バッチ50 バッチ1820
policy loss 1.2397 1.2380
policy KL 0.9241 0.9257
policy top-1 agreement 51.4% 51.2%

running metric は累積平均であることを考慮しても、window metric に一方向の改善はなく、探索 target の蒸留が進んだ証拠は弱い。

target entropy 0.31 は実効候補数に直すと約 1.4、予測 entropy 1.24 は約 3.5 に相当する。これは teacher がほぼ 1 手へ集中する一方、student が複数手へ確率を残している状態である。

勾配クリップ

torch.nn.utils.clip_grad_norm_ が返す clipping 前 norm は、ほぼ全区間で 10-13 だった。設定は gradient-clip-norm: 1.0 なので、各 update は概算 8-10% まで縮小される。clip 自体は発散防止に必要だが、learning-rate: 1e-5、1 epoch と組み合わせると更新不足になる可能性がある。

現状は clipping 後 norm、clip 適用率、学習前 validation を記録していないため、これだけで clip=1.0 を原因と断定しない。

train/running 全系列

MLflow child run 0ba8addf22fa4b3bab8929424773ce52 に保存された train/running/* は20系列、各37点で、batch 50から1820までを記録している。running は開始から当該batchまでの累積batch平均であるため、終盤の変化を薄める。以下では、最初と最後の累積値に加え、直近windowの値も併記した。通常windowは50 batchesだが、最後だけ20 batchesなので変動がやや大きい。

Series Running 50 Running 1820 Last window 診断
loss 1.8164 1.8300 1.8431 改善なし。複数headの増減が相殺されるため単独では判断しない
policy_loss 1.2397 1.2380 1.2605 累積は横ばい、終盤は悪化
policy_kl 0.9241 0.9257 0.9638 targetへの一致は改善せず、終盤は悪化
policy_target_entropy 0.3156 0.3123 0.2967 teacher targetは一貫して非常に鋭く、終盤はさらに鋭い
policy_predicted_entropy 1.2421 1.2365 1.2693 studentはtargetより大幅に拡散し、終盤は差が拡大
policy_top1_agreement 51.44% 51.19% 48.98% 改善なし。終盤windowは50%を下回る
policy_weight_mean 0.4999 0.5160 0.4952 sample構成の変化。lossはweight sumで正規化されるためbranch全体の倍率ではない
value_loss 0.4704 0.4817 0.4751 一方向の改善なし。validationは0.5102でtrainより悪い
value_weight_mean 1.0000 1.0000 1.0000 全sampleがvalue学習対象
turn_value_coverage 100% 100% 100% turn value targetは欠損なし
aux_prize_loss 0.1033 0.1073 0.1044 重み込み合計はほぼ横ばい
this_turn_prize_loss 0.4890 0.5213 0.4557 変動が大きい。最終windowだけは改善
own_prize_completion_loss 0.5308 0.5475 0.5948 終盤で悪化
opp_prize_completion_loss 0.5563 0.5556 0.5829 累積は横ばい、終盤で悪化
aux_prize_coverage 92.41% 92.95% 95.00% label coverageは十分。上昇は主にsample構成を表す
prize_completion_coverage 84.75% 87.89% 89.77% label coverageは上昇したが、loss改善とは結び付いていない
integrated_belief_loss 0.003102 0.003009 0.002984 わずかに低下。ただし重み込みかつ疎なbinary targetなので精度の根拠には弱い
integrated_belief_coverage 100% 100% 100% belief targetは欠損なし
grad_norm 10.93 10.90 13.03 clip前norm。上限1.0を継続的に大幅超過
lr 4.72e-6 5.00e-6 9.77e-10 runningは累積平均。実際の終端LRはほぼ0

policy_target_entropy=0.3123 の実効候補数は exp(entropy)=1.37、予測側は3.44である。したがって policy_loss=1.2380 のうち約0.9257はtargetと予測のKL差であり、teacherの鋭いcompleted-Q targetをstudentが蒸留できていないことがpolicy側の中心問題である。top-1も約51%のままなので、単に確率校正だけがずれている状態ではない。

total lossの最終値は、policy 1.2380 + value 0.4817 + aux 0.1073 + belief 0.0030 = 1.8300 である。policyが全体の約68%を占めるため、belief lossの小ささだけでは行動性能を押し上げられない。またbelief lossはcard vocabulary全体に対するbinary BCEを平均してから0.05の重みを掛けた値であり、非該当cardの多さによって低くなりやすい。belief品質の判定にはcard-level precision/recall、AUPRC、count calibrationを別途記録する必要がある。

cosine scheduleは最終windowでLRをほぼ0まで落とす。streaming shuffle bufferは10,000 recordsで、全116,418 train recordsより小さいため、終盤に異なる難易度やtarget分布が現れても、その区間ではほぼ更新できない。終盤windowでtarget entropyが0.2967まで鋭くなり、policy KLが0.9638、top-1が48.98%へ悪化したことと整合する。ただしデータ順序との因果は、固定validationを学習途中にも測るか、同じデータで複数epochを回す比較実験が必要である。

このrunではclip後norm、clip scale、clip適用率、学習前validationをまだ保存していない。現在の実装にはこれらを追加済みで、次cycleから「更新が弱すぎる」のか「target自体を学べない」のかを直接切り分けられる。

Deck sampling の seed 重複

self-play は各 chunk の seed を base_seed + chunk とし、parallel worker はさらに seed + worker_index を使っていた。このため次のように RNG 系列が重複する。

chunk 0 / worker 1 -> seed 1
chunk 1 / worker 0 -> seed 1
chunk 1 / worker 1 -> seed 2
chunk 2 / worker 0 -> seed 2

weighted_deck_choice は同一 RNG から player 0 / player 1 の deck を順番に選ぶ。10 chunks、各 100 games、8 workers の条件を上記 seed で再計算すると、実測した deck 出現数と一致した。したがって、偏りは偶然ではなく seed 設計から再現する。

30 decks、1000 games では両 player 合計 2000 deck assignments なので、均等なら 1 deck あたり約 66.7 回になる。promotion 対象 7 decks の実測は次の通りだった。

Deck 両 player 合計出現数
Garchomp 27
Starmie 60
Iono / Bellibolt 64
Mega Lucario 66
Dragapult 72
Archaludon 78
Mega Abomasnow 82

全 30 decks では両 player 合計の最少が 29、最多が 115 だった。特に Garchomp は期待値の約 40% しかなく、promotion でも 7-13 と大きく負け越した。ただし、十分出現した Dragapult、Iono、Abomasnow も負け越しているため、deck 偏りだけで 60-80 の全差を説明しない。

今後は global game ID から独立 seed を導出するか、30 x 30 ordered matchup を先に一巡させる balanced-pairs sampling を使う。

Game ID 重複

生成済みの各 part JSONL は、すべて game_id=0..99 だった。

生成物 実測
game metrics JSONL 1000 lines
merged training JSONL 122,459 records
unique game_id 100
split summary の total games 100
train records 116,418
validation records 6,041

同じ local ID の 10 games が同じ split 側へ入ったため、record 数としてはおおむね 950 games 対 50 games に分かれており、直ちに train/validation record leakage が起きたとは限らない。一方、replay builder は recent games を 95 と認識して過去追加数を計算するため、将来 cycle の replay ratio と game-level 集計は壊れる。

現在の script と parallel self-play には PCA_SELFPLAY_STEP_OFFSET が追加されているが、今回の part files はその修正前に生成された。chunk、--start-chunk--resumeを含む回帰テストが必要である。

Config に関する補足

cycle manifest の train config は configs/v13/train-policy-unified-selfplay.yaml だった。現在用意した configs/v14/train-policy-gumbel-selfplay.yamlとの差は、artifact path と policy-target-temperature: 1.0 の明示が中心である。実行時の主要 optimizer/model 設定は一致しているため、現時点ではファイル名の V13/V14 差を主要因とはみなさない。ただし、再現性のため次回は V14 config を明示する。

原因の確度

確認済み

  • Candidate は Champion に 60-80 で負けた。
  • deck sampling の RNG seed が chunk/worker 間で重複し、deck 分布を偏らせた。
  • 生成済み part 間で game_id が重複した。
  • policy loss、KL、top-1 agreement は 1 epoch でほぼ改善しなかった。
  • gradient clipping 前 norm は上限を大幅に超えていた。
  • train/validation gap に典型的な過学習は見えない。

有力だが未確定

  • deck 不均衡が deck 別退行の一部を引き起こした。
  • 1 epoch、低 learning rate、強い clipping の組み合わせが更新不足を引き起こした。
  • 鋭い Gumbel completed-Q target を現在の student が十分に蒸留できていない。

未確認

  • Gumbel completed-Q target 自体が Visit target より学習教師として悪い。
  • policy/value/aux/belief の勾配競合が主因である。
  • model capacity が不足している。
  • 評価乱数だけで 60-80 の差が生じた。

次の実行順

  1. chunk/worker/game ごとに一意で再現可能な seed を使う。
  2. balanced-pairs deck sampling と deck 出現数検証を追加する。
  3. game_id の chunk/resume 回帰テストを追加する。
  4. optimizer 更新前の Champion を同じ validation で測る。
  5. deck 別の records、policy loss、KL、top-1 agreement、target entropy を MLflow に出す。
  6. clip 前後 norm、clip scale、clip 適用率を記録する。
  7. 同じ初期 checkpoint とデータで次を比較する。
  8. 1 epoch、LR 1e-5、clip 1.0
  9. 1 epoch、LR 1e-5、clip 5.0
  10. 最大 2-3 epochs、LR 5e-6、clip 5.0、early stopping
  11. completed-Q、Visit、両者の混合 target を同じデータで比較する。
  12. 小規模 cycle で teacher agreement と frozen validation が改善した候補だけ promotion に回す。

改善実装の進捗

同日、上記1-3に対して次を実装した。

  • base seedとglobal game IDからdeck、search policy、oracle policy用のseedを分離して導出する。
  • V14 self-playの既定をdeck-sampling: balanced_pairsとし、全ordered matchupを一巡してから再利用する。
  • workerへ渡すglobal game offsetの二重加算を修正した。
  • chunk分割、worker分割、途中resumeの境界が変わっても、同じglobal game IDのdeck matchupを維持する。
  • 30対30 decksの先頭90 gamesで各deckが両側とも3回ずつ出現することを回帰テストで確認する。
  • 実CABTの2-worker smokeで、offset 100から生成した4 gamesがrecordsとgame metricsの双方で 100, 101, 102, 103になることを確認する。

さらに、学習前checkpointを同じvalidation splitで測るpretrain_val_* baselineと、clip前後norm、clip scale、clip適用率を追加した。これにより項目4と6の観測基盤まで完了した。次の改善対象はdeck別の学習metricと、target/optimizerの制御比較である。

今回の Candidate は latest Champion へ昇格させず、失敗分析用 artifact として保持する。