コンテンツにスキップ

当時のモデル構造と学習方針

更新日: 2026-06-28

このメモは、別AIやレビュアーに現在の方針を確認してもらうための整理である。実験ログではなく、現時点で採用しているモデル構造、self-play 生成、学習ターゲット、heuristic reranker、評価方針、既知の懸念をまとめる。

2026-06-28 現在の結論

現時点の共有用仕様は ../architecture/current-method.md に整理した。このメモは、そこに至る方針変更と実験判断の履歴として扱う。

現在の本線:

  • NN-only 提出ではなく、Policy/Value Net と ISMCTS を組み合わせる。
  • rollout は使わず、AlphaGo Zero 寄せに leaf で NN value + progress value を使う。
  • Belief Model は ISMCTS の hidden state sampling prior として使う。
  • PublicKnowledgeTracker で公開ログから確定できる hidden 情報を hard constraint として扱う。
  • oracle policy target は実験用に残すが、v12 本線では使わない。
  • deck context / Set Transformer は実装済みで v7 系では使った。v10/v11 では teacher search 安定化と構造差の切り分けを優先して一時的に deck_context_mode=none を使ったが、2026-06-28 以降の v12 学習 default は deck_context_mode=set_transformer に戻す。
  • seed-out / empty bench 対策を追加し、pokemon_out を deck-out と別にログ・評価する。

現在の主な評価指標:

  • normal wins
  • prizes taken
  • attacks
  • first attack / first prize step
  • deck-out losses
  • pokemon-out losses
  • unfinished
  • attack/prize reached rate
  • replay 上の行動品質

2026-06-27 追記: v12 AlphaGo Zero 寄せの方針

6/26 時点では、teacher search を強くするために探索量を増やし、Belief-guided ISMCTS で self-play を集める方針にした。しかし実測ログを見ると、探索 depth は平均 3 前後で止まることが多く、NN forward が主なボトルネックになっていた。

また、弱い rollout を入れて無理に攻撃まで進めるより、AlphaGo Zero に寄せて leaf で止まり、Policy/Value NN の prior/value と軽い progress value で探索する 方が方針として一貫していると判断した。

そのため v12 では次を本線にする。

  • random rollout / leaf extension rollout は入れない。
  • --search-rollout-depth は互換性のため残すが、意味としては ISMCTS max tree depth として扱う。
  • root と non-root で candidate pruning の上限を分ける。
  • attack action と forced/choice 系 action は pruning で落とさない。
  • progressive widening を入れ、visit が少ない node では候補を絞り、visit が増えるほど候補を広げる。
  • v12_prize_race value profile を追加し、サイド差・実際のサイド取得 delta・deck-out 負け回避を重視する。
  • attack-ready は弱めの補助評価に留め、サポート役ポケモンを手書きで attacker と決め打ちしない。
  • heuristic reranker は本線 self-play では使わない。
  • oracle policy target は今回は使わない。
  • deck context / Set Transformer は v12 学習 default で再度有効化する。効果は deck-context-free 版と A/B して確認する。

v12 実装済み変更

  • src/pca/search/mcts.py
  • SEARCH_VALUE_PROFILES = ("current", "v12_prize_race") を追加。
  • search_value_config_for_profile() を追加。
  • v12_prize_race では、deck-out 勝ちを強い勝ちにせず、deck-out 負けを強く悪く扱う。
  • prize_diff_weight / prize_take_weight / prize_pressure_weight を上げ、attack_ready_weight は弱めた。

  • src/pca/search/ismcts.py

  • ISMCTSConfig に以下を追加。
    • root_max_candidate_actions
    • nonroot_max_candidate_actions
    • progressive_widening
    • progressive_widening_base
    • progressive_widening_scale
  • root / non-root で候補手上限を分けられるようにした。
  • progressive widening は base + scale * sqrt(node.total_visits) で候補数を増やす。
  • attack action と choice 系 action は pruning で落とさない。
  • simulation 単位の到達率ログを追加した。
    • turn_advance_rate
    • attack_reached_rate
    • prize_reached_rate
  • stops depth 表示は誤解を避けるため stops max_depth に変更。

  • src/pca/training/selfplay.py

  • self-play CLI に以下を追加。
    • --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
  • v12_prize_race 指定時、既存の --ismcts-max-candidate-actions が無ければ root=8 / non-root=6 を default とする。
  • progress log に reach turn_advance / attack_reached / prize_reached を追加。
  • incremental JSONL output は維持。Kaggle 等で途中停止しても完了済み game の records は残る。

  • src/pca/evaluation/tournament.py

  • evaluation CLI に self-play と同じ v12 search flags を追加。
  • 評価 JSON の config に v12 search flags と search_value_profile を保存する。
  • v12_prize_race 指定時の root=8 / non-root=6 default を evaluation 側にも入れた。

  • tests/test_encoder.py

  • candidate pruning が attack / choice を落とさないことをテスト。
  • progressive widening の candidate limit が visit 数で増えることをテスト。
  • v12_prize_race が prize race を重視し、attack-ready を弱める profile になっていることをテスト。

v12 推奨 self-play command

Kaggle T4 での本線収集:

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

v12 推奨 evaluation command

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

v12の完了条件

v12 では勝率だけでなく、次の改善を重視する。

  • normal_wins が増える。
  • avg_prizes_taken が増える。
  • avg_attacks が増える。
  • first_attack_step が短くなる。
  • first_prize_step が短くなる。
  • deck_out_losses が増えない。
  • unfinished が悪化しない。
  • reach attack_reached / reach prize_reached が改善する。
  • replay で攻撃・サイド取得に向かう動きが増える。

詳細な当日ログと判断は 2026-06-27 journal にまとめた。

2026-06-26 追記: 現在の上書き方針

6/24 時点では「Belief-guided teacher search で作った policy/value を NN-only 提出に蒸留する」ことを短期本命としていた。しかしその後の smoke evaluation で、NN-only は攻撃・育成が弱く、pass / deck-out に寄りやすいことが分かった。

そのため、現時点の短期方針は次のように上書きする。

  • v9 は本線にしない。
  • v7 / v9 の構造差をいったん外し、policy_value_v4_best.pt を起点に戻す。
  • 実戦評価は checkpoint-only ではなく、両者 search-ismcts で比較する。
  • Belief Model は ISMCTS を置き換えず、hidden state sampling の prior として使う。
  • training data は Belief-guided ISMCTS teacher で集める。
  • deck-out 勝ちを狙わせるのではなく、deck-out 負けを避ける。
  • 主要指標は normal_wins, avg_prizes_taken, avg_attacks, avg_attack_ready, unfinished, deck_out_losses
  • heuristic reranker は teacher quality の切り分けを難しくするため、当面の本線 self-play では使わない。

