コンテンツにスキップ

サーバー学習手順

更新日: 2026-07-11

この文書は、サーバーまたは長時間実行環境で self-play 収集、Policy/Value 学習、評価前チェックを回すための現行 runbook である。古い version 固有の script ではなく、pca コマンドと configs/default.yaml を入口にする。

方針

現行の標準パイプラインは Belief-Guided Neural ISMCTS self-play -> unified Policy/Value 学習 である。

  • self-play は configs/default.yamlselfplay-train に定義された最新 config を使う。
  • Policy/Value checkpoint は unified model を前提にし、aux prize heads と integrated belief heads も同じ checkpoint に含める。
  • standalone BeliefNet は互換用または個別実験用であり、通常の反復学習では必須ではない。
  • 長時間 run は chunk に分け、--resume で再開できるようにする。
  • 学習後は固定デッキの promotion benchmark を実行する。既定では直前Championとの直接対戦、またはrule-poolの非回帰評価のどちらかを通過したcandidateでlatest aliasを更新する。

前提

repo root で実行する。環境は Python 3.12 と uv を前提にする。

uv sync
source .venv/bin/activate
pca commands

direnv を使っている場合は、direnv allow 後に pca をそのまま実行できる。

direnv allow
pca commands

必要な asset の目安:

pokemon-tcg-ai-battle/EN_Card_Data.csv
decks/own/
decks/opponents/
checkpoints/policy_value_latest_best.pt

現在のデフォルトは configs/default.yaml にまとまっている。コマンドごとの実体は次の通り。

Command Default
pca selfplay configs/v14/selfplay-gumbel-sh-ismcts.yaml
pca train configs/v13/train-policy-unified-selfplay.yaml
pca eval configs/v14/evaluate-gumbel-sh-vs-rule.yaml
pca selfplay-train scripts/run_selfplay_train.sh
初期 checkpoint checkpoints/policy_value_latest_best.pt
固定 model deck configs/benchmarks/model-decks-v1.yaml
champion 対戦条件 configs/benchmarks/evaluate-model-head-to-head.yaml

標準 self-play は root Gumbel sequential halving、4 determinizations、各120 simulations(1 decision あたり合計480 simulations)を使う。過去runの再現やA/B比較では、v13のvisit設定を明示的に指定する。ローカルCPUではworker間の推論競合を避けるため既定を1 workerとし、GPUサーバーでは --workersを実測に合わせて上書きする。

実行内容だけ確認したい場合は --print-command を使う。

pca --print-command selfplay-train --games 10 --workers 2

推奨する実行単位

長時間 self-play は、1つの巨大ファイルを一気に作るのではなく、chunk に分けて実行する。1000 games を 100 games x 10 chunk で収集してから 1 回学習する例:

pca selfplay-train \
  --run-name ismcts-selfplay-1000g \
  --chunks 10 \
  --games-per-chunk 100 \
  --workers 8 \
  --train-device mps \
  --resume

Linux/CUDA サーバーでは --train-device cuda、CPU 検証では --train-device cpu を使う。self-play は multiprocessing と安定性を優先し、デフォルトで CPU を使う。必要な場合だけ --selfplay-device を上書きする。

pca selfplay-train \
  --run-name cuda-selfplay-1000g \
  --chunks 10 \
  --games-per-chunk 100 \
  --workers 16 \
  --train-device cuda \
  --resume

反復学習

「N 試合 self-play するたびに学習し、その best checkpoint を次の self-play に使う」場合は、--total-games--games-per-cycle を使う。

合計 10,000 games を 1,000 games ごとに学習する例:

pca selfplay-train \
  --checkpoint checkpoints/policy_value_latest_best.pt \
  --run-name ismcts-iterative-10k \
  --total-games 10000 \
  --games-per-cycle 1000 \
  --chunks 10 \
  --workers 8 \
  --train-device mps \
  --resume

