調査メモ: Beliefを利用するニューラルISMCTS¶
更新日: 2026-06-28
Note: この文書は初期提案メモであり、現在の実装方針とは一部異なる。現行仕様は ../architecture/current-method.md を優先する。現在は NN-only ではなく、Policy/Value Net と ISMCTS を実戦でも組み合わせる方針である。oracle policy target は実験用に残しているが、v12 本線では使わない。
目的¶
Kaggle の Pokemon TCG AI Battle Challenge に向けて、ポケモンカードゲームの不完全情報、ランダム性、長期リソース管理、サイドレース、複合アクションに対応できるモデル構成を検討する。
今回の結論は、最終提案手法として Belief-Guided Neural ISMCTS for Pokemon Card Game を採用すること。
Belief Model
+ Policy Model
+ Value Model
+ Information Set MCTS
= Belief-Guided Neural ISMCTS Agent
コンペ前提¶
確認した前提:
- コンペは Pokemon TCG AI Battle Challenge。
- Simulation Category では Kaggle 上でエージェント同士が CABT Engine により対戦する。
- Strategy Category では、学習方法、設計判断、洞察、手法の説明が評価される。
- 提出は通常の
submission.csvではなく、main.pyとdeck.csvを含む agent bundle。 - 初回の
obs.select is Noneのとき、エージェントは 60 枚デッキを返す。 - 通常の選択時は、
obs.select.optionの合法手 index のリストを返す。 - 返す index 数は
minCount <= len(selected) <= maxCountを満たす必要がある。
重要な制約:
- 相手の手札、山札順、サイド落ちは非公開。
- ドロー、シャッフル、コイントス、カード効果によるランダム性がある。
- 1ターン中に、手札使用、進化、エネルギー添付、特性、攻撃、各種対象選択など複数ステップの意思決定がある。
- 持ち時間制約があるため、深い探索だけに依存する構成は危険。
CABT API 前提¶
CABT の observation は大きく以下の形。
Observation
├─ current
│ ├─ turn / turnActionCount / yourIndex / firstPlayer
│ ├─ supporterPlayed / stadiumPlayed / energyAttached / retreated
│ ├─ stadium
│ └─ players[0..1]
│ ├─ active
│ ├─ bench
│ ├─ deckCount
│ ├─ discard
│ ├─ prize
│ ├─ handCount
│ └─ hand # 自分のみ見える。相手は None
├─ logs
│ └─ DRAW / PLAY / ATTACH / EVOLVE / ATTACK / HP_CHANGE / COIN / RESULT ...
└─ select
├─ type
├─ context
├─ minCount / maxCount
├─ option[]
└─ deck / contextCard / effect
探索 API は次の方向で使う。
search_begin(agent_observation, your_deck, your_prize, opponent_deck, opponent_prize, opponent_hand, opponent_active, manual_coin=False)search_step(search_id, select)search_end()search_release(search_id)
search_begin() は非公開情報の推定リストを要求するため、Belief Model / belief
sampler が探索品質に直結する。
なぜ通常 MCTS では足りないか¶
通常の MCTS は完全情報の局面を前提にする。
ポケカでは、同じ公開盤面でも以下の世界が同時にあり得る。
- 相手がボスの指令を持っている世界
- 相手がエネルギーを引けない世界
- キーカードが相手サイドに落ちている世界
- 次ドローで入れ替え札を引く世界
- 自分のサイドに必要カードが埋まっている世界
1つの完全状態を決め打ちして探索すると、その仮定にだけ強い手を選びやすい。そこで、情報集合単位で複数のあり得る hidden state を扱う ISMCTS が必要になる。
提案手法¶
1. State Encoder¶
Observation と select.option をニューラルネットワーク向けに token 化する。
含める特徴:
- 自分の active / bench / hand / discard / prize
- 相手の公開 active / bench / discard / prize count / hand count
- deck count、turn、turnActionCount
- supporter / stadium / energy attachment / retreat 使用状態
- HP、ダメージ、付与エネルギー、tool、pre-evolution
- poisoned / burned / asleep / paralyzed / confused
- 直近 logs
select.optionの action type / context / target fields
実装場所:
src/pca/features/encoder.py
2. Belief Model¶
非公開情報を確率分布として推定する。
予測対象:
P(opponent hand | observation, history)
P(opponent deck remaining | observation, history)
P(opponent prize cards | observation, history)
P(next threat card | observation, history)
P(knockout threat | observation, history)
実装場所:
src/pca/models/belief.pysrc/pca/search/belief.py
初期版では、公開情報と deck prior から矛盾の少ない hidden
state をサンプリングする。学習が進んだら、BeliefNet の logits を sampler の重みに使う。
3. Policy Model¶
CABT の select.option は局面ごとに変化するため、固定アクション分類ではなく action-conditioned
policy にする。
policy_logits = f(state_tokens, action_tokens)
Policy Model は ISMCTS の PUCT prior として使う。
実装場所:
src/pca/models/policy_value.pysrc/pca/decision/policy.py
4. Value Model¶
現在局面からの勝率を推定する。
value = V(state_tokens, belief)
評価対象:
- サイドレース
- 次ターンのきぜつ可能性
- 山札切れ
- 手札枚数とリソース
- エネルギー供給
- 進化準備
- アタッカー継続性
初期実装では Policy/Value 同一ネットワークの value head とし、後で belief embedding を加える。
5. Belief-Guided ISMCTS¶
推論手順:
observationとlegal actionsを受け取る。- State Encoder で token 化する。
- Belief Model / sampler で hidden state を複数生成する。
- 各 hidden state で探索する。
- Policy Model を prior に使う。
- Value Model を leaf evaluation に使う。
- 各サンプルの探索結果を情報集合単位で統合する。
- 期待値が最も高い action index を返す。
実装順:
- Determinized UCT
- 複数 hidden state を作る。
- 各 world の root score / visit を合算する。
- サンプル実装からの改善として最初に入れる。
- Single-tree ISMCTS
- ノードを完全状態ではなく情報集合で共有する。
- strategy fusion を減らす。
- Neural ISMCTS
- Policy prior、Value leaf evaluation、Belief prior を接続する。
実装場所:
src/pca/search/determinized.py- 後続で
src/pca/search/ismcts.pyを追加予定。
学習計画¶
Stage 1: 教師あり学習¶
自己対戦またはシミュレーションログから以下を作る。
- observation tokens
- legal action tokens
- selected action
- final result
- hidden state labels
Belief Model:
- 学習時のみ完全情報を使い、相手手札・山札・サイドを教師にする。
Policy Model:
- 勝利プレイヤーの行動、または探索で高評価だった行動を教師にする。
Value Model:
- 各局面から最終勝敗を予測する。
Stage 2: 自己対戦¶
モデルを使って自己対戦し、以下を保存する。
SearchTrainingTargetBeliefTrainingTargetSelfPlayRecord
実装場所:
src/pca/training/targets.py- 後続で
src/pca/training/selfplay.py
Stage 3: 探索結果の蒸留¶
深い ISMCTS の探索分布を Policy Model に学習させる。
L_policy = CE(pi_search, pi_model)
L_value = MSE(z, V)
L_belief = BCE(hidden_zone_labels, belief_logits)
提出時は局面により探索量を切り替える。
- 通常局面: Policy Model + shallow search
- 重要局面: deeper search
- 終盤: Value Model 重視
- 時間不足: Policy Model のみ
ポケカ特化の工夫¶
サイドレース¶
残りサイド枚数、相手が次に何枚サイドを取れるか、自分が何回のきぜつで勝てるかを Value Model に学習させる。
非公開情報の推定¶
相手手札・山札・サイド落ちを明示的に belief として扱う。特に、ボスの指令、入れ替え札、エネルギー、サポートの所持可能性は重要。
コンボと行動順序¶
同じカードを使う場合でも順序で結果が変わるため、直近 logs と turnActionCount を入力に含める。将来的には turn-level action sequence encoder を追加する。
リソース管理¶
手札、山札、トラッシュ、エネルギー、サポート使用権、進化権、ベンチ枠を State Encoder に含める。
デッキタイプ推定¶
相手の公開カードと行動履歴から deck-type latent embedding を推定し、Belief Model の prior に使う。これは Strategy Category で説明しやすい差別化要素になる。
現在の実装状態¶
実装済み:
src/pca/cabt/card_db.pyEN_Card_Data.csvを読み、カード種別、HP、逃げエネ、ワザ数などの静的特徴を提供CardVocabularyで card_id を contiguous belief target index に変換し、vocab hash を生成src/pca/features/encoder.py- CABT dict/dataclass observation の tokenization
- 任意の
CardDatabaseから静的カード特徴を token に追加 src/pca/models/policy_value.py- Action-conditioned Policy/Value network skeleton
src/pca/models/belief.py- BeliefNet skeleton
src/pca/search/belief.py- 公開情報と deck prior からの hidden state sampling
- BeliefNet の logits / dict prior を使う weighted sampler
- BeliefNet output を raw card_id keyed
BeliefPriorに変換 - BCE logits を sampler 用の bounded probability weight として使用
src/pca/search/determinized.py- Determinized policy の初期骨格
BeliefPriorを hidden state sampling に渡す接続src/pca/training/targets.py- 自己対戦・belief 学習ターゲット型
src/pca/training/selfplay.py- CABT battle API から
SelfPlayRecordを生成 - JSONL 書き出し
python -m pca.training.selfplayCLI- CABT
visualize_data()の完全状態からBeliefTrainingTargetを抽出 src/pca/training/dataset.py- SelfPlayRecord JSONL の読み込み
- Policy/Value 学習用の batch collation
- Belief 学習用の multi-hot target 化と batch collation
- Belief target の raw card_id を
CardVocabularyindex へ変換 src/pca/training/train.py- Policy/Value の最小学習CLI
torch導入済みdata/selfplay/docker-smoke.jsonlで CPU 1 epoch の smoke training 済みsrc/pca/training/belief_train.py- BeliefNet の最小学習CLI
- opponent hand / deck / prize / next threat を multi-label BCE で学習
- knockout threat scalar を BCE で学習
- checkpoint に
card_vocab_hashと card id list を保存 src/pca/evaluation/tournament.py- head-to-head 評価
- 勝敗、平均step、policy別平均推論時間を集計
- 終局試合と未完了試合の平均stepを分離して集計
scripts/evaluate_docker.sh- Mac から Linux amd64 Docker 経由で CABT head-to-head 評価
scripts/collect_selfplay_docker.sh- Mac から Linux amd64 Docker 経由で CABT 自己対戦JSONLを収集
data/selfplay/belief-smoke.jsonlで belief label 入り JSONL 生成を確認src/pca/submission/main.py- checkpoint なしでも合法手を返す Policy-only fallback 提出 entrypoint
policy_value.ptが同梱されている場合はActionConditionedPolicyValueNetをロードして neural policy を使用belief.ptが同梱されている場合はBeliefNetと card vocab metadata を任意ロード- Belief checkpoint の
card_vocab_hashを検証し、card id list を保持 - 提出時 observation から
BeliefPriorを生成できる helper を追加 src/pca/submission/build_bundle.pymain.py、deck.csv、pca/package を含む提出 bundle 作成--checkpoint指定時はpolicy_value.ptとして同梱--belief-checkpoint指定時はbelief.ptとして同梱/private/tmp/pokemon-card-ai-belief-smoke.tar.gzでbelief.pt同梱を確認tests/test_encoder.py- encoder / policy / belief / target schema / card DB の smoke tests
tests/test_training.py- belief batch collation と BeliefNet loss の smoke tests
- Claude レビュー対応
- encoder のデフォルトを公開情報 view に固定し、相手手札・サイドなどの hidden card ID が policy/value tokens に混ざらないようにした
extract_belief_target()を追加し、完全情報がある場合だけ hidden labels をBeliefTrainingTargetに分離して保存する構造にしたSearchTrainingTargetにmin_count/max_count/belief_summary、SelfPlayRecordにmetaを追加したdeterminized_policy()は Search API なしなら determinization 風の no-op ループを回さず root policy を返す契約にしたActionConditionedPolicyValueNet.forward()にbelief_summaryの拡張口を追加し、action tokens は state Transformer ではなく軽量 action encoder に通すようにした- submission checkpoint load は
model_configを読み、失敗時は stderr に理由を出すようにした
次にやること:
submission/main.py- BeliefPrior を Search API / determinized search に接続する。
training/selfplay.pyknockout_threatやnext_threat_card_idsの教師ラベルを強化する。evaluation/tournament.py- checkpoint世代の総当たり、複数デッキ評価、集計CSV出力を追加する。
search/ismcts.py- Single-tree ISMCTS の実装に着手する。
- Claude レビューの残項目
- BeliefNet prior を
determinized_policy()/ Search API 呼び出しの本番経路へ接続 - Belief calibration の実測評価