詳細な当日ログと判断は 2026-06-26 journal にまとめた。

現在の推奨 teacher setting:

checkpoint: policy_value_v4_best.pt
belief: belief_v10_general_best.pt
search: ISMCTS
determinizations: 8
simulations per determinization: 16
max tree depth: 18
max steps: 180
workers: 8
deck context: disabled
heuristic reranker: off

目的

最終的には、特定デッキだけでなく、デッキリストを入力として複数デッキを自然に回せる汎用的な policy/value model を作る。

現在の短期課題は、勝率だけを上げることではなく、次のような「まともに対戦できる」挙動を増やすことである。

  • アタッカーを育てる。
  • サイド取得につながるエネルギー添付・進化・ベンチ展開を選ぶ。
  • 攻撃してサイドを取る通常勝ちを増やす。
  • deck-out で負ける展開を強く避け、deck-out による偶然の決着を過大評価しない。
  • できるだけ短い step 数で勝つ。

v10 方針の履歴: Belief-Guided Teacher Search + NN-only Submission (6/24案)

2026-06-24 時点で、v9 は本線から外し、v7 SetTransformer prior を起点に元の提案手法へ戻す。中心は Belief Model を hidden-state distribution の推定器として使い、ISMCTS がその分布から複数世界をサンプリングして強い教師ラベルを作る 構成である。

6/24 時点では、実戦・提出時の本命は NN 単体 としていた。online ISMCTS は評価・教師データ生成には使うが、提出では時間・安定性・実装リスクを考えて policy/value model の即決を標準にする、という案である。

ただし 6/26 の検証で NN-only はまだ攻撃・育成が弱いことが分かったため、この提出方針は短期本命から外す。現時点の短期方針は上の「2026-06-26 追記」を優先する。

重要な設計分離:

実際の self-play 行動:
  public observation
  + BeliefNet による opponent hand/deck/prize prior
  + ISMCTS
  -> action

学習用 policy label:
  simulator full observation
  + fixed hidden state oracle search
  -> oracle_policy

提出時:
  public observation のみ
  + Policy/Value Net
  -> action

oracle search は training label 専用であり、実際の行動選択・提出 bundle には使わない。提出時に相手手札が observation に見えていた場合は既存の submission check でエラーにする。提出標準では search を無効化し、BeliefNet も探索用 prior としては使わない。

このため、v10 のデータ生成は二重構造になる。

  • 行動として実際に打つ手は、提出時と同じ public observation + BeliefNet + ISMCTS で選ぶ。
  • oracle_policy は、その局面の教師ラベルだけを作る。CABT の full observation から hidden を固定し、同じ探索を noise off / temperature 0 で回して「その hidden が本当にそうなら強い手」を推定する。
  • 学習時に --policy-target-source oracle を使うと、この full-information teacher policy を policy target にする。ただし value target は実戦結果ベースのまま。
  • 評価では oracle_policy 生成経路を使わず、相手手札は見えない前提で BeliefNet の確率分布から hidden state をサンプリングして online ISMCTS を回す。
  • 提出では oracle_policy も online ISMCTS も使わず、NN 単体で行動を選ぶ。online ISMCTS 評価は「教師探索で作った prior が実際に強いか」を測る診断として使う。

実装済みの v10 変更

  • src/pca/search/ismcts.py
  • information_set_key を public information key に変更した。
  • root observer 視点の public key にし、非 observer の hidden hand/deck/prize の具体カードで tree が分断されにくくした。
  • 非 observer の discard/log card id も hidden token に寄せ、determinization ごとの不要な node split を抑える。
  • 合法手リストは key に残している。hidden によって合法手集合が変わる場合に visit を誤対応させないための保守的な設計であり、完全な public-state abstraction ではない。
  • ISMCTSConfigsimulations=64, max_depth=12, dirichlet_alpha, dirichlet_epsilon, visit_temperature を追加した。
  • root Dirichlet noise と visit-count temperature を追加した。
  • leaf_value fallback は raw policy logits を value に使わず、value 欠損時は 0.0
  • root scores は探索後の Q/visit に統一した。
  • training-only ismcts_policy_with_hidden を追加し、oracle policy target を作れるようにした。

  • src/pca/training/selfplay.py

  • --belief-checkpoint を ISMCTS hidden sampler の prior として使う。
  • --dirichlet-alpha, --dirichlet-epsilon, --visit-temperature を追加した。
  • --oracle-policy-target を追加した。
  • visualize_observation() から full hidden state を取り出し、oracle_policy を JSONL に保存する経路を追加した。
  • actual action は oracle で選ばない。
  • oracle label 生成側は dirichlet_epsilon=0.0, visit_temperature=0.0 に固定し、探索ノイズを教師ラベルへ混ぜない。

  • src/pca/training/targets.py / dataset.py / train.py

  • SearchTrainingTarget.oracle_policy を追加した。
  • --policy-target-source search|oracle を追加した。
  • oracle 指定時も、record に oracle_policy が無ければ従来の search_policy に fallback する。

  • src/pca/evaluation/tournament.py

  • evaluation CLI に --dirichlet-alpha, --dirichlet-epsilon, --visit-temperature, --belief-checkpoint0, --belief-checkpoint1 の search 配線を反映した。
  • evaluation default は noise off: dirichlet_epsilon=0.0, visit_temperature=0.0

  • src/pca/submission/main.py

  • submission default は NN-only。
  • PCA_ENABLE_SEARCH=0 が標準。1 にした場合のみ BeliefNet prior + ISMCTS を使える。
  • search を有効化した場合の default は PCA_ISMCTS_SIMULATIONS=64, PCA_ISMCTS_MAX_DEPTH=12
  • search を有効化した場合も noise off: PCA_ISMCTS_DIRICHLET_EPSILON=0.0, PCA_ISMCTS_VISIT_TEMPERATURE=0.0

v10 学習コマンド

BeliefNet:

PYTHONPATH=src uv run python -m pca.training.belief_train \
  --input data/selfplay/ \
  --output checkpoints/belief_v10_general_final.pt \
  --best-output checkpoints/belief_v10_general_best.pt \
  --epochs 3 \
  --batch-size 64 \
  --learning-rate 0.0001 \
  --card-data pokemon-tcg-ai-battle/EN_Card_Data.csv < belief_bootstrap > .jsonl

v10 self-play:

