Skip to content

GPU リスコア driver を追加 (--rescore-input で教師 pool を i16 score sidecar に relabel) - #411

Merged
SH11235 merged 6 commits into
mainfrom
feat/rescore-driver
Sep 6, 2026
Merged

SH11235 merged 6 commits into
mainfrom
feat/rescore-driver

Conversation

@SH11235

@SH11235 SH11235 commented Sep 5, 2026

Copy link
Copy Markdown
Owner

概要

GPU リスコア driver を追加する。教師 pool PSV の全 record を学習済み LayerStack net の 1-node 静的評価 (forward のみ) で relabel し、little-endian i16 の score sidecar (<入力名>.scores.i16) を出力する — チェス Stockfish の大 net (BT4/4096 級) による教師 relabel の将棋版基盤。

nnue-train --rescore-input pool.psv --rescore-output scores/ \
  --rescore-score-scale 1200 --batch-size 65536 \
  layerstack --init-from net.bin \
  --ft-out 3072 --l1 16 --l2 32 --num-buckets 9 \
  --bucket-mode progresskpabs --progress-coeff progress.bin

構成: OrderedPsvLoader (#409、順序保存並列 decode) → GpuTrainer::forward_step (validate の forward から loss kernel を外した抽出、forward-only trainer #408) → ScoreSidecarWriter (#409、marker/resume/fail-closed)。--rescore-score-scale は既定なしの明示必須 (net 世代の nnue2score)。学習系 filter・低精度 flag (--tf32 / --ft-fp16 系) との併用は明示 reject し、ラベルは常に strict fp32 forward で作る。

実測 (sh11235 / RTX 3080 Ti, 12GB — LayerStack 3072x16x32 halfka-hm-merged net, nodchip 系教師 100M 行)

  • 800k pos/s (125.0s / 100M 行、定常 800.3±0.3k)、GPU util P50 98%、VRAM max 4622 MiB、RSS 1.6GB (入力サイズ非依存の streaming)
  • 目標 ≥1M pos/s は未達 (8 割)。batch sweep (16384/32768/65536 × 20M 行 = 800.6k/798.2k/792.7k でフラット) + util 98% により、律速は driver でなく純 forward kernel のこの net での実力と切り分け済み — kernel 側最適化は別 issue 相当。CPU 静的評価 (16T) 比 ~3.6×、15.5B 行 pool ≈ 5.4h
  • batch サイズ非依存の bit 決定論を実証: sweep の 3 sidecar が sha256 完全一致

fail-closed 設計

  • LoadedArtifact: net / progress 係数の sha256 をロードに使った byte 列そのものから計算 (.bin / 係数は一括読み → 同一 buffer から parse、.ckpt は stream hash → 直後ロード → stat 等値検証)。.done 昇格前に入力 / net / 係数の現物を stat で再検証
  • build identity: build.rs が TATARA_BUILD_COMMIT (git short + dirty 印) を埋め込み (HEAD / index / common git dir の refs / packed-refs を rerun 追従)。unknown / dirty build では fingerprint に起動ごとの nonce を混ぜ、完了 skip と resume を無効化 (campaign は clean checkout build が前提)
  • canonical path 統一: --init-from / --resume / --progress-coeff / --rescore-input を起動時に 1 回だけ canonicalize し、hash・ロード・loader worker open・最終検証の全消費を同じ実体に固定
  • fingerprint / .meta.json を単一の key=value リストから生成: net sha256、weights source (fp32_dequantised = .bin / fp32_master = .ckpt)、arch + threat/effect/factorizer/PSQT/shared-delta の全 provenance、routing、progress 係数 sha256、score 変換 (f32 bits 込み)、batch_size、tool version + git commit
  • 残余リスクの明文化: 内容 hash で守られるのは .bin / 係数のみ。.ckpt と入力 PSV は size+mtime 検証で、mtime を書き戻した同サイズ置換は検出できない (quickstart / module doc に記載し、その挙動自体をテストで固定)
  • 非有限出力・入力の途中変化・不正 record は全て硬いエラー (sidecar の行対応を無言で壊す経路なし)

テスト

  • GPU e2e: 行数 / validate forward との i16 一致 / 決定論 / 完了 skip / 件数 resume の bit 一致 / score_scale 変更での再生成 / .meta.json 検証
  • host: LoadedArtifact の差し替え検出 (読み中 / 事後 / mtime 書き戻しの限界)、fingerprint のビルド識別 + provenance、昇格前検証、CLI reject 経路 (必須 flag 欠落・併用不可・clip/batch 下限)
  • quickstart (en/ja) に利用手順と制約を記載

検証記録

  • bash scripts/local-ci.sh フル PASS (sh11235 / ubuntu-3080ti、レビュー各巡で再実行)
  • Windows 側 fmt / clippy -D warnings / host テスト green
  • 独立レビュー (Codex) 4 巡: high 4 件 (tool identity 不足 / ロードと hash の TOCTOU / エラー経路ほか) → medium → doc コメント 1 件まで収束し解消

🤖 Generated with Claude Code

SH11235 and others added 5 commits September 6, 2026 05:53
…を出力)

