2026-06-27 Journal¶
今日の結論¶
今日は v12 の方針を、AlphaGo Zero 寄せの Belief-Guided Neural ISMCTS として整理し、実装した。
重要な判断は次の通り。
- rollout は本線に入れない。
- ISMCTS は leaf で止まり、Policy/Value NN の prior/value を使う。
- 弱い rollout で無理に攻撃まで進めるより、teacher search の候補手制御と value 設計を改善する。
- deck-out 偶発勝ちではなく、攻撃・サイド取得による通常勝ちを増やす。
- heuristic reranker は本線 self-play では使わない。
- oracle policy target は今回使わない。
- deck context / Set Transformer 再導入は、teacher search が安定してから検討する。
実装したこと¶
探索評価値のプロファイル¶
src/pca/search/mcts.py に search_value_config_for_profile() を追加した。
profile は次の 2 つ。
current
v12_prize_race
v12_prize_race の意図:
- deck-out 勝ちを強い勝ちとして扱わない。
- deck-out 負けは強く悪い。
- サイド差と実際のサイド取得 delta を重視する。
- 相手 active の damage pressure を少し評価する。
- attack-ready は弱めの補助評価にする。
- no-progress END / empty-bench END は引き続き減点する。
- サポート役ポケモンを attacker と決め打つようなカード固有 heuristic は入れない。
ISMCTSの候補削減¶
src/pca/search/ismcts.py に root / non-root 別の candidate cap を追加した。
追加した config:
root_max_candidate_actions
nonroot_max_candidate_actions
progressive_widening
progressive_widening_base
progressive_widening_scale
v12_prize_race では、CLI 側で root=8 / non-root=6 を default とする。
また、次の action は pruning で落とさない。
- attack action
- choice 系 action
choice 系を残す理由は、カード選択・エネルギー選択・YES/NO などを雑に落とすと、合法手列の途中で意味のある action が壊れるため。
Progressive Widening¶
progressive widening を追加した。
候補数は概ね次で増える。
base + scale * sqrt(node.total_visits)
デフォルト候補:
base = 4
scale = 1.5
root / non-root cap を超えては広げない。
探索到達率ログ¶
simulation 単位で次を記録するようにした。
turn_advance_rate
attack_reached_rate
prize_reached_rate
self-play log では次のように出る。
reach turn_advance=... attack_reached=... prize_reached=...
これにより、「平均 depth は伸びているが、実際にターン進行・攻撃・サイド取得まで届いているのか」を見られる。
また、従来の stops depth=0 は誤解しやすかったため、stops max_depth=0 に変更した。
これは「探索 depth が 0」という意味ではなく、「max depth 到達で停止した simulation が 0」という意味。
CLIへの接続¶
self-play と evaluation の両方に以下を追加した。
--ismcts-root-max-candidate-actions
--ismcts-nonroot-max-candidate-actions
--ismcts-progressive-widening
--ismcts-pw-base
--ismcts-pw-scale
--search-value-profile current|v12_prize_race
evaluation の JSON config にも v12 search flags を保存するようにした。
テスト¶
tests/test_encoder.py に以下を追加した。
- candidate pruning が attack / choice action を落とさないこと。
- progressive widening の candidate limit が visit 数で増えること。
v12_prize_raceが prize race を重視し、attack-ready を弱める profile になっていること。
実行した確認:
PYTHONPATH=src python -m py_compile \
src/pca/search/mcts.py \
src/pca/search/ismcts.py \
src/pca/training/selfplay.py \
src/pca/evaluation/tournament.py \
tests/test_encoder.py
UV_CACHE_DIR=/private/tmp/uv-cache PYTHONPATH=src uv run python -m unittest tests.test_encoder
結果:
Ran 75 tests
OK
v12の自己対戦コマンド¶
Kaggle での本線収集候補:
python -m pca.training.selfplay \
--deck0-dir /kaggle/working/pokemon-card-ai/decks/opponents/train \
--opponent-deck-dir /kaggle/working/pokemon-card-ai/decks/opponents/train \
--policy search \
--checkpoint /kaggle/working/pokemon-card-ai/checkpoints/policy_value_v11_d8s16_300g_best.pt \
--belief-checkpoint /kaggle/working/pokemon-card-ai/checkpoints/belief_v10_general_best.pt \
--games 300 \
--workers 4 \
--device cuda \
--max-steps 180 \
--search-mode ismcts \
--ismcts-determinizations 4 \
--ismcts-simulations-per-determinization 12 \
--ismcts-root-max-candidate-actions 8 \
--ismcts-nonroot-max-candidate-actions 6 \
--ismcts-progressive-widening \
--ismcts-pw-base 4 \
--ismcts-pw-scale 1.5 \
--search-rollout-depth 18 \
--search-value-profile v12_prize_race \
--unknown-card-rate 0.05 \
--full-observation-targets \
--card-data /kaggle/working/pokemon-card-ai/pokemon-tcg-ai-battle/EN_Card_Data.csv \
--nn-cache-size 50000 \
--no-color \
--output /kaggle/working/pokemon-card-ai/data/selfplay/v12-az-prizerace-d4s12-300g.jsonl
--output は incremental に書き込まれるため、途中停止しても完了済み game の records は残る。
v12の評価コマンド¶
bash scripts/evaluate_docker.sh \
--deck0-dir /app/decks/opponents/train \
--deck1-dir /app/decks/opponents/holdout \
--policy0 search-ismcts \
--checkpoint0 /app/checkpoints/policy_value_v12_az_prizerace_best.pt \
--belief-checkpoint0 /app/checkpoints/belief_v12_general_best.pt \
--policy1 search-ismcts \
--checkpoint1 /app/checkpoints/policy_value_v11_d8s16_300g_best.pt \
--belief-checkpoint1 /app/checkpoints/belief_v10_general_best.pt \
--policy0-opponent-prior-deck-dir /app/decks/opponents/train \
--policy1-opponent-prior-deck-dir /app/decks/opponents/train \
--games 1 \
--workers 4 \
--max-steps 180 \
--ismcts-determinizations 4 \
--ismcts-simulations-per-determinization 12 \
--ismcts-root-max-candidate-actions 8 \
--ismcts-nonroot-max-candidate-actions 6 \
--ismcts-progressive-widening \
--ismcts-pw-base 4 \
--ismcts-pw-scale 1.5 \
--search-rollout-depth 18 \
--search-value-profile v12_prize_race \
--unknown-card-rate 0.05 \
--output /app/data/eval/v12-az-prizerace-vs-v11-holdout.json \
--csv-output /app/data/eval/v12-az-prizerace-vs-v11-holdout.csv
未検証のこと¶
今日はコード接続と unit test まで。まだ以下は未検証。
- Docker で 1 game smoke が通るか。
- Kaggle で 16 games smoke が通るか。
reach attack_reached/reach prize_reachedが改善するか。normal_wins,avg_prizes_taken,avg_attacks,first_attack_step,first_prize_stepが v11 より改善するか。- candidate pruning によって重要な非攻撃 action が落ちすぎていないか。
- progressive widening の
base=4,scale=1.5が妥当か。
次に見る指標¶
v12 smoke では、勝率より先に以下を見る。
depth avg / hist
reach turn_advance
reach attack_reached
reach prize_reached
root atk_top prior/visit/sel
root end_sel
root-actions attach / evolve / ability / retreat / choice
prize-delta events / value
normal_wins
avg_prizes_taken
avg_attacks
first_attack_step
first_prize_step
deck_out_losses
unfinished
特に depth avg だけでは不十分。depth が伸びても、attack / prize に届いていないなら teacher
search はまだ弱い。
v12レビュー後の対応¶
外部レビューで Critical は無かったが、High 2 件を優先対応した。
src/pca/search/ismcts.py- max depth 到達時に NN value を捨てて progress value だけで leaf 評価していた問題を修正。
- max depth leaf でも現在局面の
policy_fn(obs)を評価し、失敗時のみ最後に得た decision へ fallback する。 ISMCTSRuntimeStats.delta()のpath_depth_maxを累積最大ではなく、差分ヒストグラム由来の直近区間最大に変更。src/pca/evaluation/tournament.py- 評価 JSON/CSV に ISMCTS 探索品質の summary を追加。
policy0_attack_reached_rate,policy0_prize_reached_rate,policy0_turn_advance_rate, candidate cap 平均などを CSV で比較可能にした。- raw diagnostics は
policy*_ismcts_diagnosticsに保持する。 src/pca/training/selfplay.py/src/pca/evaluation/tournament.pyv12_prize_raceprofile では legacy--ismcts-max-candidate-actionsが root/non-root default を無音で消さないよう修正。--search-rollout-depthの help を「rollout」ではなく互換名の max tree depth と説明するよう変更。tests/test_encoder.py- max depth leaf が NN value を使う回帰テストを追加。
- v12 default cap の回帰テストを追加。
- evaluation summary に ISMCTS reach/candidate 指標が入るテストを追加。
まだ保留している論点:
- candidate pruning の ranking はまだ priors-only。Q/visit を混ぜる案は search behavior を変えるため、次の teacher-quality smoke を見てから入れる。
- public information key の log tail 24 件は現状維持。必要なら docs に衝突リスクを明記する。
YAML設定への対応¶
長い self-play / evaluation / training command を毎回手で組まなくて済むように、主要 CLI に
--config を追加した。
対象:
python -m pca.training.selfplaypython -m pca.evaluation.tournamentpython -m pca.training.trainpython -m pca.training.belief_train
ルール:
- YAML key は CLI option から先頭
--を外した名前で書く。 - 例:
--max-stepsはmax-steps --belief-checkpointはbelief-checkpoint_形式も受け付ける。- 例:
max_steps - YAML の値は argparse default として入る。
- 同じ option を CLI で指定した場合は CLI が勝つ。
- 例:
--config configs/v12/selfplay-mac-d4s20.yaml --games 5 common:と command section (selfplay:,evaluation:,train:,belief_train:) も使える。- command section の値が
commonを上書きする。 - 未知 key はエラーにする。typo を黙って無視しない。
追加した v12 config:
configs/v12/selfplay-mac-d4s20.yamlconfigs/v12/selfplay-kaggle-d4s20.yamlconfigs/v12/evaluate-mac-quality.yamlconfigs/v12/train-policy.yamlconfigs/v12/train-belief.yaml
使用例:
bash scripts/collect_selfplay_docker.sh \
--config configs/v12/selfplay-mac-d4s20.yaml
bash scripts/evaluate_docker.sh \
--config configs/v12/evaluate-mac-quality.yaml
PYTHONPATH=src uv run python -m pca.training.train \
--config configs/v12/train-policy.yaml
PYTHONPATH=src uv run python -m pca.training.belief_train \
--config configs/v12/train-belief.yaml
CABT Docker image でも YAML を読めるように Dockerfile.cabt に pyyaml を追加した。