bash scripts/collect_selfplay_docker.sh \
  --deck0-dir /app/decks/opponents/train \
  --opponent-deck-dir /app/decks/opponents/train \
  --policy search \
  --checkpoint /app/checkpoints/policy_value_v7_settransformer_best.pt \
  --belief-checkpoint /app/checkpoints/belief_v10_general_best.pt \
  --games 300 \
  --workers 4 \
  --max-steps 180 \
  --search-mode ismcts \
  --ismcts-determinizations 8 \
  --ismcts-simulations-per-determinization 8 \
  --search-rollout-depth 12 \
  --dirichlet-alpha 0.3 \
  --dirichlet-epsilon 0.25 \
  --visit-temperature 1.0 \
  --unknown-card-rate 0.05 \
  --oracle-policy-target \
  --card-data /app/pokemon-tcg-ai-battle/EN_Card_Data.csv \
  --output /app/data/selfplay/v10-general-belief-oracle-300g.jsonl

Policy/Value:

PYTHONPATH=src uv run python -m pca.training.train \
  --input data/selfplay/v10-general-belief-oracle-300g.jsonl \
  --init-checkpoint checkpoints/policy_value_v7_settransformer_best.pt \
  --output checkpoints/policy_value_v10_general_belief_oracle_final.pt \
  --best-output checkpoints/policy_value_v10_general_belief_oracle_best.pt \
  --epochs 1 \
  --batch-size 64 \
  --learning-rate 0.00001 \
  --policy-target-source oracle \
  --turn-value-weight 0.0 \
  --deck-out-win-value 0.0 \
  --deck-out-loss-value -1.0 \
  --deck-out-policy-weight 0.25 \
  --unfinished-policy-weight 0.2 \
  --long-game-policy-decay 0.5 \
  --long-game-reference-steps 180 \
  --deck-context-mode set_transformer \
  --card-data pokemon-tcg-ai-battle/EN_Card_Data.csv \
  --init-deck-gate 0.0

Evaluation:

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_v10_general_belief_oracle_best.pt \
  --belief-checkpoint0 /app/checkpoints/belief_v10_general_best.pt \
  --policy1 search-ismcts \
  --checkpoint1 /app/checkpoints/policy_value_v7_settransformer_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 2 \
  --max-steps 180 \
  --ismcts-determinizations 8 \
  --ismcts-simulations-per-determinization 8 \
  --search-rollout-depth 12 \
  --unknown-card-rate 0.05 \
  --output /app/data/eval/v10-general-belief-oracle-vs-v7-holdout.json \
  --csv-output /app/data/eval/v10-general-belief-oracle-vs-v7-holdout.csv

v10の完了条件

  • v7 より normal_wins が増える。
  • deck-out 決着依存が減る。
  • player*_avg_attacks, player*_avg_prizes_taken, player*_ko_count が増える。
  • player*_avg_first_attack_step, player*_avg_first_prize_step, avg_finished_steps が短くなる。
  • replay で、アタッカー育成・active 選択・攻撃選択が増える。

v9 までの履歴メモ

以下の節には v9 時点の分析や旧方針が含まれる。v10 以降の本線は上記の Belief-Guided ISMCTS + Oracle Policy Target である。

初期提案手法との差分

最終提案は docs/research/2026-06-21-belief-guided-neural-ismcts.mdBelief-Guided Neural ISMCTS。現状はその全コンポーネントを実装しているわけではない。後から振り返れるよう、ここに差分を明示する。

初期提案コンポーネント 現状 差分の性質
State Encoder (Transformer) 実装済み (ActionConditionedPolicyValueNet.state_encoder) 一致
Belief Model (相手手札 / 山札 / サイドの確率分布推定) 未実装 意図的な保留
Policy / Value Model 実装済みだが belief 入力は無い (π(a\|s), V(s)) 部分実装
Belief-Guided ISMCTS (複数世界をサンプリングして探索) online ISMCTS 自体はある。unknown_card_rate=0.0 / belief off で 単一仮定の determinization 意図的な簡略化
教師あり pre-training (シミュレータ対戦ログから hidden info を真値ラベル化) スキップ 意図的な省略
探索結果の蒸留 (self-play distillation) 実装済み (search_policy を policy target に) 一致
相手デッキタイプ推定 (latent embedding) 未実装。代わりに 自分デッキ条件付け (SetTransformerDeckEncoder) を実装 方向転換
手書きルール非依存 heuristic reranker (weight=0.05) を scaffolding として導入 意図的な妥協

特に押さえるべき 3 点:

  • Belief Model は基本 off。現状は「Belief なし Neural MCTS」と呼ぶのが正確。復活路は後述「Belief Model 復活路」を参照。
  • ルールベース最小限導入。初期提案の「手書き評価関数不使用」原則から、prize-distance reranker を一時導入している。廃止条件は後述「Heuristic Reranker の廃止条件」を参照。
  • デッキ条件付けの方向転換。初期提案 §9.5 の「相手デッキ latent 推定」ではなく、自分デッキを Set Transformer で条件付ける構成にしている。これは「汎用 policy が複数デッキを扱う」要件に対する現実解として採用したもの。

現在のモデル構造

モデル本体は ActionConditionedPolicyValueNet

入力は CABT の observation と、その時点の合法手リストである。CABT は各局面で合法手数が変わるため、固定 action space ではなく、合法手ごとに action tokens を作り、action-conditioned にスコアを出す。

構造の概略:

observation
  -> state_tokens
  -> token embedding
  -> TransformerEncoder
  -> state_vec

recent logs
  -> history_tokens[event_t]
  -> token embedding mean pool per event
  -> event TransformerEncoder
  -> history_vec

legal options
  -> action_tokens[action_i]
  -> token embedding mean pool
  -> action_encoder
  -> action_vec_i

own deck list
  -> deck card ids
  -> card_id_embedding(raw id identity)
  -> card_feature_embedding(static feature tokens)
  -> concat + card_feature_encoder
  -> SetTransformerDeckEncoder
  -> deck_vec

fusion:
  state_vec + history_gate * fusion(state_vec, history_vec)
  state_vec + deck_gate * fusion(state_vec, deck_vec)

heads:
  policy_head([state_vec, action_vec_i]) -> policy_logits_i
  value_head(state_vec) -> value in [-1, 1]

