コンテンツにスキップ

調査メモ: 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.pydeck.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

Observationselect.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.py
  • src/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.py
  • src/pca/decision/policy.py

4. Value Model

現在局面からの勝率を推定する。

value = V(state_tokens, belief)

評価対象:

  • サイドレース
  • 次ターンのきぜつ可能性
  • 山札切れ
  • 手札枚数とリソース
  • エネルギー供給
  • 進化準備
  • アタッカー継続性

初期実装では Policy/Value 同一ネットワークの value head とし、後で belief embedding を加える。

5. Belief-Guided ISMCTS

推論手順:

  1. observationlegal actions を受け取る。
  2. State Encoder で token 化する。
  3. Belief Model / sampler で hidden state を複数生成する。
  4. 各 hidden state で探索する。
  5. Policy Model を prior に使う。
  6. Value Model を leaf evaluation に使う。
  7. 各サンプルの探索結果を情報集合単位で統合する。
  8. 期待値が最も高い action index を返す。

実装順:

  1. Determinized UCT
  2. 複数 hidden state を作る。
  3. 各 world の root score / visit を合算する。
  4. サンプル実装からの改善として最初に入れる。
  5. Single-tree ISMCTS
  6. ノードを完全状態ではなく情報集合で共有する。
  7. strategy fusion を減らす。
  8. Neural ISMCTS
  9. 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: 自己対戦

モデルを使って自己対戦し、以下を保存する。

  • SearchTrainingTarget
  • BeliefTrainingTarget
  • SelfPlayRecord

実装場所:

  • 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.py
  • EN_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.selfplay CLI
  • 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 を CardVocabulary index へ変換
  • 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.py
  • main.pydeck.csvpca/ package を含む提出 bundle 作成
  • --checkpoint 指定時は policy_value.pt として同梱
  • --belief-checkpoint 指定時は belief.pt として同梱
  • /private/tmp/pokemon-card-ai-belief-smoke.tar.gzbelief.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 に分離して保存する構造にした
  • SearchTrainingTargetmin_count / max_count / belief_summarySelfPlayRecordmeta を追加した
  • 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 に理由を出すようにした

次にやること:

  1. submission/main.py
  2. BeliefPrior を Search API / determinized search に接続する。
  3. training/selfplay.py
  4. knockout_threatnext_threat_card_ids の教師ラベルを強化する。
  5. evaluation/tournament.py
  6. checkpoint世代の総当たり、複数デッキ評価、集計CSV出力を追加する。
  7. search/ismcts.py
  8. Single-tree ISMCTS の実装に着手する。
  9. Claude レビューの残項目
  10. BeliefNet prior を determinized_policy() / Search API 呼び出しの本番経路へ接続
  11. Belief calibration の実測評価

関連ドキュメント