コンテンツにスキップ

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.pysearch_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.py
  • v12_prize_race profile では 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.selfplay
  • python -m pca.evaluation.tournament
  • python -m pca.training.train
  • python -m pca.training.belief_train

ルール:

  • YAML key は CLI option から先頭 -- を外した名前で書く。
  • 例: --max-stepsmax-steps
  • --belief-checkpointbelief-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.yaml
  • configs/v12/selfplay-kaggle-d4s20.yaml
  • configs/v12/evaluate-mac-quality.yaml
  • configs/v12/train-policy.yaml
  • configs/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.cabtpyyaml を追加した。