重要な点:

  • deck_context_modenone / mean / set_transformer
  • history_context_modenone / event_transformer。v12 以降の新しい self-play JSONL では search.history_tokens を保存し、recent logs を時系列 event として直接入れる。
  • この v7/v9 時点の方針では deck_context_mode=set_transformer を本線候補としていた。
  • その後、v10/v11 では teacher search の品質問題を先に切り分けるため、安定本線は一時的に deck_context_mode=none に戻した。
  • 2026-06-28 以降は、現在のデッキを明示的に理解させるため v12 学習 default を deck_context_mode=set_transformer に戻す。
  • 2026-06-28 のモデル構造改善で、deck context は card_id_embeddingcard_feature_embedding を分離した。raw card id はカード個体の identity、static feature token は Pokemon / HP / attack_count / retreat などの汎化特徴を担当する。
  • Set Transformer はデッキを順序なし集合として扱う。
  • init_deck_gate=0.0 で初期化し、既存 prior を壊しにくくしている。
  • init_history_gate=0.0 で初期化し、履歴 branch も既存 prior を壊しにくくしている。
  • pokemon-tcg-ai-battle/EN_Card_Data.csv からカード静的特徴を使う。
  • 効果文の自然言語解析はまだ入れていない。
  • 特性やカード固有コンボは、NN がデータから暗黙に覚えるか、探索 rollout で見える範囲に限られる。

現在のベースライン

主な checkpoint:

v7:
  checkpoints/policy_value_v7_settransformer_best.pt
  Set Transformer deck-aware prior。
  複数デッキ pilot から作った汎用寄り baseline。

v8 / v8b:
  Dragapult Citytop 固定の特化実験。
  deck-out 決着に寄りすぎる問題が見えた。

v9 方針:
  prize-distance board development heuristic を入れた teacher で self-play を取り直す。
  本線は v9-general。

v7 baseline 数値

data/eval/online-ismcts-v7-dragapult-citytop-vs-v6b-holdout.json の summary:

games=100
player0_wins=46    (Dragapult Citytop 側)
player1_wins=23    (v6b holdout 側)
unfinished=31
avg_steps=162.77
avg_finished_steps=146.04

注意:

  • これは Dragapult Citytop 固定 vs v6b holdout の評価で、v9-general (汎用 deck pool 学習) の baseline としては不十分。
  • TODO: v9-general 評価時には、v7 SetTransformer general を train deck pool 全体で同条件評価し、ここに数値を併記する。
  • normal_wins / deck_out_wins の分解はこの JSON にまだ無い。今後の評価では分解した数値を併記する。

自己対戦の教師

学習データは人間の棋譜ではなく、自己対戦で生成する。

teacher policy:

base prior:
  v7 SetTransformer policy/value model

search:
  online ISMCTS
  simulations=8
  rollout_depth=8
  belief は基本 off
  unknown_card_rate=0.0

heuristic:
  heuristic reranker
  weight=0.05

heuristic reranker は training 中には直接呼ばれない。self-play 収集時に teacher の action prior を補正し、その結果として JSONL に保存される search_policyselected_action に間接的に反映される。

つまり:

self-play collection:
  model + ISMCTS + reranker -> JSONL

training:
  JSONL を読む -> model が teacher distribution を模倣

reranker を変更した場合、古い JSONL では新方針が反映されないため、self-play を取り直す必要がある。

Teacher の exploration 設定

ISMCTSConfig (src/pca/search/ismcts.py) に存在するパラメータは c_puct / seed / failed_action_penalty / unknown_card_rate のみ。つまり:

  • Dirichlet noise は無い
  • softmax temperature / visit-count temperature は無い
  • teacher は 決定論的 prior + PUCT exploration のみ で動いている

これは意図的な選択ではなく未対応。AlphaZero 系の self-play では Dirichlet noise (α=0.3 程度) と visit-count temperature (序盤 τ=1.0、終盤 τ→0) を入れるのが定番で、self-play のデータ多様性に寄与する。v10 以降で導入を検討する候補とする。

Heuristic Reranker の現在方針

目的はルールベースで勝つことではなく、未熟な NN prior / search prior を少しだけ整えること。重みは小さく 0.05 から始める。

現在の中心思想:

高打点だから加点しない。
低エネだから加点しない。
高HP / ex / 進化後だから加点しない。

その行動が、近い将来のサイド取得までの距離を短くするなら加点する。

実装済みの補正:

  • 攻撃:
  • legal attack に小さく加点。
  • option-level damage があり、相手 active を KO できるなら、取れるサイド枚数に応じて加点。
  • CABT の attackId とカードDBの技行が未対応なため、直接攻撃の KO 判定ではカードDB最大打点だけを使わない。

  • エネルギー添付:

  • 添付後に、相手 active を倒す route の距離が短くなるなら加点。
  • 色エネを考慮する。
  • 特殊エネルギーは暫定的に任意色 1 個ぶんの wildcard とする。
  • すでに攻撃コストを満たす対象への追加添付は減点しない。

  • 進化:

  • 進化後に相手 active を倒す route が短くなるなら追加加点。
  • 進化そのものにも小さな基礎加点はある。

  • ベンチ展開:

  • 場に出すポケモンが相手 active へのサイド取得 route を持つなら小さく加点。
  • 「強そうなカード」ではなく、サイド取得 route の有無を見る。

  • バトル場選択:

  • 前に出すポケモンがサイド取得 route に近いなら加点。

  • discard:

  • 低採用枚数カード、進化ライン、ACE SPEC、基本エネルギーの discard を減点。
  • 基本エネルギーの減点は残す。エネルギー不足は攻撃不能につながるため。

  • deck-out:

  • 自分の deckCount が 0〜1 など危険な場合、draw/search を減点。
  • 自分 deck が 0 で負ける END を減点。
  • 相手 deck が 0 でも END を直接加点しない。
  • 自分 deckCount が 8 以下の終盤では、攻撃に追加加点し、進展しない PLAY / END / deck touch を減点する。
  • 攻撃可能だから常に END を直接減点する方針は撤回した。問題の主因は END そのものではなく、攻撃できる盤面を作れないまま終盤に入ることだから。
  • ただし v9 replay では、終盤に攻撃候補があるにもかかわらず山札を引いて pass する挙動が残ったため、低山札時だけ no-progress action を抑制する補正を追加した。

未対応:

  • エネルギー添付で発動する特性。
  • カード固有の効果文解析。
  • 特殊エネルギーの正確な効果。
  • 技ごとの正確な damage / attackId 対応。

廃止条件 (NN が heuristic を内面化したかの判定)

reranker は初期提案「手書きルール非依存」原則からの一時的な妥協であり、永続化させない。以下のいずれかを満たしたら廃止判定に入る:

  1. reranker OFF の self-play teacher で取得した eval の normal_wins が、ON 時と差 5% 以内。
  2. reranker weight=0.0 で再学習した policy の normal_wins が、weight=0.05 版と同等以上。
  3. policy 出力 top-3 と reranker 補正後 top-3 の Jaccard が 0.8 以上 (= NN がほぼ heuristic を取り込んだ)。

進行中の段階的削減方針も検討する:

weight: 0.05 → 0.03 → 0.01 → 0.0

