[{"data":1,"prerenderedAt":213},["ShallowReactive",2],{"finding:a-9-f16-forward-negative":3,"finding-runs:a-9-f16-forward-negative":156,"finding-related:a-9-f16-forward-negative":179},{"meta":4,"impact":29,"sections":36},{"id":5,"title":6,"subtitle":7,"eyebrow":8,"date":9,"status":10,"category":11,"polarity":12,"axes":13,"tags":15,"task_code":22,"related_runs":23,"related_findings":26},"a-9-f16-forward-negative","A.9 f16 forward — half3 accumulator が underflow + cast overhead で二重 negative","rasterize forward の per-pixel RGB accumulator を half3 化 (中間計算は f32 維持) した試行。env SPLAT_F16_FORWARD=1 で kernel 切替。30k bench で PSNR 14.873 dB (-10.0 dB) \u002F wallclock 40m40s (+75%)、二重 negative finding。","Negative finding · Mixed precision","2026-05-23","stable","experiment","negative",[14],3,[16,17,18,19,20,21],"phase-5","f16","mixed-precision","metal","underflow","apple-silicon","A.9",[24,25],"lego-sh3-30k","lego-a9-f16-30k",[27,28],"a-10-kahan-negative","a-7-icb-batching-plan",{"summary":30,"rank":31,"verdict":32,"delta_psnr":33,"delta_wallclock":34,"delta_splats":35},"half3 per-pixel accumulator が low-T 領域 (alpha * T \u003C 6e-5) で underflow → 寄与 splat の累積消失で PSNR -10.0 dB。さらに half↔float cast が compute bound でも重く wallclock +75%。Apple Silicon SIMD は half と float が同 throughput、bandwidth bound でないので f16 化は loss-only。","high","rejected","-10.006 dB (14.873 vs 24.879)","+75.1% (2439.73s vs 1393s)","+13.3% (94,900 vs 83,734)",[37,40,57,60,70,73,75,116,118,120,123,125,127,129,131,133,135,140,142,148,150],{"type":38,"text":39},"lead","\u003Ccode>render_splats_f16\u003C\u002Fcode> kernel (per-pixel \u003Ccode>half3 pix_out\u003C\u002Fcode> accumulator + 中間計算 f32 維持) を \u003Ccode>shaders\u002Fforward\u002Frasterize.metal\u003C\u002Fcode> に追加し、env \u003Ccode>SPLAT_F16_FORWARD=1\u003C\u002Fcode> で切替可能にした。30k bench (lego sh=3, seed=42, capacity=1M) で baseline 24.879 dB \u002F 23m13s に対し PSNR \u003Cstrong>14.873 dB (-10.0 dB)\u003C\u002Fstrong> + wallclock \u003Cstrong>40m40s (+75%)\u003C\u002Fstrong>、精度と速度の二重悪化が確定。Negative finding。",{"type":41,"items":42},"kv",[43,45,48,51,54],{"key":44,"value":9},"実装日",{"key":46,"value":47},"前提 baseline","lego-sh3-30k 24.879 dB \u002F 23m13s \u002F 83,734 splats, seed=42",{"key":49,"value":50},"本 run","lego-a9-f16-30k 14.873 dB \u002F 40m40s \u002F 94,900 splats, seed=42",{"key":52,"value":53},"config","configs\u002F2026-05-23-0700-lego-a9-f16-30k.toml",{"key":55,"value":56},"活性化","env SPLAT_F16_FORWARD=1 (rasterize.rs::forward の pso 切替)",{"type":58,"text":59},"heading","実装方針",{"type":61,"ordered":62,"items":63},"list",true,[64,65,66,67,68,69],"\u003Ccode>shaders\u002Fforward\u002Frasterize.metal\u003C\u002Fcode> に \u003Ccode>render_splats_f16\u003C\u002Fcode> を新規追加、\u003Ccode>render_splats_f32\u003C\u002Fcode> をコピーして \u003Ccode>float3 pix_out\u003C\u002Fcode> → \u003Ccode>half3 pix_out\u003C\u002Fcode> に変更","中間計算 (sigma \u002F alpha \u002F exp \u002F T \u002F next_T) は \u003Cstrong>f32 維持\u003C\u002Fstrong> (under flow 防止)","term の add 累積のみ half 化: \u003Ccode>pix_out += half3(rgb * (alpha * T))\u003C\u002Fcode>","出力 \u003Ccode>float4\u003C\u002Fcode> は f32 維持 (loss 計算 \u002F backward path は変更なし)、出力時に \u003Ccode>float3(pix_out)\u003C\u002Fcode> で cast","\u003Ccode>rasterize.rs\u003C\u002Fcode> に \u003Ccode>pso_forward_f16\u003C\u002Fcode> field 追加、\u003Ccode>forward()\u003C\u002Fcode> 内で env 確認して pso 切替 (Trainer API は不変)","cargo test 23\u002F23 pass (既存 f32 path は変更ナシ)",{"type":71,"lang":19,"text":72},"code","half3 pix_out = half3(0.0h);\nfloat T       = 1.0f;\n\u002F\u002F 中間計算は f32 維持\nfloat alpha = min(0.999f, splat.color_a * exp(-sigma));\nfloat next_T = T * (1.0f - alpha);\nfloat3 rgb = float3(splat.color_r, splat.color_g, splat.color_b);\n\u002F\u002F term は f32 で計算、half に cast して accumulate\npix_out += half3(rgb * (alpha * T));\nT = next_T;\n",{"type":58,"text":74},"結果",{"type":76,"columns":77,"align":82,"rows":85,"caption":115},"table",[78,79,80,81],"metric","baseline (f32 forward)","A.9 (f16 forward)","Δ",[83,84,84,84],"left","right",[86,91,96,101,106,110],[87,88,89,90],"PSNR (val 100 views)","24.879 dB","14.873 dB","-10.006 dB",[92,93,94,95],"wallclock (30k iter)","23m13s (1393s)","40m40s (2439.73s)","+1046.73s (+75.1%)",[97,98,99,100],"ms\u002Fiter (avg)","46.4 ms","81.3 ms","+34.9 ms (+75.2%)",[102,103,104,105],"ms\u002Fiter (early, iter 1-2k)","~46 ms","~50 ms","+4 ms (+8.7%)",[107,103,108,109],"ms\u002Fiter (late, iter 24k+)","~99 ms","+53 ms (+115%)",[111,112,113,114],"final splats","83,734","94,900","+11,166 (+13.3%)","wallclock 悪化は iter 進行とともに加速 — splats 増加で per-pixel 寄与 splat 数 (≈ tile load 回数) が増え、half↔float cast の compute コストが顕在化",{"type":58,"text":117},"原因分析",{"type":58,"level":14,"text":119},"(1) half3 accumulator の low-T underflow",{"type":121,"text":122},"paragraph","front-to-back α 合成では、後段 splat ほど \u003Ccode>T\u003C\u002Fcode> (transmittance) が小さくなる。具体的に \u003Ccode>T &lt; 1e-3\u003C\u002Fcode> 領域では \u003Ccode>alpha * T * rgb\u003C\u002Fcode> が \u003Ccode>~1e-5\u003C\u002Fcode> 以下になりやすく、これは half (IEEE 754 binary16) の normal range 下限 \u003Ccode>6.1e-5\u003C\u002Fcode> を下回り \u003Cstrong>denormal もしくは zero\u003C\u002Fstrong> に丸められる。背景に近い半透明 splat の寄与が消失し、画像の low-frequency 成分が削れて PSNR が大幅低下。",{"type":58,"level":14,"text":124},"(2) half↔float cast の compute overhead",{"type":121,"text":126},"Apple Silicon GPU の SIMD ALU は half と float の演算 throughput が同じ (4-wide vector で per-cycle 同数 op)。\u003Cstrong>memory bandwidth bound\u003C\u002Fstrong> でない workload (rasterize は threadgroup memory に 256 splat load して再利用、bandwidth ではなく compute bound) では f16 化のメリットゼロ。さらに add 1 回ごとに \u003Ccode>half3(rgb * alpha * T)\u003C\u002Fcode> の cast 命令 (3 命令) が追加され、純粋 overhead として残る。",{"type":58,"level":14,"text":128},"(3) refine が破綻",{"type":121,"text":130},"underflow で寄与が消えた splat に対し gradient が薄まる → refine が「効果のない splat を split」する誤判定を起こし、不要な splat が増加 (final 94,900 vs baseline 83,734、+13.3%)。これがさらに per-pixel 寄与 splat 数を増やし、ms\u002Fiter を悪化させるフィードバック loop。",{"type":58,"text":132},"卒論への含意",{"type":121,"text":134},"第 3 軸 (Apple Silicon 固有最適化) の Negative finding。「Apple Silicon は half と float が同 throughput、bandwidth bound でない rasterize の f16 化は purely loss」を実測で示した。これは brush (Vulkan \u002F Metal) や gsplat (CUDA) も同じ理由で f16 forward を採用していないことの傍証になる。Negative finding 章 (D.3) の 4 つ目のストーリーとして組み込み可能。",{"type":136,"label":137,"variant":138,"text":139},"callout","Lesson","warn","GPU の f16 化は \u003Cstrong>memory bandwidth bound\u003C\u002Fstrong> な workload にのみ適用すべき。Rasterize forward は threadgroup memory 内再利用で compute bound、しかも IEEE 754 binary16 の normal range は alpha 合成の low-T 領域と相性が悪い。Apple Silicon に限った話ではなく一般則として記録。",{"type":58,"text":141},"実装の現状",{"type":61,"items":143},[144,145,146,147],"\u003Ccode>render_splats_f16\u003C\u002Fcode> kernel は \u003Ccode>shaders\u002Fforward\u002Frasterize.metal\u003C\u002Fcode> に残置 (Negative finding として参照可能、削除しない)","\u003Ccode>rasterize.rs::forward\u003C\u002Fcode> の env 切替 (\u003Ccode>SPLAT_F16_FORWARD\u003C\u002Fcode>) も残置、default OFF で baseline 同一動作","\u003Ccode>cargo test 23\u002F23 pass\u003C\u002Fcode> (env OFF 時)","main branch は変更なし (defaults f32)",{"type":58,"text":149},"関連",{"type":61,"items":151},[152,153,154,155],"A.10 Kahan Negative finding (compiler が compensator 削除): \u003Ccode>a-10-kahan-negative\u003C\u002Fcode> — Metal compiler の挙動という共通主題","A.6 #feat.G f16 packed Splat (storage 全体 f16): \u003Ccode>a-6-feat-g-packed-investigation\u003C\u002Fcode> — A.9 の二重 negative を考えると、A.6 の packed も trainer 統合しても同様の risk あり、ROI ~1% の追求は妥当","A.7 batched cmd buffer (Mildly positive): \u003Ccode>a-7-icb-batching-results\u003C\u002Fcode> — 第 3 軸の対比として positive 1 例 \u002F negative 2 例 (A.9 + A.10) の構造に","A.5 final ablation 表 第 3 軸 row \"Mixed precision (A.9)\": \u003Ccode>final-ablation-table\u003C\u002Fcode>",[157,169],{"id":25,"title":25,"subtitle":158,"date":9,"workspace":159,"tags":160,"verdict":164,"psnr":165,"psnr_unit":-1,"wallclock":166,"splats":167,"summary_url":168,"detail_path":168},"A.9 f16 forward (half3 per-pixel accumulator) — wallclock vs PSNR trade-off","splat",[161,162,18,163,16],"a-9","f16-forward","lego-30k","partial",14.872771263122559,"40m 39s",94900,"\u002Fruns\u002Flego-a9-f16-30k\u002F",{"id":24,"title":24,"subtitle":170,"date":171,"workspace":159,"tags":172,"verdict":164,"psnr":175,"psnr_unit":-1,"wallclock":176,"splats":177,"summary_url":178,"detail_path":178},"A.8 SH degree ablation — sh_degree=3 (DC only, no view-dependence)","2026-05-22",[173,163,174,16],"sh-ablation","sh-3",24.87872886657715,"23m 13s",83734,"\u002Fruns\u002Flego-sh3-30k\u002F",[180,195],{"id":27,"title":181,"date":9,"status":10,"polarity":12,"category":11,"axes":182,"tags":183,"task_code":188,"related_runs":189,"delta_psnr":190,"delta_wallclock":191,"rank":192,"verdict":32,"impact_summary":193,"detail_path":194},"A.10 Kahan summation — Metal compiler が compensator を最適化消去",[14],[16,184,185,186,187],"kahan","metal-compiler","variance","msl","A.10",[24],0,"+0.5% (overhead のみ)","low","Neumaier compensated summation の compensator term は MSL compiler の algebraic optimization で消去され、loss は bit-identical。Kahan は wallclock overhead だけ残し variance reduction 効果ゼロ。","\u002Ffindings\u002Fa-10-kahan-negative\u002F",{"id":28,"title":196,"date":9,"status":197,"polarity":198,"category":199,"axes":200,"tags":201,"task_code":206,"related_runs":207,"delta_psnr":-1,"delta_wallclock":208,"rank":209,"verdict":210,"impact_summary":211,"detail_path":212},"A.7 #5.32 ICB \u002F per-iter command buffer commit reduction — 実装プラン","draft","neutral","spec",[14],[16,202,203,204,19,21,205],"icb","command-buffer","batching","plan","A.7",[24],"target -10% (未検証)","mid","investigative","forward \u002F backward の各 chain を 1 cmd buffer に集約する simpler batching plan。期待効果 +15-30% wallclock 改善 (commit overhead 20-50% を集約)。スタイル A (Option\u003C&CommandBuffer> opt-in) で既存テスト 23 件を touch せず実装。target -10% wallclock \u002F PSNR drift \u003C 0.05 dB。","\u002Ffindings\u002Fa-7-icb-batching-plan\u002F",1782449788620]