この例では、各 cycle が 1,000 games で、--chunks 10 によって 1 cycle が 100 games x 10 chunk に分割される。cycle 1 の学習が終わると、cycle 2 の self-play は cycle 1 の best checkpoint から始まる。各candidateは同じbenchmarkから二段階で判定する。完了試合勝率52%以上なら正式Champion、50%以上ならTraining Championとして次cycleのself-playとtrainだけを前進させる。既定のOR判定では、rule-poolの回帰条件だけを満たした場合も正式Championへ昇格する。直接対戦とrule-poolのどちらも満たさない場合にだけ同じdataからretryを学習し、retryも不合格ならseriesを停止する。

学習入力は、直近cycleを全件使用したうえで、過去のpromotion済みcycleを追加する。既定値は次の通り。

recent: 直近のtrain対象gameを100%使用
history: 過去3 promoted cycleからrecent game数の25%を追加
history weights: 最新 / 中間 / 最古 = 50% / 30% / 20%

例えば直近が1,000 gamesなら、過去から最大250 gamesをgame単位で選び、合計1,250 games相当を学習する。試合長によりrecord数の比率は多少変わる。既定では直近gameの5%をvalidationとして分離し、残りのtrain gamesを100%使用する。validationは履歴replayを含まないため、各cycleで新たに生成した対戦への汎化を確認できる。

pca selfplay-train \
  --replay-history-cycles 3 \
  --replay-history-ratio 0.25 \
  --replay-history-weights 0.5,0.3,0.2 \
  ...

train終了時には logs/selfplay-train/<run-name>-<run-id>.train-metrics.json にfinal/bestのtrain lossとvalidation lossを保存する。best checkpointは val_loss が最小のepochを選ぶ。 --validation-ratio 0 を指定するとvalidationを無効化できる。

学習の再試行

既定profileは--train-attempts 3を使う。状態遷移は次の通り。

  1. attempt 1をTraining Championから学習し、固定の正式Championに対してpromotionを実行する。
  2. 直接対戦の正式基準52%、またはrule-poolの非回帰基準を満たせば両Championを更新する。どちらも満たさず、直接対戦の学習継続基準50%だけを満たす場合はTraining Championだけを更新し、retryせず次cycleへ進む。
  3. 両基準で不合格ならattempt 2と3を、同じtrain/validation splitと同じTraining Championから独立に学習する。
  4. retry群はval_loss最小の1候補だけを選び、promotionを一度だけ再実行する。
  5. 再度両基準で不合格ならaliasを維持し、既定の--promotion-reject-action stopで次cycleへ進まない。

既定recipeはattempt 2でlearning rateを5e-6へ下げ、attempt 3ではさらに policy-target-temperature=1.5まで上げてGumbel targetをsoftenする。全attemptは不合格candidateではなく同じChampionから開始するため、失敗した更新を累積しない。設定は次で上書きできる。

pca selfplay-train \
  --train-attempts 3 \
  --train-attempt-learning-rates default,0.000005,0.000005 \
  --train-attempt-policy-temperatures default,1.25,1.5 \
  --promotion-reject-action stop \
  ...

train-attempts.jsonには全candidateの条件とvalidation score、選択attemptを保存する。複数candidateを同じpromotion benchmarkへ順番に当てないため、52%を偶然超えるまで試す選択バイアスを抑えている。

正式昇格またはTraining Champion昇格したcycleだけが data/replay/<run-name>/promoted.yaml に登録される。両基準で却下されたcycleや、過去sampleを混ぜた出力そのものは登録しない。比較実験で直近だけを使う場合は --no-replay を指定する。