各段で normal_wins / avg_finished_steps が悪化しないことを確認して次に進む。判定は v10 以降のサイクルで行う。

学習データの扱い

1つの self-play game から、各 decision point が JSONL record として保存される。

主な record 内容:

search.observation_tokens
search.action_tokens
search.search_policy
search.selected_action
search.final_result
search.turn_value
meta.your_index
meta.result
meta.result_reason
meta.own_deck_card_ids

search.final_result は、その record の current player 視点で付与される。

例:

player0 が勝った試合:
  player0 側 record -> final_result = +1
  player1 側 record -> final_result = -1

負けた側のデータも学習に使う。value は負けとして学ぶ一方、policy target はその局面で teacher が出した分布を模倣する。この点は AlphaZero 系の self-play と似ているが、teacher が未熟な場合は悪い方策も模倣してしまうリスクがある。

教師あり pre-training をスキップした判断

初期提案 §8.1 のシミュレータ対戦ログからの教師あり pre-training (hidden info を真値ラベル化して Belief / Policy / Value を初期化する) は 意図的にスキップ している。

理由:

  • v7 baseline が既に self-play distillation の積み重ねで存在し、それ自体が cold-start prior として十分機能する。
  • 現状 Belief Model 自体が無いため、hidden info ラベルを使う先がない。
  • supervised stage を追加するコストよりも、teacher 改良 (reranker / search) のサイクルを早く回す方が優先度が高いと判断。

cross-reference: Belief Model 復活時 (後述 Stage B) には、この方針が「hidden info supervision として再活性化」する設計とする。

汎用モデルと --player-index

デッキ特化 fine-tune では --player-index 0 を使うことがある。

--player-index 0 あり:
  player0 の decision record だけで学習する。
  Dragapult Citytop 固定など、提出候補デッキ特化に向く。

--player-index なし:
  player0 / player1 の両方の decision record を使う。
  汎用 deck-aware model ではこちらを使う。

汎用モデルでは、deck0-diropponent-deck-dir の両方に train deck pool を使い、両プレイヤーの判断を学習する。各 record には current player の own_deck_card_ids が入るため、Set Transformer deck context が「このデッキではどう動くか」を学べる。

deck-out の扱い

過去の v8 / v8b 実験で、勝敗の多くが deck-out 決着になった。

これは「意図的に相手を deck-out させた」のではなく、攻撃できる盤面を作れず試合が長引き、どちらかが山札を引き切っただけと判断している。

現在の方針:

  • 自分が deck-out で負ける展開を明確に悪く評価する。
  • deck-out で勝った record も通常勝ちとして過大評価しない。
  • --deck-out-win-value 0.0 を使い、deck-out で勝った record の value target を +1 ではなく 0 に下げる。
  • --deck-out-loss-value -1.0 を使い、自分が山札切れで負けた局面を value target -1 として固定する。
  • --deck-out-policy-weight を使い、deck-out game の policy imitation を弱める。
  • --unfinished-policy-weight を使い、unfinished game の policy imitation を弱める。
  • --long-game-policy-decay を使い、長期戦の policy imitation を弱める。

未解決:

  • deck-out / unfinished の policy weight をどの値にするのが最適か。
  • deck-out loss の value は -1.0 固定でよいか。

できるだけ短い勝ちを目指す方針

今後の目的は、勝率だけでなく、短い step 数でサイドを取り切ること。

現在はまだ value target に step penalty は入っていない。今後検討する案:

normal win:
  +1.0 - step_penalty * steps / max_steps

deck-out ending won:
  0.0 〜 +0.2

unfinished:
  0.0 または盤面評価による微調整

loss:
  -1.0

ただし、まずは teacher 側の board development を改善し、通常勝ちが増えるかを確認する。

Belief Model 復活路 (v10+ Roadmap)

初期提案手法の名称そのものを構成する Belief Model は現在 off。永続化を避けるため、復活手順を段階的に定義しておく。

  • --unknown-card-rate0.0 → 0.05 → 0.1 と上げる。
  • Belief 推論モデルは未学習でも、相手手札の uncertainty を一様分布などで導入。
  • 判定: normal_wins / avg_finished_steps が悪化しないか、わずかに向上するか。
  • 悪化しない → Stage B へ。悪化する → Belief 推論モデル無しでは確率化が早すぎる、と判断して保留。

Stage B: 軽量 Belief head の supervised 学習

  • policy_value.pybelief_head を追加 (相手手札に特定カードが存在する確率を出力するヘッド)。
  • self-play log から hidden info を真値ラベルとして教師あり学習 (初期提案 §8.1 をここに集約)。
  • まずは belief 出力を policy / value 入力に 接続しない 状態で精度だけ測る。
  • 判定: 相手手札 top-k 推定精度がランダム baseline を有意に上回るか。

Stage C: Belief embedding を policy / value に配線

  • belief output を state_vec 側に concat、または cross-attention で融合。
  • π(a | s, b), V(s, b) を実現。
  • determinization sample 数を増やし、A* = argmax_a E_b[Q(a | obs, b)] を本格運用。

判断分岐

Stage A 勝率維持 -> Stage B 着手
Stage B 推定精度 OK -> Stage C 配線変更
Stage C で normal_wins が伸びる -> Belief-Guided Neural ISMCTS 完成形

各 stage は独立に評価可能なので、A だけ採用 / B まで採用 / C まで採用、のどこで止めても出せる。

現在推奨する汎用 v9 実験

現在の本線は、Dragapult 固定ではなく、train deck pool 全体を使う v9-general

ただし、レビュー指摘とリプレイ観察を踏まえると、このまま self-play を増やして学習するだけでは不十分。特に、deck-out / 長期戦 / 攻撃できる盤面を作れない問題は、データ量不足だけでなく teacher 品質と学習ターゲット設計の問題でもある。

そのため、v9 は次の順番で進める。

Stage 0: 評価指標を増やす
  deck-out だけでなく、attack_count / KO / prize / first_attack_step を見る。

Stage 1: teacher 単体の sanity check
  v7 + online ISMCTS + reranker が、学習前の時点で通常勝ちを増やすか確認する。

Stage 2: quality-filtered self-play
  全 game を同じ重みで学習しない。
  normal win / normal loss / deck-out / unfinished / long game を分けて扱う。

Stage 3: general model training
  --player-index は外し、両プレイヤー視点を学習する。
  ただし低品質 game の policy target は弱める。

Stage 4: online ISMCTS prior として評価
  checkpoint-only ではなく、提出想定に近い online ISMCTS prior として v7/v9 を比較する。

レビュー後の改訂判断

現時点の重要な判断:

  1. 汎用モデル方針は維持する