教師 pool PSV の全 record を学習済み LayerStack net の 1-node 静的評価で
relabel する経路。OrderedPsvLoader (順序保存並列 decode) と ScoreSidecarWriter
(marker/resume/fail-closed) を forward-only trainer に配線する。

- CLI: --rescore-input / --rescore-output / --rescore-score-scale (既定なし・
  明示必須。net 世代の nnue2score を渡す) / --rescore-score-clip (既定は
  rescore_psv と同じ 10000)。--data 系 filter・--eval-only・threat 診断・
  低精度 flag (--tf32 / --ft-fp16 / --ft-fp16-out / --fp16-opt-state /
  --all-optim) との併用は明示 reject (ラベルは strict fp32)。progresskpabs は
  --progress-coeff 必須 (学習側の全 bucket 4 縮退を持ち込まない)。simple では
  reject。--init-from (.bin) / --resume (.ckpt) 両対応
- GpuTrainer::forward_step: validate の forward から loss kernel を外した
  net_output 取り出し (StepOptions の forward_output で loss 手前 early return)
- fingerprint: net path/size/sha256、weights source 種別、arch / feature_set /
  bucket_mode / num_buckets、progress 係数 sha256、score 変換 (bits 込み)、
  batch_size、tool version。text marker (resume 判定) と .meta.json
  (fp32_dequantised / fp32_master のラベル種別・変換式込み) を単一の key=value
  リストから生成
- 変換: score = clamp(round(net_output * scale), ±clip)。非有限出力は
  fail-closed の硬いエラー
- テスト: GPU e2e (行数 / validate forward との i16 一致 / 決定論 / 完了 skip /
  件数 resume の bit 一致 / score_scale 変更での再生成 / .meta.json)、CLI 検証
  reject 経路 (host-only)。quickstart doc (en/ja) に節を追加

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- net / progress 係数の sha256 をロードに使った byte 列そのものから計算する
  (LoadedArtifact)。.bin と係数は一括読み → 同一 buffer から parse、.ckpt は
  stream hash → 直後にロード → stat 等値検証。ロード後に path を開き直す方式は
  その間の差し替えで誤った識別情報が完成 sidecar に付く
- .done 昇格前に入力 / net / 係数の現物を stat で再検証し、実行中の差し替え・
  上書きを硬いエラーにする
- fingerprint に git commit (dirty 印付き、experiment.json と同じ取得方式) を
  追加 — crate version が同じ別実装で旧 sidecar を無言 skip しない
- arch provenance を完全化: threat_profile / effect_bucket / ft_factorize mode /
  psqt / stack_shared_delta を fingerprint と .meta.json の両方へ
- --rescore-score-clip に 1..=i16::MAX の CLI 制約、rescore 経路の --batch-size
  に >= 16 の下限 (0 は %16 検査を素通りする)、学習範囲検査の免除を
  training_range_exempt helper に集約して rescore にも適用
- ShogiProgressKPAbs::load_from_bytes を追加 (load_from_bin は委譲)
- テスト: identity の差し替え検出 (読み中 / 事後)、fingerprint のビルド識別と
  provenance キー、昇格前検証の入力差し替え検出、clip / batch-size の reject、
  免除 helper

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nonical に統一

- git commit の埋め込みを runtime の CWD 依存呼び出しから build.rs の
  build 時埋め込み (TATARA_BUILD_COMMIT、HEAD/index の rerun 追従) に変更。
  runtime 方式は tatara 外で unknown、別 repo 内で無関係 commit になり binary の
  identity として成立しない