既定の promotion gate は次を行う。

  1. 固定7デッキで candidate と直前 champion を同一 deck、同一 seed で対戦する。
  2. player 0 / player 1 を入れ替え、先後の偏りを相殺する。
  3. candidate と champion を同じ rule-agent pool に当て、deck ごとの macro win rate を比較する。
  4. 既定の--promotion-criteria-mode anyでは、完了試合勝率52%以上、またはrule win rate・unfinished・pokemon-out lossの全回帰条件が許容範囲なら正式昇格する。
  5. 正式基準をどちらも満たさず、完了試合勝率が50%以上ならTraining Championへ昇格する。

--promotion-criteria-mode allを指定すると、直接対戦とrule-poolの両方を正式昇格とTraining Champion昇格に必須とする。判定結果はpromotion-benchmark.jsonpromotion_gateに保存され、 head_to_head_passedrule_pool_passedcriteria_modeから通過経路を確認できる。

Training Championはcheckpoints/policy_value_training_latest_best.ptへ保存し、反復run内では次cycleのself-playとwarm startに使う。正式なpolicy_value_latest_best.ptは52%を満たすまで更新しない。benchmarkの比較対象も正式Championに固定するため、50%の小さな更新を積み重ねながら正式基準への到達を確認できる。

固定7デッキ、rule-agent 16デッキ、既定値では、初回評価は次の364試合になる。

Candidate vs Champion: 7 x 10 x 2 directions = 140
Candidate vs rule pool: 7 x 16 x 1 = 112
Champion vs rule pool: 7 x 16 x 1 = 112

Champion の rule-pool 結果は data/eval/promotion-gate/cache/ に保存する。2 cycle 目以降は、前 cycle の promoted Candidate または据え置かれた Champion の結果を再利用するため、通常は140 + 112 = 252試合になる。--promotion-seed は self-play seed と分離され、既定値0で固定される。

cache は checkpoint、deck、config、評価実装、試合数、worker、device、seedのfingerprintが一致する場合だけ使う。再計測したい場合は --no-promotion-rule-cache を指定するか、別の --promotion-seed を使う。

評価 artifact は data/eval/promotion-gate/<run-name>-<run-id>-attemptNNN/ に保存される。短い疎通確認などで評価を省略する場合は --no-promotion-gate を明示する。この場合は学習完了後に latest alias が無条件更新されるため、通常の長時間学習には使わない。

MPS/CUDA で self-play 推論だけを軽くしたい場合は --selfplay-precision fp16 を追加する。各 cycle の train は直前 cycle の fp32 best checkpoint を warm start に使い、self-play stage だけ checkpoints/quantized/<run_name>/*_fp16.pt に変換した checkpoint を読む。CPU self-play では fp16 が速くならないことが多いため、基本は --selfplay-device mps または cuda と組み合わせて使う。

複数の NVIDIA GPU があるサーバーでは、--selfplay-devices auto を指定すると visible な CUDA device をすべて検出し、self-play worker を cuda:0,cuda:1,... へ round-robin に割り当てる。明示したい場合は --selfplay-devices cuda:0,cuda:2 のようにカンマ区切りで指定する。

途中で止まった場合は、同じ --run-name--run-id--resume で再実行する。run id を固定しておくと再開しやすい。

pca selfplay-train \
  --checkpoint checkpoints/policy_value_latest_best.pt \
  --run-name ismcts-iterative-10k \
  --run-id 20260705-120000 \
  --total-games 10000 \
  --games-per-cycle 1000 \
  --chunks 10 \
  --workers 8 \
  --train-device mps \
  --resume

再開時の挙動:

  • chunk JSONL と summary CSV がそろっている chunk は skip する。
  • --resume 付きで best checkpoint が既にある train stage は skip する。
  • train途中ではattemptごとの*.train-state.ptからmodel、optimizer、RNG、epoch内batch位置を復元する。V14は3,000 micro-batchごとに保存する。MPSではmps_driverが22,000 MiBへ達した場合もoptimizer更新境界で保存し、その直後にtrain processを自動で置き換えてMPSGraph memoryを解放する。CUDA/CPUではprocessを置き換えない。
  • streaming stateにはJSONL byte cursorとshuffle buffer referenceを含むため、新形式stateからの再開で巨大なtrain入力を先頭から読み直さない。旧stateからの初回再開だけはprefix replayが必要になる。
  • cycle 実行では、次 cycle の checkpoint が直前の promoted best checkpoint に自動で切り替わる。
  • .promotion-statuspromoted / training_promoted / rejected として残り、--resume 時は完了済み判定を再利用する。
  • retryごとのcheckpoint、metrics、promotion statusもattempt suffix付きで残り、完了済みattemptはskipする。

出力

主な生成物:

生成物 パス
chunk JSONL data/selfplay/<run-name>-<run-id>/<run-name>-partNNN.jsonl
merged JSONL data/selfplay/<run-name>-<run-id>.jsonl
agent summary *.agent-summary.csv
agent matchup summary *.agent-matchup.csv
deck summary *.deck-summary.csv
search diagnostics *.search-diagnostics.csv
final checkpoint checkpoints/policy_value_<run_name>_<run_id>_final.pt
best checkpoint checkpoints/policy_value_<run_name>_<run_id>_best.pt
run manifest logs/selfplay-train/<run-name>-<run-id>.manifest.yaml
run ledger logs/selfplay-train/<run-name>-<run-id>.ledger.yaml
live metrics logs/selfplay-train/<run-name>-<run-id>.metrics.jsonl
train attempts logs/selfplay-train/<run-name>-<run-id>.train-attempts.json
per-game metrics data/selfplay/<run-name>-<run-id>.game-metrics.jsonl
MLflow run ID logs/selfplay-train/<run-name>-<run-id>.mlflow-run-id
logs logs/selfplay-train/<run-id>-*.log
promotion benchmark data/eval/promotion-gate/<run-name>-<run-id>-attemptNNN/
promotion rule cache data/eval/promotion-gate/cache/
promotion status <best-checkpoint>.promotion-status
replay registry data/replay/<run-name>/promoted.yaml
replay sample data/replay/<run-name>/<run-id>-history.jsonl
replay summary data/replay/<run-name>/<run-id>-history-summary.json

学習が完了し promotion gate に合格すると latest alias が更新される。却下された candidate checkpoint と評価結果も削除されず、調査用 artifact として残る。

train-compareなどpipeline外で作ったcheckpointは、promotion-runが合格しても自動ではaliasを更新しない。評価済みCandidateを正式採用するときは pca promote-checkpointを使う。このコマンドは評価artifactのhashと現在Championを確認し、latest alias、cycle manifest、run ledger、replay registryを同じ採用単位で同期する。

Alias Meaning
checkpoints/policy_value_latest_best.pt 最後に完了した学習 run の best checkpoint。
checkpoints/policy_value_latest_final.pt 最後に完了した学習 run の final checkpoint。
checkpoints/policy_value_<run_name>_latest_best.pt 同じ run name 内の latest best checkpoint。
checkpoints/policy_value_<run_name>_latest_final.pt 同じ run name 内の latest final checkpoint。
checkpoints/policy_value_latest.yaml latest alias が指す実体、run name、run id、config、run manifest。

run manifest には、初期 checkpoint、self-play config、train config、chunk 数、train 入力、checkpoint 出力、promotion gate、latest alias 更新状態が残る。途中停止後は、同じ --run-name--run-id で再実行する前に manifest の selfplay.statustraining.statuslatest.status を見る。

uv sync --group mlops済みの環境では、通常のpca selfplay-trainがMLflowへ試合単位と集計metric、15秒間隔のsystem metrics、stage/validation/代表・異常gameのtraceを自動記録する。 mise run mlflow:uiを起動し、http://127.0.0.1:5050から同じrun IDの全cycleを親runの推移グラフと子run一覧で確認できる。子runではcycle内のloss、selfplay/game/*の試合時系列、探索統計、promotion結果を確認し、Tracesから処理時間や異常gameを調査する。詳細はMLOps Pipelineを参照する。

反復runでは、個別manifestを横断しなくてもよいようにrun ledgerも更新される。champion.best_cyclechampion.best_checkpoint が現在の最良checkpointを示し、cycles には各cycleのpromotion判定、head-to-head勝率、rule-pool macro勝率、Replay追加ゲーム数が並ぶ。

次の self-play、eval、submission bundle では、基本的に checkpoints/policy_value_latest_best.pt を使う。

pca selfplay \
  --checkpoint checkpoints/policy_value_latest_best.pt \
  --output data/selfplay/latest-smoke.jsonl \
  --games 4 \
  --workers 2

小さな疎通確認

大量実行の前に、同じ入口で小さく動かす。

pca selfplay-train \
  --run-name smoke-selfplay-train \
  --games 4 \
  --workers 2 \
  --train-device cpu \
  --resume

コマンド展開だけ見る場合:

pca --print-command selfplay-train \
  --run-name smoke-selfplay-train \
  --games 4 \
  --workers 2 \
  --train-device cpu

self-play だけ確認したい場合:

pca selfplay \
  --output data/selfplay/smoke.jsonl \
  --games 2 \
  --workers 2 \
  --device cpu

確認するログ:

fallback=0
search begin > 0
ismcts dec > 0
nn calls > 0
depth avg が 2 以上
reach attack_reached / prize_reached が出る

fallback が連続して出る場合、その JSONL は teacher search として弱い。大量学習に進む前に例外、checkpoint load、card metadata、belief source を確認する。

Policy・Value学習だけを再実行する

self-play JSONL が既にある場合は train stage だけ実行できる。

pca selfplay-train \
  --skip-selfplay \
  --selfplay-output data/selfplay/ismcts-selfplay-1000g-20260705-120000.jsonl \
  --run-name ismcts-selfplay-1000g \
  --run-id 20260705-120000-retrain \
  --checkpoint checkpoints/policy_value_latest_best.pt \
  --train-device mps

より直接的に学習する場合:

pca train \
  --input data/selfplay/ismcts-selfplay-1000g-20260705-120000.jsonl \
  --init-checkpoint checkpoints/policy_value_latest_best.pt \
  --output checkpoints/policy_value_retrain_final.pt \
  --best-output checkpoints/policy_value_retrain_best.pt \
  --device mps

大きな JSONL では config 側の streaming を使う。CLI で明示する場合:

pca train \
  --input data/selfplay/large-selfplay.jsonl \
  --output checkpoints/policy_value_large_final.pt \
  --best-output checkpoints/policy_value_large_best.pt \
  --streaming \
  --device cuda

Belief学習

通常の unified self-play / train では integrated belief heads を使うため、別 checkpoint の BeliefNet 学習は必須ではない。standalone belief checkpoint を別実験で使う場合だけ実行する。

pca belief-train \
  --input data/selfplay/example.jsonl \
  --output checkpoints/belief_final.pt \
  --best-output checkpoints/belief_best.pt \
  --device mps

No usable belief records found が出る場合は、self-play 収集時に full-observation targets が入っているか、JSONL が壊れていないかを確認する。

評価

学習後は小さな評価で動作確認してから、games / workers を増やす。

pca eval \
  --checkpoint0 checkpoints/policy_value_latest_best.pt \
  --games 20 \
  --workers 4 \
  --device cpu \
  --output data/eval/latest-smoke.json \
  --csv-output data/eval/latest-smoke.csv

rule agent pool 相手のデフォルト評価:

pca eval \
  --checkpoint0 checkpoints/policy_value_latest_best.pt \
  --games 100 \
  --workers 8 \
  --device cpu \
  --output data/eval/latest-vs-rule.json \
  --csv-output data/eval/latest-vs-rule.csv

探索方式や config の変更を比較する場合:

pca eval-ab \
  --set games=100 \
  --set workers=8 \
  --set device=cpu

pca eval-ab は baseline / experiment の evaluation config を同じ override で順番に実行し、 data/eval/ab/<run-name>/eval-ab.metrics.csv に差分を保存する。片側だけ条件を変える場合は --baseline-set KEY=VALUE または --experiment-set KEY=VALUE を使う。

評価で見る指標:

  • normal_wins
  • avg_prizes_taken
  • avg_attacks
  • avg_first_attack_step
  • avg_first_prize_step
  • deck_out_losses
  • unfinished
  • attack_ready_count

deck-out 勝ちだけ増える場合は、teacher search または value target がサイド取得に十分寄っていない可能性がある。

ログの読み方

self-play ログの重要部分:

search begin=... step=... end=... full_obs=... fallback=...
nn calls=... cache=hit/miss total=... fwd=...
[local-policy-batcher] requests=... batches=... avg_batch=... req/s=...
ismcts dec=... sim=... hidden=... time=...
depth avg=... max=... hist=...
reach turn_advance=... attack_reached=... prize_reached=...
root-actions sel play=... attach=... attack=... choice=...
prize-delta events=... taken=... value=...
perf elapsed=... speed=... progress=... remaining=... eta=...

見る順番:

  1. fallback
  2. 0 が望ましい。増える場合は search が落ちて NN-only fallback になっている。
  3. depth avg
  4. 2 以上を目安に見る。1 台だとほぼ root 付近しか見ていない。
  5. reach
  6. attack_reached / prize_reached が極端に低いと、探索が攻撃・サイド取得に届いていない。
  7. nn fwd
  8. 最大ボトルネックになりやすい。local-policy-batching を使う場合は [local-policy-batcher] avg_batch も見る。
  9. perf progress / remaining / eta
  10. 並列 self-play では一番遅い worker の eta が全体完了の目安になる。
  11. taken / remain
  12. サイド取得が増えているかを見る。deck-out や pokemon-out だけで終わるデータは品質が低い。

training ログで見る項目:

loss policy value aux belief policy_w aux_cov belief_cov lr grad
[memory] rss mps_alloc mps_driver mps_limit
Wrote best checkpoint ...
Wrote checkpoint ...

MPSのmps_allocが横ばいなのにmps_driverだけが継続的に増える場合、live tensorではなく可変input shapeに対応するMPSGraph cacheが増えている可能性がある。V14はbatch-padding-mode=mps_stableで通常範囲のshapeを固定し、 mps-restart-driver-memory-mb=22000でOOM前に自動再起動する。ログにrestarting process ... because MPS driver memory ...、続いてexec restartが出た後、同じstateから再開すれば正常である。watermark無効化はsystem memoryを使い切る危険があるため標準手順にはしない。

JSONL の保全

長時間実行後は、生成された JSONL と summary CSV を消さないようにする。最低限、行数と先頭 record を確認する。

wc -l data/selfplay/ismcts-selfplay-1000g-20260705-120000.jsonl
head -n 1 data/selfplay/ismcts-selfplay-1000g-20260705-120000.jsonl

別環境へ移す場合は、JSONL と対応する checkpoint manifest を一緒に残す。

data/selfplay/<run>.jsonl
data/selfplay/<run>/*.csv
checkpoints/policy_value_<run>_best.pt
checkpoints/policy_value_latest.yaml

推奨サイクル

  1. pca selfplay-train --games 4 で smoke。
  2. pca selfplay-train --chunks 10 --games-per-chunk 100 で 1,000 games 収集と学習。
  3. pca eval --checkpoint0 checkpoints/policy_value_latest_best.pt で rule agent pool と評価。
  4. 問題なければ --total-games / --games-per-cycle で反復学習に進む。
  5. 良い checkpoint は run-name scoped alias と manifest を残す。

1 回で大きく強くするより、teacher search と value head を少しずつ改善しながら反復する。

関連ドキュメント