デッキごとに専用モデルを作るだけでは、未知デッキや対面の多様性に弱い。Set Transformer deck context によって「同じ policy/value model が、入力デッキに応じて振る舞いを変える」方向を維持する。

  1. ただし、汎用 self-play をそのまま全部模倣しない

現在の teacher はまだ未熟で、攻撃盤面を作れず deck-out / long game に流れることがある。負け局面も学習する方針自体は正しいが、低品質な game の policy target を同じ重みで模倣すると悪い癖も蒸留される。

  1. deck-out 決着は value だけでなく policy 側も弱めるべき

--deck-out-win-value 0.0 は value target の過大評価を防ぐが、policy loss はまだ deck-out game の teacher 行動を模倣する。deck-out が「狙った勝ち筋」ではなく「攻撃できず長引いた結果」なら、policy target も downweight するのが自然。

  1. 短い勝ちは step penalty だけでなく normal win 優先で扱う

ただ短ければよいわけではない。短い deck-out や事故勝ちは評価したくない。優先順位は次の順にする。

normal win with prizes
  > normal loss but fighting game
  > unfinished
 > long game ending by deck-out
  1. reranker は teacher 補助であり、恒久的な勝ち筋ではない

reranker の目的は、未熟な prior が明らかに変な行動を選び続けるのを避け、学習に使える teacher data を増やすこと。最終的には NN が内面化できたかを確認し、weight を下げる。

追加すべき学習ターゲット設計

今後の train/dataset 側に入れたい設計:

policy_weight:
  normal finished game: 1.0
  deck-out ending:      0.2〜0.5
  unfinished:           0.1〜0.3
  very long game:       step 数に応じて減衰

value_target:
  normal win:           +1.0 - small_step_penalty
  normal loss:          -1.0
  deck-out ending won:   0.0〜+0.2
  deck-out loss:        -1.0 (避けるべき敗北として扱う)
  unfinished:            0.0 または turn_value fallback

auxiliary targets:
  可能なら future_prize_delta / next_prize_taken / attack_available_next を追加する。

特に policy_weight は優先度が高い。理由は、現在の最大リスクが「悪い teacher action を policy が真似すること」だから。

Teacher 品質確認の合格条件

v9-general の大規模 self-play に進む前に、teacher 単体で以下を見る。

online ISMCTS(v7 + reranker) vs online ISMCTS(v7 no reranker)
  normal_wins が増える
  deck_out_finishes が減り、normal_wins の比率が増える
  avg_finished_steps が短くなる
  unfinished が増えない
  replay でアタッカー育成・進化・エネ添付が自然になる

この条件を満たさない場合、v9 学習に進まず teacher / reranker / search depth を直す。

2026-06-24 v9 replay で見えた問題

v9-general-prize-distance 後の replay では、勝敗の多くがまだ deck-out に寄り、特に後半で次のような挙動が確認された。

  • 攻撃できる、または攻撃準備に進める候補があるのに、山札を引く/手札を増やす/END に寄る。
  • アタッカーを育ててバトル場に置く前に、山札だけが減っていく。
  • 結果として「通常のサイド取得勝ち」ではなく、相手または自分の deck-out で決着する。

この症状は value_target だけでは直りにくい。なぜなら、self-play teacher が終盤の無進展行動を選んだ時点で、その行動分布が policy target として保存されるからである。

対応として HeuristicRerankerConfig に低山札時の no-progress 抑制を追加した。

late_game_deck_threshold = 8
late_game_attack_bonus
late_game_end_penalty
late_game_no_progress_play_penalty
late_game_deck_touch_penalty

この補正は常時の攻撃強制ではない。deckCount が十分ある序盤・中盤では従来通りで、低山札時だけ「攻撃/進化/エネルギー添付/バトル場準備」より「何も進めない PLAY/END」が選ばれにくくなることを狙う。

次の self-play は、この修正後の teacher で取り直す必要がある。既存の v9-general-prize-distance-300g.jsonl にはこの補正が反映されていない。

v9 self-play コマンドの位置づけ

以下のコマンドは「最終決定版」ではなく、Stage 1 の teacher sanity check が通った後に使う候補とする。

self-play:

bash scripts/collect_selfplay_docker.sh \
  --deck0-dir /app/decks/opponents/train \
  --opponent-deck-dir /app/decks/opponents/train \
  --policy search \
  --checkpoint /app/checkpoints/policy_value_v7_settransformer_best.pt \
  --games 300 \
  --workers 4 \
  --max-steps 180 \
  --search-mode ismcts \
  --ismcts-simulations 8 \
  --search-rollout-depth 8 \
  --unknown-card-rate 0.0 \
  --heuristic-reranker \
  --heuristic-weight 0.05 \
  --card-data /app/pokemon-tcg-ai-battle/EN_Card_Data.csv \
  --output /app/data/selfplay/v9-general-prize-distance-300g.jsonl

training:

PYTHONPATH=src uv run python -m pca.training.train \
  --input data/selfplay/v9-general-prize-distance-300g.jsonl \
  --init-checkpoint checkpoints/policy_value_v7_settransformer_best.pt \
  --output checkpoints/policy_value_v9_general_prizedistance_final.pt \
  --best-output checkpoints/policy_value_v9_general_prizedistance_best.pt \
  --epochs 1 \
  --batch-size 64 \
  --learning-rate 0.00001 \
  --turn-value-weight 0.0 \
  --deck-out-win-value 0.0 \
  --deck-out-loss-value -1.0 \
  --deck-out-policy-weight 0.25 \
  --unfinished-policy-weight 0.2 \
  --long-game-policy-decay 0.5 \
  --long-game-reference-steps 180 \
  --deck-context-mode set_transformer \
  --card-data pokemon-tcg-ai-battle/EN_Card_Data.csv \
  --init-deck-gate 0.0

重要:

  • 汎用モデルでは --player-index を外す。
  • v9 reranker を学習に反映するには、v9 reranker ありで self-play を取り直す必要がある。
  • 古い v8 / v8b JSONL は、現在の prize-distance 方針と一致しない。

2026-06-24 v9-general 評価結果

policy_value_v9_general_prizedistance_best.ptpolicy_value_v7_settransformer_best.pt と比較した。

policy0:
  v9-general-prizedistance
  deck0-dir = decks/opponents/train

policy1:
  v7-settransformer
  deck1-dir = decks/opponents/holdout

search:
  online ISMCTS
  simulations=8
  rollout_depth=8
  unknown_card_rate=0.0

games=170
player0_wins=79
player1_wins=55
unfinished=36
deck_out_finishes=91

player0_deck_out_wins=71
player0_normal_wins=8
player0_avg_attacks=0.57
player0_avg_first_attack_step=82.78
player0_avg_prizes_taken=0.45