- unknown / dirty build は「同じ識別で別内容の binary」があり得るため、
  fingerprint に起動ごとの nonce を混ぜて完了 skip と resume を無効化する
  (毎回最初から再生成 + 警告。campaign は clean checkout build が前提。方針は
  module doc / build.rs / quickstart に記載)
- identity の hash / ロード / loader open / 最終検証を起動時に 1 回 canonicalize
  した path に統一 (--init-from / --resume / --progress-coeff / --rescore-input)。
  symlink 差し替えで「hash した物」と「読んだ物」が乖離する経路を閉じる
- stat 検証の残余リスク (同サイズ + mtime 書き戻しの置換は検出不能。内容 hash で
  守られるのは .bin / 係数のみ) を quickstart (en/ja)・module doc・
  verify_unchanged doc に明記し、mtime 書き戻し置換が stat 検証を通過して
  sha256 だけが乖離することを固定するテストを追加

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- LoadedArtifact::{from_loaded_bytes, hash_file} と Fingerprint::build 内の
  再 canonicalize を除去。解決は training.rs の起動時 1 箇所だけとし、helper は
  解決済み path をそのまま保持・使用する (2 回の解決の間の symlink 差し替えで
  「ロード・hash・worker open・最終検証が同一実体を見る」不変条件が崩れるため。
  契約は各 helper の doc に明記)
- build.rs の rerun-if-changed に common git dir の refs/ (directory walk) と
  packed-refs を追加。branch の実体 ref は worktree gitdir でなく共有側にあり、
  ref だけ動く更新では worktree の HEAD が変わらず TATARA_BUILD_COMMIT が
  stale になっていた。個別 ref file は pack で消えるため directory ごと追跡し、
  packed-refs は存在時のみ登録 (不存在 path の登録は毎 build 再実行になる)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
commit の変化は HEAD / index / refs / packed-refs 追跡で再ビルドされる。
index 変化まで反映されない制約は未 staged 編集の dirty 判定にのみ残る。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 5, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-05T22:10:39.901316Z c1b3078 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c1b3078865

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


let mut pairs: Vec<(&'static str, String)> = vec![
("version", "1".to_string()),
("mode", "gpu-nnue-fp32".to_string()),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include the CUDA backend in the fingerprint

When a clean checkout builds both the default native binary and an oxide/oxide-parity binary at the same commit, this fingerprint is identical even though the selected kernels are different; the repository's parity tests explicitly allow FMA-related numerical differences (native_cuda_tests.rs:24-26), which can cross an i16 rounding boundary. Reusing the same output directory therefore lets the second backend accept the first backend's .done marker and skip rescoring instead of producing its own labels. Record the selected backend—and for cuda-oxide, the loaded kernel artifact identity—in the fingerprint.

AGENTS.md reference: AGENTS.md:L121-L122

Useful? React with 👍 / 👎.

Comment on lines 91 to 94
if cli.data.is_some()
|| cli.eval_only
|| cli.rescore_input.is_some()
|| cli.threat_ablate.is_some()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Dispatch incomplete rescore options to validation

If a user specifies --rescore-output or --rescore-score-scale but accidentally omits --rescore-input, neither condition enters run_training; the command falls through to smoke_test and can exit successfully. Consequently, the explicit rejection in validate_rescore_cli is unreachable from the actual binary for precisely these incomplete invocations. Include the auxiliary rescore options in this dispatch condition so the intended validation error is emitted rather than silently ignoring them.

Useful? React with 👍 / 👎.

…d code を解消

GitHub CI の --no-default-features 構成では rescore 経路 (GPU gate 下) から
呼ばれず、cfg(any(gpu, test)) の test 側だけで compile されて未使用になる。
reject 行列を直接呼び出しで固定する ungated テストを追加し、non-GPU CI に
検証ロジックのカバレッジを持たせる形で消費する (run 経路越しの配線検証は
既存の GPU gated テストが担当)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@SH11235
SH11235 merged commit 29196b8 into main Sep 6, 2026
1 check passed
@SH11235
SH11235 deleted the feat/rescore-driver branch September 6, 2026 07:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant