1 train step ~21 command buffer / ~11 CPU wait のうち、GPU loss chain (ssim → l1combine → rasterize backward → project_backwards → adam) の 9 CB / 9 wait を <strong>1 CB / 1 wait</strong> に、adam 単独 5 CB / 5 wait を 1 CB / 1 wait に統合 (step 全体 ~14 CB / ~5 wait)。dispatch 列・PSO・uniform 値は不変で CB/encoder 境界だけを動かすため <strong>bit-exact</strong> (uniforms は setBytes 化で per-iter の 4B buffer alloc も排除)。grad への CPU RMW (scale_reg / MCMC L1) が有効な iter は adam を CB から外し RMW → adam の数学的順序を厳守。replay bench <strong>final regime 20.87 → 18.00 ms/iter = -13.7% / iter5000 18.60〜19.76 → 16.56〜16.61 = -10.7〜-15.9%</strong>。12.5k full gate n=3: wallclock mean 241.41 → <strong>219.51s (-9.1%)</strong>、PSNR mean <strong>36.170 dB</strong> (W1 基準 36.201 比 -0.031、guard ±0.1 内) → default flip。msplat 同日等価 gap 1.44× → <strong>1.31×</strong>。
HW 4 軸調査 #2 で、1 train step が ~21 command buffer / ~11 CPU wait (msplat は 1 CB / 0 wait) であることを特定した。同一 CB 内の連続 encoder は firmware が CPU 介在なしに back-to-back 実行し、waitUntilCompleted は 0.1〜1 ms 級の full round trip。W2 は dispatch 列 (順序・grid・PSO・uniform 値) を一切変えず、CB/encoder 境界だけを統合する: Stage A は adam の 5 param group (means / log_scales / rot_quats / raw_opacities / sh_coeffs — 互いに素な buffer 集合で hazard なし) を 1 CB / 1 encoder / 5 dispatch に、Stage B は GPU loss 経路の ssim (2 encoder) → l1combine → rasterize backward → project_backwards → adam を 1 CB に連結し、loss scalar / splats_grad の CPU read を commit 後の 1 wait に集約する。encoder 間の read-after-write は Metal tracked resource の自動 hazard 直列化が保証。uniforms は setBytes 渡しにして per-iter の小 buffer alloc (adam 5 本 + loss/ssim 各 1 本) も排除 (値 bytes 同一で数値へ影響なし)。よって bit-exact。grad への CPU RMW (scale_reg / MCMC L1) が有効な iter は adam のみ CB から外し、RMW → adam の数学的順序を legacy と同一に保つ (Stage A の単独 1 CB で実行)。
| 項目 | 内容 |
|---|---|
| Stage A (adam.rs) | `Adam::encode_step` (既存 CB に 1 encoder / 5 dispatch を encode) + `step_chained` (単独 1 CB wrapper)。5 group は互いに素な buffer 集合のため barrier 不要。uniforms は `set_bytes` (legacy は group ごとに `new_buffer_with_data` = 5 alloc/iter) |
| Stage B (train_loop.rs / trainer.rs / ssim.rs / loss.rs) | `SsimEvaluator::encode_forward_and_grad` / `LossEvaluator::encode_l1_only・encode_l1_combine_ssim` / `Trainer::encode_backward_combined_active` (既存 batched backward から encode 部を抽出した共通 refactor) を 1 CB に連結。mean SSIM / loss scalar は wait 後に `read_mean_ssim` / `read_loss_mean` で読む |
| RMW 順序保証 | `scale_reg > 0 || mcmc.scale_eigen_l1 > 0 || mcmc.opacity_l1 > 0` の iter は adam を統合 CB から外す (`adam_done = false`) — RMW (CPU) → refine accumulate → adam の legacy 順序を厳守。regression test あり |
| CB/wait 数 | loss chain 9 CB / 9 wait → **1 / 1**。step 全体 ~21 CB / ~11 wait → **~14 / ~5** (forward 側 pipeline は S1 資産のまま) |
| config 配線 | `BackendConfig.submission = { per_kernel, chained }`、`apply_backend_config` の exhaustive destructuring に配線。Stage B は GPU loss 経路のみ (host loss / L2 は Stage A のみ、train_loop が起動時に note を出す) |
| timing 運用 | chained では per-kernel label (ts_ssim_fwd_grad / ts_backward_raster / ts_adam 等) は **encode コストのみ** を計り、実 GPU 時間は `ts_chain_commit_wait` に集約 (timing.rs 注記)。**per-kernel breakdown 表は per_kernel mode で取得する運用** |
(1) kernel level: adam `step` vs `step_chained` の param/m/v 全 buffer byte 一致 (t=1..3、bias correction の t 依存込み)。ssim encode 版 vs 自己完結版の mean SSIM bits + grad byte 一致。loss encode 版 2 本の dldr byte 一致 (loss scalar は atomic reduce のため rel 1e-5)。(2) train_step level: single-texel fixture (dldr 1 element のみ非ゼロ → atomic 累積が決定的) で PerKernel vs Chained の iter 1 の loss bits + adam 後 param/m/v byte 一致 — L1 GPU 経路 / host loss (Stage A 単独) / scale_reg RMW 順序の 3 構成。複数 iter は tolerance 比較 + L1+SSIM 経路も tolerance で PASS。(3) production-scale (`splat bench --parity`、Lego 409k splats): tile_offsets byte 一致 + 全 grad buffer PASS (残差 max 2.8e-5 = 既知の atomic 順序非決定性、loss diff 7.4e-8)。
worktree 実装時に書かれた parity test は「single-texel なら 2 iter でも byte 一致」を仮定していたが、GPU 実行で反証された: iter 1 の adam step で param が全域微動 → iter 2 の L1 sign-grad (±1/N) がほぼ全 pixel で非ゼロ → loss_sum atomic reduce + rasterize backward atomic float の加算順非決定性 (C7) により、同一 mode の 2 run 間ですら iter 2 は 1-2 ulp 差 (probe test で実測、3/3 再現)。byte 一致の要求は iter 1 に限定し、fixture の決定性前提は恒久 guard test (`per_kernel_single_texel_run_to_run_deterministic_1iter`) で防衛、複数 iter は tolerance 比較とした。判定への影響なし (chained 固有の差は存在しない)。
| metric | per_kernel (baseline) | chained | Δ |
|---|---|---|---|
| **final regime total** | 20.869 ms/iter (σ 0.95%) | 18.005 ms/iter (σ 0.27%) | **-13.7%** (閾値 max(2σ,1%)=1.9%) |
| final (clean batch 帯) | 20.87〜21.50 | 17.99〜18.02 | -13.7〜-16.2% |
| **iter5000 regime total** | 18.60〜19.76 (clean 4 batch) | 16.56〜16.61 (σ ≤0.75%、4 連続 batch) | **-10.7〜-15.9%** (閾値 ≤2.8%) |
| per-kernel 対照 (per_kernel mode、final) | ts_adam 2.50 ms/call + ts_ssim 2.93 + ts_backward 5.17 (wait 込み) | encode 0.10 / 0.10 / 0.10 ms + `ts_chain_commit_wait` 7.17 ms | chain 統合で wait 重複が消えた分が total 差 (~2.9 ms/iter) と整合 |
計 14 invocation 中 3 window で全 kernel が一様に +15〜25% 遅くなる slow mode を観測 (per_kernel / chained の両方に発生)。W1 gate と同じ config 非依存の系統外 interference と判定し、σ が正常な batch (per_kernel σ ≤1.6% / chained σ ≤0.8%) を採用。chained final は 3 clean batch で 17.99 / 18.00 / 18.02 と 0.1% 内に再現、iter5000 chained は 4 連続 batch で 16.56〜16.61。なお同日朝の W1 replay (19.30 ms/iter) と本 session の per_kernel baseline (20.87) の差は日内 drift — A/B は同 session 内の対で判定。
| rep | wallclock (training) | PSNR (100 views) | final splats |
|---|---|---|---|
| rep1 | 213.42s | 36.160 dB | 408,258 |
| rep2 | 224.83s | 36.203 dB | 407,135 |
| rep3 | 220.27s | 36.146 dB | 413,223 |
| **n=3 mean** | **219.51s** | **36.170 dB** | — |
| W1 baseline (n=3 mean) | 241.41s | 36.201 dB | — |
| **Δ** | **-9.1%** | -0.031 dB (guard ±0.1 内) | — |
replay 有意閾値 max(2σ,1%) を 5 倍超過、PSNR guard は n=3 mean で通過。1k smoke は loss curve が iter 500 まで有効数字 4-5 桁一致 (以降は refine の atomic 由来分岐で noise 圏、PSNR Δ ±0.02 dB)、grad RMW あり構成 (scale_reg = 0.001) も同様に一致し順序保証を確認。expected gate 帯 -5〜15% のほぼ上限 (-13.7% replay / -9.1% full)。PerKernel は A/B baseline + per-kernel timing 用に enum 保持。Stage C (indirect dispatch で pair_count readback 除去 → radix まで統合) は未実施 — W4 (untracked heap + fence) と合わせて期待値を再見積りする。
| 時点 | Lego 12.5k | msplat 同日実測比 (167.7s) | 備考 |
|---|---|---|---|
| W1 (warp sparse skip + exp-skip) | 241.41s | 1.44× | p2-w1-warp-sparse-skip |
| **+ W2 (encoder/CB 統合)** | **219.51s** | **1.31×** | 本 finding、-9.1% — 累計 766.07 → 219.51s = **-71.3%、全て数学的同値の施策のみ** |
12.5k chained run の breakdown (per-CB 粒度): forward 30.0% (radix_sort 18.0% 内数、rasterize 5.6% / project 3.7% / emit_pairs 2.0%) / chain_commit_wait 26.0% (ssim + l1combine + backward + project_back + adam の GPU 実時間) / refine 系 3.2%。forward pipeline (特に radix) が単独最大の律速になった。1× 工程表 v2 の順序どおり counter session (HW-3) で limiter を確定し、W3a (SSIM float4)・W3b (Splat2D 48B 化)・W4 (untracked heap + Stage C) の優先度を実測に従わせる。
この finding が観測された / 言及している実験 run。