player1_deck_out_wins=20
player1_normal_wins=35
player1_avg_attacks=2.52
player1_avg_first_attack_step=65.30
player1_avg_prizes_taken=0.71

解釈:

  • 表面上は player0_wins=79 で v9 が勝って見える。
  • しかし v9 の通常勝ちは 8 のみで、勝敗の大半は deck-out 決着。
  • v9 は v7 より攻撃回数、初攻撃の速さ、サイド取得数が悪い。
  • replay でも、終盤に山札を引いて pass し、アタッカーを育ててバトル場に出せない挙動が確認された。

結論:

  • この v9 checkpoint は本線に昇格しない。
  • この v9 JSONL / checkpoint を次世代 teacher として使うべきではない。
  • 先に teacher 側の低山札 no-progress 抑制、normal win 増加、攻撃/サイド取得指標の改善を確認する。
  • 改善後に self-play を取り直す。既存の v9-general-prize-distance-300g.jsonl は、悪い teacher action を含むため参考データ扱いに留める。

2026-06-24 v10 teacher sanity check

低山札時 no-progress 抑制を入れた reranker を、まず問題が出ていた dragapult-citytop vs garchomp で小規模確認した。

common:
  deck0 = decks/opponents/train/dragapult-citytop.csv
  deck1 = decks/opponents/holdout/garchomp.csv
  policy0 = search-ismcts + v7
  policy1 = search-ismcts + v7
  simulations=8
  rollout_depth=8
  games=5

reranker ON:
  policy0 に heuristic-reranker0 weight=0.05

reranker OFF:
  両者 reranker なし

結果:

reranker ON:
  player0_wins=3
  player0_normal_wins=3
  player0_deck_out_wins=0
  player0_deck_out_losses=2
  player0_avg_attacks=1.4
  player0_avg_first_attack_step=23.67
  player0_avg_first_prize_step=36.67
  player0_avg_prizes_taken=0.6
  avg_finished_steps=60.8

reranker OFF:
  player0_wins=4
  player0_normal_wins=3
  player0_deck_out_wins=1
  player0_deck_out_losses=1
  player0_avg_attacks=3.4
  player0_avg_first_attack_step=29.67
  player0_avg_first_prize_step=65.33
  player0_avg_prizes_taken=0.6
  avg_finished_steps=79.2

解釈:

  • reranker ON は初攻撃と初サイド取得を早めた。
  • ただし normal wins は増えていない。
  • deck-out finishes も減っていない。
  • 攻撃回数はむしろ減った。
  • サンプル数は 5 games なので結論は弱いが、少なくとも このまま大規模 self-play に進む合格結果ではない

判断:

  • v10 self-play 収集にはまだ進まない。
  • 次は teacher の行動選択そのものを改善する。
  • 優先候補は、低山札 no-progress 抑制だけでなく、通常盤面で「攻撃可能な active を作る」「攻撃可能なポケモンを active に出す」方向の補助を強めること。

評価方針

勝率だけでは判断しない。

最低限見る指標:

player0_wins
player1_wins
unfinished
avg_steps
avg_finished_steps
deck_out_finishes
player0_deck_out_wins
player1_deck_out_wins
normal_wins = player_wins - player_deck_out_wins

今後追加したい指標:

attack_count
ko_count
prizes_taken
first_attack_step
first_ko_step
first_prize_step

現時点では、評価 JSON/CSV に deck-out count と、近似的な attack / KO / prize count が入っている。

注意:

  • attack_count は、選択した option が OptionType.ATTACK だった回数。
  • prizes_takenprizeCount の減少から計算する。
  • ko_count は現時点では「サイド取得イベント数」の近似であり、複数 KO や特殊なサイド取得は厳密ではない。
  • first_ko_step はまだ未実装。現状は first_prize_step を見る。

評価で重視すること:

  • 通常勝ちが増えているか。
  • deck-out 決着依存が減っているか。
  • unfinished が増えていないか。
  • avg_finished_steps が短くなっているか。
  • リプレイ上、アタッカー育成・エネ添付・進化・攻撃が自然か。

レビューしてほしい論点

  1. 汎用モデルでは --player-index を外して player0/player1 両方を学習する方針でよいか。
  2. deck-out で勝った record を --deck-out-win-value 0.0 で value 中立扱い、deck-out 負けを --deck-out-loss-value -1.0 で明確な敗北扱いにする方針で十分か。
  3. prize-distance heuristic は、カード効果を読まない範囲で妥当か。
  4. 特殊エネルギーを wildcard 1 個ぶんとして扱う暫定仕様は許容できるか。
  5. attackId とカードDBの技行を対応づける作業を優先すべきか。
  6. 短い勝ちを目指すため、value target に step penalty を入れるべきか。
  7. heuristic-weight=0.05 は妥当か。progressive bias のように探索 visit に応じて薄めるべきか。
  8. v9-general は 300 games から始める方針で十分か。最初から 1000 games 以上を回すべきか。

直近の実装優先順位

レビュー後の方針として、次はこの順番で進める。

  1. 評価ログ拡張

tournament.py / replay summary に以下を追加する。

normal_wins
deck_out_wins
attack_count
first_attack_step
ko_count
prizes_taken
first_prize_step

理由: 現在は「勝ったが deck-out 依存」「負けたが攻撃できていた」などを数値で分けきれていない。

  1. teacher sanity check

学習前に、同じ v7 checkpoint で reranker ON/OFF を比較する。

policy0 = search-ismcts + v7 + reranker
policy1 = search-ismcts + v7 no reranker
deck pool = train / holdout

ここで normal_wins が伸びず deck-out が減らないなら、self-play 収集より reranker/search 修正を優先する。

  1. policy/value sample weighting

dataset.py / train.py に sample weight を追加する。

優先する仕様:

--deck-out-win-value 0.0
--deck-out-loss-value -1.0
--deck-out-policy-weight 0.25
--unfinished-policy-weight 0.2
--long-game-policy-decay 0.5
--long-game-reference-steps 180
--normal-win-step-penalty は未実装

これにより、deck-out / unfinished の行動を policy が強く模倣する問題を抑える。

  1. v9-general self-play

上記 1〜3 の後に、train deck pool 全体で 300 games から開始する。300 games は smoke より大きく、1000 games より回転が速い中間点として使う。結果が良ければ 1000+ games に拡張する。

  1. v9-general training

--player-index を外し、両プレイヤー視点で学習する。これは汎用 deck-aware model のための本線。

  1. v9 evaluation

checkpoint-only ではなく、online ISMCTS prior として評価する。

比較軸:

v7 + online ISMCTS
v9 + online ISMCTS
v9 + online ISMCTS + reranker

目的は、v9 が reranker なしでも v7 より自然に盤面を作れるかを見ること。

v10 Belief制約層

v10 では元の提案手法に戻し、Belief Model は ISMCTS を置き換えず、hidden state distribution の推定器として使う。

ただし BeliefNet の確率推定だけでは不十分で、公開ログから確定できる hidden 情報はシステム側で hard constraint として扱う。

実装方針:

公開観測
  -> PublicKnowledgeTracker が public log / visible zones から確定情報を蓄積
  -> BeliefNet で hand/deck/prize の soft prior を推定
  -> sample_hidden_state で hard constraint を先に固定
  -> 残りスロットだけ BeliefPrior で weighted sampling
  -> ISMCTS の determinization として search_begin に渡す

現在入れた制約:

  • OPPONENT moves Card X: ... -> Hand は、相手手札の固定候補として扱う。
  • OPPONENT moves Card X: ... -> Deck は、相手山札の固定候補として扱う。
  • OPPONENT moves Card X: ... -> Prize は、相手サイドの固定候補として扱う。
  • OPPONENT TakePrize Card X は、公開上そのカードが相手手札に入ったものとして扱う。
  • OPPONENT plays Card X / Hand -> ... は、固定手札候補から外す。
  • 盤面・トラッシュなど visible zone にあるカードは従来通り hidden 候補から差し引く。

PublicKnowledgeTracker の扱い:

  • self-play / evaluation では policy closure ごと、つまり基本的に 1 battle の agent state として保持する。
  • submission ではグローバル agent state として保持し、agent(obs) 呼び出しごとに更新する。
  • CABT の logs は rolling window になりうるため、前回ログ末尾と今回ログ先頭の overlap を見て新規ログだけを処理する。
  • 同じ rolling log を何度も見ることによる known hand の二重加算を避ける。
  • 同じカードが後続ログで play された場合、known hand から外す。

重要な制限:

  • サーチで見たが非公開のまま残った候補、複数カードから選んだ候補、山上/山下の順序などはまだ厳密には扱わない。
  • ログが完全に途切れて overlap が取れない場合は、現在 window を新規として読むため、ログ形式によっては過剰・過少追跡の余地がある。
  • 同名カード複数枚は card id 単位の Counter として扱う。serial 単位の完全追跡ではない。
  • BeliefNet は引き続き必要で、hard constraint で確定できない残りの手札・山・サイドを推定する。

次の改善候補:

  • known_in_hand, known_in_deck, known_in_prize, known_not_in_hand を Counter として管理する。
  • BeliefNet の入力にも tracker summary token を追加し、学習側にも公開確定情報を明示する。
  • CABT の structured log type / area enum を確認し、文字列ログだけでなく enum ベースでより正確に zone movement を読む。

2026-06-28 v12 Seed-Out / Empty Bench Fix

ルールベース AI との対戦で、Active card must be the ID of a Pokémon card.reason=3 の種切れ負けが目立った。前者は Belief 側が active hidden card を推定するときに、エネルギーやトレーナーを active 候補として選べてしまうことが原因だった。CardStaticFeatures.is_pokemonBasic Energy を Pokemon と誤判定していたため、カード種別判定を修正した。

今回の追加方針:

  • hidden active をサンプリングするときは、card_db 由来の Pokemon card id だけを active 候補にする。
  • is_pokemon は category / stage_or_kind の Pokemon 表記を使い、Basic Energy を Pokemon と扱わない。
  • ISMCTS の candidate pruning では、空ベンチ時にベンチへ出せる Pokemon 候補を落とさない。
  • leaf progress value に空ベンチの seed-out risk を入れる。
  • 空ベンチで Pokemon を場に出す行動には小さい safety bonus を入れる。
  • reason=3 で負けた側の record は、value target には負けとして残しつつ、policy imitation だけ low-progress weight で弱める。
  • 評価 summary では pokemon_out_wins/losses/finishes を deck-out と別に集計し、normal win から除外する。

注意点:

  • 場の Pokemon 数を多くするだけの加点は入れていない。
  • サポート役をアタッカー扱いするような card-role heuristic は入れていない。
  • 空ベンチ時の safety bonus は「種切れ負け回避」のための弱い補助で、サイド取得や通常勝ちを置き換える目的ではない。

次の確認:

  • rule-based AI との再戦で Active card must be... が消えるか。
  • pokemon_out_losses が減るか。
  • normal wins / prizes taken / attacks が悪化しないか。
  • replay で初期からベンチを作れているか。

2026-07-02 v13 Aux Prize Targets / Integrated Belief Heads

v13 unified model では、Policy/Value の shared Transformer trunk に補助 head を追加する。目的は、勝敗 value だけでは学習しづらい「サイド取得へ近い局面」と「hidden-state belief」を同じ checkpoint から出せるようにすることである。

追加した head:

  • this_turn_prize_gain_logits: 実教師軌跡で、このターンに自分が取ったサイド枚数 0..6
  • own_prize_completion_logit: decision 時点の残りサイドに対して、以後どれだけ自分がサイドを取り切ったか。
  • opp_prize_completion_logit: 同じ定義の相手側。
  • integrated belief heads: opponent hand / deck / prize、next threat、knockout threat。

ラベル方針:

  • this_turn_prize_gain は oracle 最大値ではなく、self-play / rule teacher が実際に辿った軌跡から作る。
  • completion target は future_gain / current_remaining_prize とし、すでに取ったサイド枚数で値が不自然に縮まらないよう「残りサイドをどれだけ取り切ったか」を見る。
  • unfinished game の completion は mask 0。未完了最終ターンの this-turn target も mask 0。
  • 既存 JSONL は aux が無ければ mask 0 で学習を通す。aux 本格学習には新規 self-play 収集か後処理済み JSONL を使う。

学習の段階:

  1. Phase 1: aux prize heads と integrated belief heads を学習し、loss / coverage / calibration を見る。
  2. Phase 2: v13_aux_prize_race profile で、E[own completion] - E[opp completion] と this-turn prize distribution を小さい重みで ISMCTS leaf tie-break に使う。勝敗 value を置き換えるのではなく、サイド取得に近い leaf を少し優先する。
  3. Phase 3: standalone BeliefNet と integrated belief heads のどちらが hidden-state prior として安定するか、--belief-source auto|separate|policy で比較する。

注意点:

  • aux head が main win value を支配しないよう、loss weight は小さく始める。
  • rule bootstrap と neural self-play ではサイド取得分布が違うため、source ごとの coverage と loss を確認する。
  • integrated belief heads は standalone BeliefNet を置き換える候補だが、互換・比較のため standalone 側は残す。