松田研究室
ArchitectureDocument No. ARCH-3IMPLS
Updated 2026-06-26
← Index
Architecture survey

3 実装アーキテクチャ 比較
splat / brush / msplat

本プロジェクト splat (Rust + native Metal) と brush (Rust + Burn + CubeCL + wgpu) と msplat (rayanht v1.1.3、Apple Silicon Metal-only) の 7 パイプライン軸 + メモリレイアウト + 学習ループ哲学を Pareto 直交性の観点で整理。

Implementations
3
Pipeline axes
7
Verified claims
13
(5 corrected)
01

Executive summary

3 実装は Pareto 平面上で直交する 3 つのベクトルを持つ。これは 2026-06-26 の msplat M4 Max 実測で確定した。

splat (本プロジェクト)
品質 + scene robustness + scene-adaptive iter

Apple Silicon native MSL、kernel は最小単位で読みやすさ重視、refine / MCMC を CPU 寄りに置き unified memory zero-copy を活用、Phase H/I で算法面 (MCMC paper §3.2 full、scene-adaptive iter budget) を厚くする

Phase H 12,500 iter, 11m48s, 36.26 dB, robust on materials (29.97 dB)
brush
cross-platform + autodiff graph

Burn + CubeCL + WGSL、wgpu 経由で WebGPU portability を保つ、Burn の symbolic differentiation に乗っかり kernel 数を最小化、StopThePop で per-tile pruning、storage に f16 packed RGB

公開実装、本プロジェクト Phase H で parity を 0.5 dB 以内に詰めた
msplat (rayanht v1.1.3)
速さ + 中-高品質 (ただし scene 依存)

Apple Silicon Metal-only、42 個の巨大 fused kernel に振り切り、kernel fusion (project+SH 1-dispatch、SH backward+Adam 1-kernel、separable SSIM 1-kernel)、pre-allocated per-tile bins + bitonic sort で global sort を捨てる

30K iter, 3m40s, 35.48 dB, materials は 7K で 8.80 dB / 367 splats と densify 破綻

卒研 narrative の核 evidence

  • wallclockmsplat (3m40s) ≫ splat Phase H (11m48s) — 速度で msplat が <strong>3.2×</strong> 勝つ。
  • PSNRsplat Phase H (36.26 dB) > msplat 30K (35.48 dB) — Lego で <strong>+0.78 dB</strong>。
  • scene robustnesssplat materials 12,500 iter (29.97 dB) ≫ msplat materials 7K (<strong>8.80 dB / 367 splats、densify 破綻</strong>) — <strong>+21.17 dB</strong> の決定的差。
  • B (G.2 backport)NO-GO 維持。msplat v1.1.3 は CHANGELOG で Fused SH-Adam / Fused SSIM / Pre-allocated per-tile bins を実装済、splat が kernel-level で追いつく工数は卒研期間に対して大。
  • A (Reframing)確定。「splat は kernel-level 速さで msplat に負けるが、scene-adaptive な品質追求と全 scene robustness で勝つ」というメッセージを Pareto plot で図示。
Pareto 直交性の結論
msplat は kernel-level 速さ、splat は scene-adaptive 品質 + robustness、brush は cross-platform reference。3 軸は競合せず卒論 §5 で 3 ベクトルを 1 つの Pareto plot に描ける。
Pareto 平面: msplat / splat / brush の 3 ベクトル + materials 破綻 (+21.17 dB 差)
図 1. Pareto 平面 (wallclock × PSNR、Lego + materials)。msplat は ←速さ、splat は ↑品質、brush は portability の独立軸。msplat materials 7K (8.80 dB / 367 splats) → splat Phase I materials (29.97 dB / 268K splats) の +21.17 dB ギャップが scene robustness 軸の決定的 evidence。
02

技術スタック比較

ホスト言語 / GPU カーネル言語 / GPU API / Autodiff / カーネル数 / 混在精度 / MCMC paper coverage の 10 軸で並べる。

splatbrushmsplat (v1.1.3)
ホスト言語RustRustC++ + Objective-C++
GPU カーネル言語Metal Shading Language (MSL)WGSL 手書き + CubeCLMetal Shading Language (MSL)
GPU APIMetal (Apple Silicon native)wgpu → Metal/Vulkan/DX12 (naga 変換)Metal (Apple Silicon native)
Autodiff手書き backward kernel + CPU chainBurn の symbolic autodiff + custom backward手書き backward kernel (CUDA 系統踏襲)
Python binding無し (Rust CLI)無し (Rust binary)nanobind 経由 _core.so
Tensor 抽象自前 Param / AdamState (SoA Metal buffer)Burn Tensor<B, N>MTensor (unified memory shared MTLBuffer wrapper)
カーネル数 (rasterize 系)~12 (project / tile_bin / fwd / bwd×3 variant / ssim / loss / adam / refine_opacity)~25 (FidelityFX radix sort 5 段 + prefix sum 4 段 + render 7 段 + bwd 2 段 + fused_ssim 2)42 (fused-heavy、CHANGELOG v1.1.3 で kernel 統合進行中)
クロスプラットフォーム不可 (Metal only)可 (WebGPU portability、Apple Silicon / NVIDIA / Linux)不可 (Apple Silicon + macOS 14+ only)
混在精度f32 base、render_splats_f16 variant あり (wallclock 効果 ~1%)storage f16 packed (ProjectedSplat.color_{r,g,b}: f16)、compositing は f32完全 f32 only (DType に Float16 無し、fusion で速度を稼ぐ哲学)
MCMC paper §3.2-§3.4full 実装 (relocate Eq.9 + SGLD noise + scale L1 + opacity L1)簡約版 (clone/split 統一 + o_new=1-√(1-o) + (1-o)^150·visible noise gate)無し (pure Kerbl classic + 内部 fusion 最適化のみ)
03

ディレクトリ / モジュール構成

3.1 splat (本プロジェクト)

cargo workspace = 6 crates + 9 MSL kernel files (path は /Users/otkrickey/dev/matsudalab/splat/ ルート)。

CratePath役割LoC
splat-corecrates/splat-core/Pure Rust 型 + 数学 (Metal 非依存)、CameraGpush.rsscene~419
splat-metalcrates/splat-metal/Metal device wrapper + 7 kernel dispatcher (project / tile_bin / rasterize / backward / ssim / loss / adam)~431
splat-iocrates/splat-io/PLY load + NeRF synthetic dataset reader~634
splat-train-v1crates/splat-train-v1/Trainer / train_loop / refine / adam / loss / regularize / mcmc / relocate~3,957
splat-clicrates/splat-cli/clap subcommand (train / check / render / hello / convert / eval)、TOML root config~407
splat-summarycrates/splat-summary/Post-training metrics / logging stub (Phase D 用)~179

主要 MSL kernel (合計 ~2,420 LoC)

  • forward / project<code>shaders/forward/project.metal</code> (417 行) — <code>project_splats_soa</code>
  • forward / tile_bin<code>shaders/forward/tile_bin.metal</code> (380 行) — <code>emit_pairs</code> + <code>radix_{histogram,scatter}</code> + <code>extract_tile_offsets</code>
  • forward / rasterize<code>shaders/forward/rasterize.metal</code> (305 行) — <code>render_splats_f32</code> + <code>render_splats_f16</code>
  • backward / project<code>shaders/backward/project_backwards.metal</code> (472 行)
  • backward / rasterize<code>shaders/backward/rasterize_backwards.metal</code> (517 行、3 variant: Original / Simd / Tg)
  • loss<code>shaders/loss/ssim.metal</code> (164 行)、<code>shaders/loss/loss.metal</code> (88 行)
  • opt<code>shaders/opt/adam.metal</code> (42 行)、<code>shaders/opt/refine_opacity_decay.metal</code> (41 行)

3.2 brush

ルート: /Users/otkrickey/dev/3dgs-workspace/brush/WGSL kernel は #[wgsl_kernel] proc macro で Rust 型と整合性チェック、CubeCL の cube! マクロは Rust 関数を直接 GPU IR にコンパイル。

Crate役割LoC
brush-renderForward: projection / culling / depth sort / SH eval / rasterizationRust ~2,200 + WGSL ~950
brush-render-bwdBackward: per-pixel grad accumulation + chain rule to splat paramsRust ~590 + WGSL ~590
brush-sortFidelityFX Radix Sort 6 stage (depth sort + tile ID sort、subgroup prefix sum)Rust ~530 + WGSL ~618
brush-prefix-sumCumulative sum 3-pass (scan + scan_sums + add_scanned)Rust ~200 + WGSL ~85
brush-fused-ssimFused SSIM (CubeCL DSL) + 11-tap Gaussian blur + 全 SSIM 式Rust ~988 (cube! マクロ、shared memory 26×26 halo)
brush-trainLearning loop: loss / backward / optimizer / refinement (prune + split + clone)Rust ~1,941
brush-kernelCommon GPU utility: workgroup size calc、dynamic dispatch bufferRust ~120 + WGSL 39
brush-wgslproc macro: #[wgsl_kernel] codegen、naga_oil shader compositionRust ~700

3.3 msplat (rayanht/msplat v1.1.3)

ModulePath役割LoC
msplat_metal.metalcore/metal/42 fused Metal compute kernels (projection+SH fused / sort / rasterize / SSIM / backward / GPU-resident densify)3,741 MSL
model.hppcore/include/Model クラス: Gaussian params + Adam state (6 group) + densify flag102 C++
metal_tensor.hppcore/include/MTensor (lightweight GPU tensor wrapper、unified memory)158 C++
model.cppcore/src/Training loop orchestration / optimizer / densify / scheduler597 C++
msplat_api.mmcore/src/C++ API bridge (PIMPL) / Swift / Python binding / step() orchestration393 ObjC++
msplat_metal.mmcore/metal/Metal command encoder setup / kernel dispatch / timestamp profiling1,592 ObjC++
loaderscore/src/loaders/COLMAP / Nerfstudio / Polycam / PLY~800 C++
重要な dead code
radix_sort_histogram / radix_sort_scan / radix_sort_scatter / map_gaussian_to_intersects_kernel は metal source に残るが .mm の dispatch chain には登場せず legacy として保持。v1.1.3 の active path は scatter_to_prealloc_bins_kernelbitonic_sort_per_tile_kernel。Adversarial verify #3 で確認済。
04

パイプライン軸別の詳細比較

forward projection から backward refinement まで 7 軸に分けて、各実装の実装位置・数式・shared memory 使用量・fusion 度を表で並列展開する。

3 実装の forward → loss → backward → Adam → refine の kernel 境界 swim-lane 比較
図 2. kernel fusion 度の swim-lane 図。splat は 8 個の独立 dispatch (algorithmic-rich、CPU refine)、brush は 6 個 (cross-platform + autodiff fusion で Fused SSIM と AdamScaled が一体化)、msplat は 4 個 (project+SH 融合 / bin+sort+pack 融合 / SSIM+L1 融合 / SH-Adam を backward kernel 内に埋め込み、~600 MB/iter 削減)。緑グラデーション枠 = 複数 stage を 1 dispatch に集約。

4.1 Projection (3D → 2D EWA)

3D Gaussian (位置 + 共分散 + SH) を 2D screen-space の (xy, conic, color, alpha) に変換する forward pass。cov3d / cov2d 数式、Jacobian の frustum clamp、SH 評価との fusion、出力レイアウト、backward の cov3d 復元経路がここで分かれる。

観点splatbrushmsplat (v1.1.3)
Pass 構成1-pass: SH + geometry + culling + SH evaluation を完結2-pass split: project_forward (visibility / atomic compaction 専任) + project_visible (SH + packed 出力)1-pass + SH fused (project_and_sh_forward_kernel、cov3d は register、means3d 二度読み排除)
入力レイアウトSoA 5 buffer (means / log_scales / rot_quats / raw_opacities / sh_coeffs)packed transforms[N*10] 1 buffer (mean / quat / log_scale concat) + 別 SH + raw_opacSoA 別 buffer (means3d / scales / quats / features_dc / features_rest) + viewmat / projmat / intrins
cov3d の materializeしない: V = J·R·S·diag(scale)、raw_cov = V·Vᵀ を直接しない (calc_cov2d in helpers.wgsl)upper-triangle 6 floats を register IR 化 (forward は register、backward は SoA 拡張に開かれる)
Cov dilationcov_xx += 0.3, cov_yy += 0.3 固定compensate_cov2d、MIP_SPLATTING 時 0.1 / 通常 0.3、filter_comp を opacity に乗ずるcov2d.x += 0.3, cov2d.z += 0.3 を return 文に埋め込み
Jacobian frustum clamp無し (-fx·mx·rz² 素のまま、暴走は depth / finite cull 任せ)calc_cam_J1.15/-0.15·img_size 非対称 lim、clamp(uv, lims_neg, lims_pos)lim = 1.3·tan_fov の classic 3DGS 値
Numerical guardisfinite(xy) + det≤0 + alpha<1/255 の 3 段3 つの中で最強: is_finite_f32 bit-level、max_abs > 1e18 → PSD-preserving scale-down、det2_strictdet == 0 cull のみ、disc = sqrt(max(0.1, b²-det)) eigenvalue safeguard
Tile bbox無し (後段 tile_bin.metal::emit_pairs で 3σ bbox emit-time 計算)opacity-aware: compute_bbox_extent + StopThePop will_primitive_contribute per-tile contribution testaxis-aligned 3σ ceil(3·sqrt(cov2d.x/z)) (opacity 非依存)
出力AoS Splat2D[9 float] + depth[N] 別 bufferAoS ProjectedSplat[32B] (xy/conic/alpha f32、RGB のみ f16 packed)、atomic compaction で num_visible 個に圧縮完全 SoA 多 buffer (xys / depths / radii / conics / colors / aabb / num_tiles_hit)
Depth gradient 受け口無し無し (project_backwards.wgsl に "Disabled as there is no depth supervision currently" 明示)有り (v_depth[idx] を受け、v_mean3d += viewmat_row3 · v_z、depth supervision を将来サポート可能)
SH → viewdir → means chain有り (normalize_vjp_3dv_pos_shv_pos に加算、Phase G.3 で degree≥1 完備設計)無し (sh_coeffs_to_color_vjp は coeffs gradient のみ)無し (SH gradient のみ)
Backward の cov3d 復元V 経由のみ (project_backwards.metal:402-430)register に materialize: covar = M·Mᵀv_M = (v_covar + v_covarᵀ)·Mupper-triangle 6 floats を IR に書き戻す (v_cov3d[0..5])

差別化サマリ

  • cov3d の扱いは 3 通りmsplat = forward / backward 両方で 6-float upper-triangle を IR として保持、brush = forward は skip / backward は register materialize、splat = forward / backward 両方で skip し V 行列経由で陰関数 chain rule。
  • frustum clamp の有無msplat = 1.3·tan_fov ハード clamp (classic)、brush = 1.15/-0.15 非対称 lim、splat = clamp 無し (NaN-finite cull 任せ)。
  • brush の数値堅牢性が最強<code>max_abs &gt; 1e18</code> の PSD-preserving scale-down は log_scale ≈ 30 のような暴走入力に唯一耐える。
  • Depth gradient — 決定的差msplat だけが <code>v_depth</code> を下流から受ける構造。splat / brush は明示的に depth supervision 対象外。
  • SH→viewdir→means chain は splat のみ卒研の B 軸 (Phase G.3) で degree≥1 backward を完備する設計が他 2 実装に対する優位点になる。

4.2 Tile binning & sort

3D Gaussian を tile に振り分け、depth でソートして rasterize 前段を組む。bin allocation の戦略、sort algorithm、global vs per-tile の選択がここで分かれる。

観点splatbrushmsplat (v1.1.3)
Tile size16×16 固定16×16 固定16×16 (binning) + 8×8 (rasterize sub-tile)
tiles_touched 計算per-emission atomic_fetch_add(pair_count, 1)、3σ AABB2 度評価 (project_forward で count、map_gaussian_to_intersects で同じ判定再走) + StopThePop will_primitive_contributeper-tile atomic scatter_to_prealloc_bins_kernel で直接 bin に書く (count + scatter 融合)
Bin allocation 戦略フラット 1 本 (pair_capacity flat buffer、overflow で host retry)フラット 1 本 (tile_id_from_isect[num_intersections] + compact_gid_from_isect[])per-tile pre-alloc (prealloc_bins[num_tiles * MAX_TILE_ELEMS=2048] uint64、overflow flag)
Prefix sum自前 MSL radix_prefix_scan (16 thread × 1 TG, simd_prefix_exclusive_sum)専用 crate brush-prefix-sum (3 pass, 512 threads/group, Hillis-Steele)per-tile counter scan のみ (num_tiles 規模)
Sort keyu64 = (tile_id<<32) | f32_to_bits(depth) single global sort2 段 sort: depth (u32 32-bit) + tile (ceil(log2(num_tiles)) bit 動的)uint64 = (depth_bits<<32) | gaussian_id per-tile に閉じた sort、global sort 無し
Sort algorithm4-bit LSD radix sort × 16 pass、自前 MSLFidelityFX 6-stage radix sort (4-bit、subgroup prefix scan、dual-LDS intra-WG shuffle)per-tile bitonic sort (threadgroup uint64_t data[2048] 16 KB shared memory) + sort/pack 融合
Tile offsets 抽出per-tile binary search (tile_bin.metal:348-380)post-sort get_tile_offsetssort kernel が tile_bins[tile_id] = (start, end) を直接書く

差別化サマリ

  • Bin 戦略の哲学が決定的に違うsplat = フラット pair バッファ + per-emission atomic、brush = 同じ判定を 2 度回して atomic を避ける、msplat = per-tile 固定 2048 slot 事前確保 + 3 kernel パイプを 1 dispatch に圧縮。
  • Sort スコープ — 決定的差brush と splat は global sort、msplat は <strong>global sort を持たず per-tile bitonic</strong> で tile_id を暗黙化。
  • msplat の per-tile pre-alloc の trade-off速い (3 dispatch → 1) 代わりに MAX_TILE_ELEMS=2048 overflow 脆性 + 固定 16 KB shared mem / tile 消費。
  • brush の StopThePopper-tile contribution test で intersection を 1.5-2× 削減 (arXiv:2402.00525)。3 実装で最も保守的 = 精密。
  • splat は教育的・移植性◎4-bit LSD radix が WebGPU / CUDA いずれにも素直に書き直せる。

4.3 Forward rasterize (alpha blending)

tile ごとに splat を front-to-back で α-合成。shared memory への cooperative load、early-out、backward 用 state の保存方法がここで分かれる。

観点splatbrushmsplat (v1.1.3)
Threads per tile16×16 = 256 thread / 1 pixel / thread16×16 = 256 thread / 1 pixel / thread + Morton (Z-order) pixel layout8×8 = 64 thread / 1 pixel / thread (RAST_BLOCK_X/Y=8) — sort tile より細かい sub-tile
Shared memory~9 KB (local_batch[256] Splat2D AoS 36B × 256) + atomic counter、f32 only on shared8 KB (local_batch[256] ProjectedSplat 32B × 256、RGB f16 packed) + BWD_INFO 時 +1 KB load_gid[256]2.25 KB (xy_opacity_batch[64] + conic_batch[64] + rgbs_batch[64]、全 f32) — 最小
Pixel layoutrow-majorMorton Z-order (分岐 divergence 削減)row-major (sub-tile 8×8 = 1 workgroup)
Cooperative loadlid 番 thread が 256 splat 単位で詰める同上、workgroupUniformLoad で WGSL portabilitysort kernel が既に packed buffer に展開済、64 splat batch を直接 read
Workgroup-wide early exitif atomic_load(num_done_atomic) >= TILE_SIZE break同上、緩い同期 (stale read OK)無し (代わりに if (sigma >= 5.55f) continue で exp 評価を skip、94% hit empirical)
Per-pixel early-outnext_T <= 1e-4f → done同上同上 + last_contributor 記録
α 上限alpha = min(0.999, color.a * exp(-sigma))同上同上 (fma 多用、packed_rgb は raw SH なので max(raw + 0.5, 0.0) で DC offset+clamp)
Background composite無し (host 側 or 後段で加算)pix_out + T*background.rgb を最終加算per-pixel saturate(fma(bg, T, pix_out)) で fused
Backward 用 statefinal_T_out[pix_id] のみBWD_INFO mode で full out_img: vec4f + per-global-splat visible[gid] = 1.0 mask (last_contributor なし)final_Ts[pix_id] + final_index[pix_id] = last_contributor の両方 → backward が [range.x, last_contributor] だけ replay でき ~半分削減
Precisionf32 / f16 mixed の 2 variant、accumulator のみ halfstorage-only f16 (ProjectedSplat.color_{r,g,b}: f16)、compositing は f32f32 only

差別化サマリ

  • Inria per-tile load pattern の踏襲度splat = 完全踏襲、brush = 完全踏襲 + Morton + workgroupUniformLoad、msplat = <strong>逸脱</strong> (8×8 sub-tile + sort/pack fusion + last_contributor)。
  • Workgroup-wide vs Per-pixel early-outsplat / brush は workgroup-wide num_done atomic で全 pixel saturate 時に batch を打ち切る、msplat は持たず代わりに sigma-based exp skip。
  • Backward state の効率 — 決定的差msplat は <code>last_contributor</code> を保存することで backward replay 範囲を縮められる (~半分削減)。splat / brush は range 全 splat を replay。
  • f16 戦略splat = 実験的 mixed variant (wallclock ~1%)、brush = storage のみ f16 packed、msplat = f16 不採用で fusion 一本勝負。

4.4 Backward rasterize

per-pixel に atomic add で勾配を書き戻すか、warp / threadgroup reduction で集約してから書くか。Inria 系の per-tile shared memory load 踏襲度、replay 方向、Refine 信号 fusion の有無が論点。

観点splatbrushmsplat (v1.1.3)
Thread parallelism1 thread / 1 pixel (Original / Simd / Tg 全 variant 共通)64 thread × 4 pixel/thread (register pressure 抑制)256 thread × 1 pixel + 64-splat threadgroup batch
Shared memoryOriginal / Simd は使わず、Tg variant は partial-sum reduction 用のみlocal_batch[64] + local_compact_gid[64] で splat input を cache + barrierid / xy_opac / conic / rgb 4 種 cooperative load + simd_broadcast で lane 0 read を 32 lane に配布
SIMD reductionsimd_sum で 256 atomic → 8 atomic / splat (32× 削減、Simd variant が production)subgroupAdd で 10 scalar (xy(2)+conic(3)+rgb(3)+alpha(1)+refine(1))、subgroup_invocation_id == 0 のみ atomicwarpSum / warpSum2 / warpSum3 で 32× 削減 + warp_reduce_all_or(valid) で warp 全員 invalid なら loop 反復 skip + warp_max_finals で leading batch 全 skip
Atomic backendatomic<float> native (M4 Max 前提、CAS fallback 無し)HARD_FLOAT ifdef で native atomicAdd<f32>atomicCompareExchangeWeak CAS fallback (WebGPU portability)atomic_float native
Replay 方向forward 方向 replay (pix_acc 逐次更新)forward 方向 replay (rgb_pixel_finals 経由)逆方向 traversal (T *= 1/(1-alpha) で reverse 復元、Inria 原典)
出力レイアウトsplats_grad[N*9] (xy / conic / rgb / color_a) densev_splats[num_visible*10] (xy(2)+conic(3)+rgb(3)+alpha(1)+refine_weight(1)) sparse compact_gid 添字4 別 buffer (v_xy[N*2] / v_conic[N*3] / v_rgb[N*C] / v_opacity[N]) SoA
Sigmoid backward別 kernel (project_backwards.metal:22a)autodiff graph 経由fused (v_opacity = -v_sigma * (1 - opac) を kernel 内)
clamp_min RGB別経路autodiff の select(0, vis * v_outs.rgb, color.rgb >= 0) で fusedb_rgb + 0.5 < 0 で atomic skip (fused)
Refine 信号 fusionCPU refine が後段で別途集計v_refine = length(v_xy_local * img_size) / final_a を backward kernel 内で累積 (fusion)accumulate_grad_stats_kernel で per-gaussian grad norm
Chunked rasterization無し無し有り (rasterize_backward_chunked_kernel、tile splat >512 で発火)
StopThePop不採用forward でのみ (per-tile bbox 段階)、backward 本体は通常 path不採用、しかし warp_max_finals + tile_max_bin_final の subtile-level early exit が機能的に等価

差別化サマリ

  • Shared memory の使い方が決定的に違うsplat は global 直 read (Tg variant の threadgroup memory は <strong>gradient reduction 用のみ</strong>)、brush は 64-entry workgroup batch、msplat は 64-entry threadgroup batch + <code>simd_broadcast</code> で threadgroup-memory read を 1/32 に圧縮。
  • SIMD reduction の atomic 削減は 3 実装とも 32×warp-sparse skip は brush と msplat の両方が持つ。warp-level sparse skip を <strong>持たないのは splat の Simd kernel のみ</strong>。
  • msplat 固有の最適化(a) <code>warp_max_finals + first_batch</code> での leading batch 全 skip、(b) warp 内 broadcast による batch ロード冗長削減、(c) <code>last_contributor</code> 保存で replay 範囲縮小、(d) tile splat &gt;512 chunked rasterization。
  • Forward saved state の設計が replay 方向と一致splat / brush は forward 方向 replay (final_T だけ保存)、msplat は逆方向 traversal (bin_final + final_Ts を保存し T を reverse 復元)。
  • Refine 信号のどこで fuse するかbrush は backward 内、msplat は別 kernel、splat は CPU refine。

4.5 SH (Spherical Harmonics) 評価と progressive band

球面調和関数の評価。最大 degree、progressive band schedule、DC / higher band の構造分離、SH backward → Adam fusion の有無が論点。

観点splatbrushmsplat (v1.1.3)
Max SH degree0..=4 (25 coeffs)0..=4 (25 coeffs)0..=4 (25 bases)
Progressive band schedule有り: ShProgressiveConfig{init, max, unlock_interval}active = init + (iter-1)/unlock_interval、init オフセット指定可無し (full degree 固定、代わりに lr_coeffs_sh_scale=10 の AdamScaled per-element scaling で吸収)有り (s.degreesToUse = step / shDegreeInterval、init オフセット指定不可、常に 0 開始)
Buffer / Active 分離CameraGpu.{sh_degree, active_sh_degree} 2 フィールド (buffer stride vs eval loop bound)単一 sh_degree (buffer = active)s.degree (buffer = featuresRest.size(-2) + 1 から逆算) + s.degreesToUse (active)
DC / higher band の構造分離単一 sh_coeffs tensor (flat、stride = max_coeffs*3)単一 sh_coeffs[N,C,3] tensor、scaling tensor で per-band LR2 buffer 分離 (featuresDc[N,3] + featuresRest[N,C-3,3]、別 Adam state group)
Forward fusionproject と rasterize 別 dispatch、SH は project 内で評価 + Splat2D に packed color として書くproject_forward / project_visible / rasterize 3 段、SH は project_visibleproject + SH を 1 kernel に fuse (project_and_sh_forward_kernel)
SH backward → Adam 経路SH 勾配を sh_coeffs_grad device buffer に書き → 別 dispatch adam_stepBurn autodiff graph で v_coeffs[N,C,3] dense scatter → AdamScaled optimizer の 3 stepproject_and_sh_backward_kernel の register 内で SH 勾配計算 → 同 thread 内 adam_update_element を直接呼び features_dc / features_rest を in-place 更新 (~600 MB/iter at 1.5M splats 削減)
Adam dispatch 数5 group × 1 dispatch3 step (transforms / sh_coeffs / raw_opacities)4 group dispatch (means / scales / quats / opacities)、SH 2 group は backward kernel に fused
viewdir → means chain有り (normalize_vjp_3dv_pos_sh)無し ("Camera gradient is not done yet" TODO)無し (SH gradient のみ)
Numerical precisionf32 (SH eval / grad)ProjectedSplat の color を f16 pack、SH grad は f32f32 only

差別化サマリ

  • Progressive band の有無splat と msplat は per-iter active degree を持つ (splat は init オフセット指定可、msplat は常に 0 開始)。brush は schedule なし、AdamScaled per-element scaling で吸収。
  • SH backward → Adam 経路 — 卒研 narrative の核msplat の v1.1.3 fused SH-Adam は ~600 MB/iter buffer + memory round-trip を排除する最も aggressive な fusion。splat / brush は SH grad buffer を別途確保し別 dispatch で Adam 適用。
  • DC / higher band の構造分離msplat のみ別 tensor + 別 Adam state group、per-band LR の自然な実装。
  • viewdir → means chain は splat だけが閉じているPhase G.3 で degree≥1 backward を完備する設計、卒研 §4 (axis 2 算法) の独自性として位置付け可能。

4.6 Loss / Fused SSIM

L1 + SSIM を組み合わせた loss と、その勾配。SSIM の separable convolution の有無、forward / backward の fusion 粒度、kernel 間の memory round-trip 排除の哲学が分かれる。

観点splatbrushmsplat (v1.1.3)
Loss configLossKind::{L1Only, L1Ssim} + lambdaSsimConfig で window K=5/7/11 可変ssim_weight / lpips_loss_weight (VGG perceptual, optional) / match_alpha_weightssim_weight のみ、kernel ハードコード式
L2無し無し無し (3DGS 慣例)
LPIPS無し有り (VGG perceptual, optional)無し
SSIM convolution 構造direct 2D 11×11 (per-pixel 121 global load、separable 無し、shared memory 無し) — 純朴 baselineseparable 11+11 1D × 2 pass + 16×16 shared memory タイル化 (26×26 halo)、CubeCL cube! マクロで Rust→GPU 自動コンパイル2 系統共存: (a) v1.0 fused_loss_*** = direct 2D、(b) v1.1.3 separable + tiled (3 ch まとめて threadgroup load 9.75 KB)
Forward / backward fusionSSIM forward と backward 別 kernel、L1 と SSIM combine も別 kernel (3 kernel)forward が SSIM map + 3 偏微分を 1 kernel で保存、backward が tiled separable conv で完結 (2 kernel)。L1 は Burn tensor op最も aggressive fusion: ssim_fused_v_fwd_h_bwd_kernel 1 つで「vertical forward 再計算 + horizontal backward + L1 + threadgroup reduce + loss atomic」を完遂、中間 loss_intermediates (130 MB/iter at 1.5M splats) を排除
Loss combine 数式dldr = (1-λ)·sign(r-t)/N - λ·ssim_grad、loss は (1-λ)·L1_mean + λ·(1-mean_ssim)tensor op l1*(1-w) - ssim_err*w (autodiff で chain)ssim_w·(1-ssim/3) + (1-w)·L1/3 を kernel 内ハードコード、backward も kernel 内
Gaussian tapdevice buffer window_1d[K] 経由 (K 可変)const GAUSS: [f32; 11] comptime 埋め込み (σ=1.5 固定)constant float GAUSS_1D[11] MSL ソースハードコード (σ=1.5 固定)
Reductionwarp 単位 simd_sum → 1 atomic / warp直接 backward image 書き込み、loss scalar は Burn mean() tensor opthreadgroup tg_sum[256] → 1 atomic / workgroup
数値精度f32 onlyf32 only (OOB zero-pad、SSIM raw を [-1, 1] clamp)f32 only (dy_min/dx_min clamp で boundary 帯まで window 縮小)

差別化サマリ

  • precision は差なし3 実装すべて f32 throughout (verify #11 で訂正)。「numerical precision の本質的差異」と書くと refuted。
  • アルゴリズム的差異brush と msplat (v1.1.3) は separable 11+11 で計算量 O(K²)→O(K) per pixel + shared memory tile で global memory traffic 削減。splat だけが non-separable nested K×K loop で global memory 直接 read (<strong>11× 重い</strong>: 121 vs 22 tap loads per pixel)。
  • fusion 粒度の哲学差 (3 通り)splat = <strong>kernel 間 fusion</strong> (SSIM と L1 分離、勾配層で線形結合)、brush = <strong>kernel 内 fusion</strong> (separable conv + SSIM 式 + chain-rule partials を 1 forward + 1 backward に集約)、msplat = <strong>loss-level fusion</strong> (SSIM + L1 を 1 kernel、~15 MPS dispatches を 1 つに、130 MB/iter intermediate buffer 排除)。

4.7 Adam optimizer & refinement / densification / MCMC

Adam tensor layout、LR schedule、densify / prune の閾値、MCMC paper coverage、opacity reset の挙動。算法面の差異が最も大きく出る軸。

観点splatbrushmsplat (v1.1.3)
Adam tensor layout5 component SoA (means / log_scales / rot_quats / raw_opacities / sh_coeffs の m, v)AdamScaled: 3 group (transforms[N,10] / sh_coeffs[N,C,3] / raw_opacities[N])、per-component LR は scaling tensor の broadcast 乗算6 group SoA (means / scales / quats / featuresDc / featuresRest / opacities)、ring-buffered with capacity
Adam dispatch 数1 kernel × 5 回 dispatch (per-component LR 差し替え)3 step4 group dispatch (SH 2 group は backward kernel 内で fused)
Bias correctionkernel 内 pow(beta1, t) 毎 stepautodiff graph で symbolichost precompute step_size = adam_lr[g] / bc1bc2_sqrt = √(1-β2^t) を kernel に注入 (kernel 内 pow 不要)
LR scheduleExpDecay { init, final_val, max_steps }、means のみ exp decayExponentialLrSchedulerlr_mean は毎 step * median_scale で scene scale 適応means のみ exponential interpolation、scene-invariant
Densify 実装場所CPU: read_vec/write_vec で snapshot → compact → writeback (unified memory zero-copy)Burn tensor ops 経由 (symbolic 構築)、ただし multinomial_sample や stats reduction は host (into_data_async() readback) — ハイブリッド完全 GPU resident (densify_classify / append_split / append_dup / cull / compact_scatter / compact_copy_back の 6 kernel + GPU prefix sum)、CPU readback ゼロ
Densify schedule100 iter / stop 15000、capacity overflow で 2x grow200 iter / stop 15000 / max 10MrefineEvery && step > warmupLength && step < stopSplitAt (=maxSteps/2)
Split 数式log_scale -= ln(1.6) + 軸ごと jitter (子 2 つ Adam m/v 0、Clone は m/v 保持)cur_log_scale + log(1/√2) + Mirror split、parent opacity o_new = 1 - √(1-o) で補正 (3DGS-MCMC Eq.9 N=2)parent も in-place -log(1.6)、child r = randn * exp(parent_scale)child Adam m/v は全 0
Prunesigmoid(raw_opacity) < 0.005、max_scale > capsigmoid(raw_opac) < 1/255、any scale < 1e-10 / > 100*bounds.extent、bounds 中心から max 超えσ(opacity) < 0.1、split parent は always 削除、check_huge で max_scale > 0.5
Relocate / MCMCpaper §3.2 Algorithm 1 full 実装 (relocate.rs:63-228): dead/live threshold 分割、opacity-weighted sample、Eq.9 o_new = 1-(1-o_t)^(1/N_t) + log_scale += -0.5*ln(N_t)、Adam state は意図的に触らない専用 MCMC path 無し (clone/split 統一で Eq.9 を常時適用)、noise gate は inv_opac.powi_scalar(150).clamp(0,1) * visible (paper σ(-k(o-t)) と非互換)無し (pure Kerbl 2023 classic)
MCMC noiseregularize.rs:73-142 paper gate σ(-100·(o-0.995))eff_lr_mean = lr_mean * median_scale、visible splat の means に N(0,1)*coeff 加算inv_opac^150 * visible gate、noise_weight = gate * (lr_mean * mean_noise_weight)、Normal(0,1)、max_noise=median_scale clamp無し
Scale L1 / Opacity L1apply_mcmc_scale_l1 / apply_mcmc_opacity_l1無し無し
Opacity resetraw_opacity → logit(0.01) 下方リセット (default cadence 0=無効)、Adam m/v 保持明示 reset 無く、毎 refine の sigmoid-space decay (new_opac = σ(raw) - decay*(1-train_t)) で代替、Adam m/v 保持op[i] > logit(0.25) の上方を クランプ + Adam group[5] m/v を全 zero 破棄
Opacity decaybrush 互換 sigmoid-space (refine.rs:383-402)refine 内で常時、opac_decay * (1-train_t)、scale_decay も同様無し
Scene-adaptive iter budget無し (max_steps 固定、SH progressive は degree のみ段階解放)無し (LOD lod_levels で post-training 段階追加、base iter 固定 30000)無し (resolutionSchedule で rendering 解像度 downscale、iter 数固定)

差別化サマリ

  • MCMC paper coverage — 決定的差splat だけが Kheradmand 2024 paper §3.2-§3.4 を full に実装 (Eq.9 relocation + SGLD noise + scale L1 + opacity L1)。brush は簡約版、msplat は完全に無し。
  • Densification の実行場所splat = 完全 CPU (unified memory zero-copy)、brush = ハイブリッド、msplat = <strong>完全 GPU resident</strong> (CPU readback ゼロ、最も aggressive)。
  • Adam dispatch 数の fusion 度msplat (4 dispatch + SH fused) ≫ brush (3 step) ≈ splat (5 dispatch)。bias correction の host precompute は msplat 固有。
  • LR の scene 依存性brush だけが <code>lr_mean *= median_scale</code> で毎 step scene scale 適応。splat は noise gate のみ scene-aware、msplat は完全 scene-invariant。
  • Opacity reset の Adam state 扱いsplat / brush = m/v 保持、msplat = m/v 破棄 — 三者三様で挙動が異なる。
05

データ構造とメモリレイアウト

Gaussian 表現の SoA vs AoS、Adam state group 数、tile bin storage、backward saved state、SSIM intermediate、precision policy を 6 つの表に分解。

5.1 Parameter storage

観点splatbrushmsplat (v1.1.3)
Layout 哲学SoA per-componentpartial AoS (transforms に concat)SoA per-component, DC / rest 分離
means[capacity * 3] f32transforms[N, 10][0..3]means3d[N, 3] f32
log_scales[capacity * 3] f32transforms[N, 10][7..10]scales[N, 3] f32 (log-space)
rot_quats[capacity * 4] f32 (brush 規約 w,x,y,z)transforms[N, 10][3..7]quats[N, 4] f32
raw_opacities[capacity] f32Tensor<B, 1>[N]opacities[N, 1] f32
SH coeffssh_coeffs[capacity * max_coeffs * 3] 単一 tensorsh_coeffs[N, C, 3] 単一 tensorfeaturesDc[N, 3] + featuresRest[N, C-3, 3] 2 buffer 分離
Adam state5 component pair (m, v)3 group + scaling tensor6 group
Total per splat (sh_deg=3)252 B value + 252 B grad + Adam 504 B = 1008 B~236 B value~236 B value

5.2 GPU intermediate (Projection 出力)

観点splatbrushmsplat (v1.1.3)
TypeSplat2D AoS 9 floats = 36 BProjectedSplat AoS 32 B (xy/conic/alpha f32、RGB f16 packed)SoA 多 buffer (xys / depths / radii / conics / colors / aabb / num_tiles_hit)
Culled markerconic=(0,0,0), color_a=0, depth=+∞atomic compaction (num_visible 個のみ書き込み)radii=0, num_tiles_hit=0
Compactionしない (dense N)する (global_from_compact_gid[num_visible] で indirection)しない (dense N、num_tiles_hit=0 で skip)

5.3 Tile bin storage

観点splatbrushmsplat (v1.1.3)
構造flat (tile_id, splat_idx) pair bufferflat tile_id_from_isect[num_intersections] + compact_gid_from_isectprealloc_bins[num_tiles * 2048] uint64 (per-tile pre-alloc)
Sort keyu64 packed (tile_id<<32 | depth_bits)2 段 (depth u32 + tile_id 動的 bit)uint64 (depth_bits<<32 | gaussian_id)、per-tile に閉じる
tile_offsetsper-tile binary search で抽出post-sort get_tile_offsetssort kernel が tile_bins[tile_id] = (start, end) 直接出力
Packed sort output無し (rasterize が splats[sorted_idx[i]] で間接 read)無し (compact_gid → projected[] で間接 read)有り (sort kernel が xy / opacity / conic / rgb の packed buffer を fused 出力)

5.4 Rasterize backward saved state

観点splatbrushmsplat (v1.1.3)
Forward savedfinal_T_out[W*H] のみout_img[W*H*4] + visible[N] + BWD_INFO 時 load_gid[256]final_Ts[W*H] + final_index[W*H] = last_contributor 両方
Backward replay 範囲range 全部 (forward 方向)range 全部 (forward 方向)[range.x, last_contributor] だけ (~半分削減)
Chunked buffer無し無しprefix_T_buf / chunk_T_buf / after_C_buf (>512 splat tile 用)

5.5 SSIM intermediate

観点splatbrushmsplat (v1.1.3)
Forward saved5-tuple stats [H*W*3*5] (μx, μy, vx, vy, vxy) — non-separableSSIM map + 3 partialsv1.0: 5 stats loss_intermediates[H*W*15] / v1.1.3: ssim_h_buf[H*W*3*5] のみ、vertical 再計算 on-the-fly
削減量tiled separable で global traffic 削減130 MB/iter @ 1.5M splats 削減

5.6 Precision policy (verify #11 で確定)

Precisionsplatbrushmsplat
Parameterf32f32f32
Adam m/vf32f32f32
SH coeffsf32f32f32
Forward intermediatef32 (f16 variant あり)f16 packed (ProjectedSplat.RGB)f32
SSIMf32f32f32
Backwardf32f32f32
Precision の結論
3 実装とも parameter / Adam state / SSIM は完全 f32。f16 を採用しているのは brush の forward intermediate (RGB packed in ProjectedSplat) と splat の experimental render_splats_f16 variant のみ。msplat は f16 を完全に避けて fusion 一本で速度を稼ぐ。
06

学習ループの哲学的違い

3 実装は "学習ループのどこに最適化を効かせるか" で哲学が分かれる。

Algorithmic richness

6.1 splat: Phase H/I 算法拡張型 (本プロジェクト)

  • kernel は最小単位で読みやすく: project / rasterize / SSIM / loss / adam を per-責務分割、advisor 推奨で per-kernel 単純化を優先。
  • CPU 寄りの refine / MCMC: unified memory zero-copy を活用して densify を CPU で書き、read_vec/write_vec で snapshot → compact → writeback。algorithm 反復が速い (Rust で書ける)。
  • 算法面の厚み: Phase H で MCMC paper §3.2-§3.4 を full に実装、Phase G.3 で SH progressive (init オフセット指定可)、Phase I で scene-adaptive iter budget。
  • trade-off: kernel-level optimization (fused SH-Adam, separable SSIM, per-tile bins) は msplat に対して後発、wallclock では msplat に 3.2× 負ける。代わりに品質 + scene robustness で勝つ。
  • Phase I scene-adaptive narrative: scene 依存の iter / lr / threshold を統合管理する PR で axis 2 算法の差別化を確立する戦略。
Cross-platform

6.2 brush: 純粋実装型 (cross-platform + autodiff graph)

  • Burn の symbolic differentiation に乗っかる: gradient は autodiff graph が自動構築、custom backward kernel は最小限 (rasterize_backward + project_backward の 2 つ)。
  • cross-platform 第一: WebGPU portability、HARD_FLOAT ifdef で CAS fallback を持つ、subgroup intrinsics を活かすが Apple Silicon 固有最適化はしない。
  • kernel-level 最適化はそこそこ: FidelityFX radix sort、StopThePop tight bbox、separable fused SSIM、Morton pixel layout — 一通りの教科書最適化は入っているが "fusion 一本勝負" ではない。
  • 算法は中庸: clone/split を統一して Eq.9 N=2 を常時適用するなど MCMC paper の簡約版を採用、SH progressive は無く AdamScaled per-element scaling で吸収。
  • 特徴的最適化: storage f16 packed RGB (ProjectedSplat)、lr_mean *= median_scale の毎 step scene scale 適応、refinement bounds の percentile 0.8 推定。
Kernel fusion

6.3 msplat: kernel 最適化型 (Apple Silicon Metal-only fusion 一本勝負)

  • 巨大 fused kernel 哲学: 42 個の kernel に振り切り、project + SH を 1 dispatch、SH backward + Adam を 1 kernel、SSIM forward + backward + L1 を 1 kernel に集約。kernel 間 memory round-trip を徹底排除。
  • Apple Silicon Metal-only: cross-platform を捨てて Apple GPU の simd_* intrinsics、unified memory、atomic_float native add に振り切る。
  • GPU-resident densification: classify / append / cull / compact が全部 GPU、CPU readback ゼロ — splat / brush と決定的に違う。
  • 算法は classic: MCMC paper coverage は完全に無し、pure Kerbl 2023 classic。代わりに kernel fusion + memory layout 削減で速度を稼ぐ。
  • trade-off: 速度は最強 (Lego 30K 3m40s)、scene robustness は弱い (materials 7K で PSNR 8.80 dB / 367 splats と densify 破綻)。「速い + 中-高品質、ただし scene 依存」の Pareto vector。

6.4 まとめ表

哲学軸splatbrushmsplat
最適化の主戦場算法 (MCMC, SH progressive, scene-adaptive)autodiff graph + cross-platformkernel fusion + memory layout
開発速度速い (Rust + 小 kernel)中 (Burn graph 構築)遅い (巨大 fused kernel の保守)
scene robustness高 (Phase I narrative)中 (bounds-based prune)低 (materials 破綻実例)
Apple Silicon 適合高 (native + unified memory CPU 活用)中 (wgpu 経由)最高 (Metal only + native intrinsics)
卒研 narrative 適合A 軸 (Reframing) / B 軸 (axis 2 算法) の本体reference 実装、parity targetdirect baseline (§5 実験)、materials 破綻 PR ネタ (E 軸)
07

決定的差別化軸 (卒研 narrative)

3 つの差別化軸を確定し、卒論 §5 (実験) と §4 (関連実装) にリンクする。

7.1 軸 A — Reframing: 「速さ vs 品質+robustness」の Pareto 直交性 (確定済)

Evidence
  • msplat Lego 30K: 3m40s, 35.48 dB, 208k splats (左上 = 速い + 中品質)
  • splat Phase H Lego 12,500 iter: 11m48s, 36.26 dB, 高品質側
  • splat Phase I 8 scene のうち 5 scene が msplat Lego 30K の 35.48 dB を上回る (Lego 36.26 / chair 35.88 / hotdog 37.37 / mic 36.62)
  • msplat materials 7K で PSNR 8.80 dB / 367 splats と densify 破綻 → splat materials 12,500 iter で 29.97 dB / 268k splats+21.17 dB の決定的差
Narrative

「splat は kernel-level 速さでは msplat に負けるが、scene-adaptive な品質追求と全 scene robustness で勝つ」を Pareto plot で killer figure として固定。

7.2 軸 B — axis 2 (算法独自性): MCMC paper full implementation + SH progressive + scene-adaptive iter

Evidence
  • splat だけが Kheradmand 2024 paper §3.2-§3.4 を full に実装 (relocate.rs:63-228 + regularize.rs:73-142)
  • splat だけが SH progressive (init オフセット指定可) と Buffer/Active SH degree 分離を CameraGpu で表現
  • splat だけが SH → viewdir → means chain rule を normalize_vjp_3d 経由で閉じている (degree≥1 完備設計)
  • Phase I scene-adaptive iter budget が brush / msplat には無い (両者とも max_steps 固定)
Narrative

「kernel-level の fusion 競争 (msplat) には参戦しない、代わりに paper coverage と scene 適応で品質を取る」。

7.3 軸 C — Apple Silicon unified memory の "非対称" 活用

Evidence
  • msplat は Apple Silicon を Metal-only に振り切るが densify を GPU resident に閉じ込める (CPU 関与ゼロ)
  • splat は同じ Apple Silicon を逆に活用 — densify を CPU 寄りに置き unified memory zero-copy で Rust から param + Adam state を直接 RMW できる (refine.rs:105-361) — これは離散 GPU では成立しない設計
  • brush は wgpu 経由のため unified memory の zero-copy は使えない (into_data_async() readback)
  • 哲学的に: "GPU でも CPU でもないただひとつのメモリ" を最大限活用するアーキテクチャは splat が最も近い
Narrative

「splat は Apple Silicon の unified memory を fast CPU densify に転用、これは Metal-only でも cross-platform でも独立した第 3 のポジション」— 卒論 §4 (関連実装) の独自軸として書ける。

7.4 NO-GO 判定済の軸

  • B (G.2 backport — kernel-level optimization で msplat に追いつく)<strong>NO-GO 維持</strong>。msplat v1.1.3 は既に Fused SH-Adam + Fused SSIM + Pre-allocated per-tile bins を実装済、splat が追いつく工数は卒研期間に対して大。代わりに A + 算法軸で勝負する。
  • E (msplat 著者接触)materials 7K densify 破綻を issue 報告するのは良い PR ネタとして残置。
08

Adversarial verify で修正された主張

Phase 3 で 13 の主張を adversarial verify したうち、4 つが訂正対象 (#2, #7, #8, #11)。残りは supported。

#主張判定修正内容
#1Pass 数 / fusion 哲学 (splat 1-pass、brush 2-pass、msplat 1-pass + SH fused)supportedmsplat v1.1.3 CHANGELOG は SH backward fusion を新機能として記載、forward fusion は pre-existing。"600 MB/iter 削減" は backward SH→Adam fusion @1.5M splats の数値。
#2cov3d materialize の三分類 (msplat=IR、splat/brush=skip)partialbrush backward は covar = M·Mᵀ を register に materialize する (3×3 行列、global IR ではないが "skip" でもない)。正しい三分類: (a) msplat = forward/backward 両方で upper-triangle 6-float global IR、(b) brush = forward は skip / backward は register materialize、(c) splat = forward/backward 両方で真に skip (V 行列経由の陰関数 chain rule)。
#3Tile binning & sort axis (3 実装の本質的差)supportedmsplat の radix_sort_* kernel は metal source に残るが .mm で dispatch されない dead code であることを確認。
#4Tile size 3 実装すべて 16×16 固定supportedinria-3dgs 由来は kernel コメント上は証明できないが妥当。
#5splat forward rasterize 256 thread / ~9 KB shared / f32 only on sharedsupportedSplat2D 9 floats = 36 B、36×256=9 KiB ぴったり。
#6brush 256 thread + Morton + 8 KB shared + +1 KB load_gidsupportedProjectedSplat 32 B × 256 = 8192 B ぴったり、BWD_INFO 時のみ +1 KB。
#7Tile parallelism / shared memory の哲学partialsplat の Tg variant は threadgroup memory を gradient reduction 用のみ使う (splat input data は global 直 read)。msplat の threadgroup batch は RAST_BLOCK_SIZE = 64 (256 ではない)。simd_broadcast の役割は threadgroup-memory read を 1/32、global read 圧縮の主因は cooperative load (~4×)。
#83 者とも 32-lane SIMD reduction、msplat だけが warp sparse skippartialbrush も subgroupAny(hasGrad) + if anyGrad で warp-level sparse skip を持つ。warp-level sparse skip を 持たないのは splat の Simd kernel のみ。msplat 固有は (a) leading batch 全 skip (back-to-front の利点)、(b) warp 内 broadcast による batch ロード冗長削減。
#9Progressive band schedule (splat/msplat 有、brush 無)supportedbrush は schedule 不在を lr_coeffs_sh_scale=10 の AdamScaled per-element scaling で代替。
#10Buffer/Active layer 分離 (splat CameraGpu 2 field、msplat state struct)supportedmsplat の "state struct" は per-iter な CamSetup s (transient)、Model 本体は shDegree のみ永続。本実装の CameraGpu も per-call 組立。構造的並列が正確に成立。
#11Loss/SSIM の 3 軸差異 (kernel-level + precision + fusion 哲学)partialprecision は差なし — 3 実装すべて f32 throughout。「precision の本質的差異」と書くと refuted。正しい 2 軸は (A) アルゴリズム的差異 (brush/msplat が separable + tiled、splat だけが non-separable で 11× 重い)、(B) fusion 粒度の哲学差 (splat = kernel 間 fusion、brush = kernel 内 fusion + autodiff、msplat = loss-level fusion)。
#12splat Fused SSIM は direct 2D 11×11 per pixel + 121 global load + separable 無し + shared memory 無し純朴 baselinesupportedK=11 default、shaders/loss/ssim.metal 全体に threadgroup/shared/simd の grep 0 hit、wy_g * window_1d[dx] の outer product 形だが loop は 2D のまま。
#13(各種小 claim) brush の AdamScaled、msplat の <code>s.degreesToUse</code>、splat の <code>ShProgressiveConfig</code> などsupportedコード一致を確認済。
ドキュメント本文で訂正済の箇所
§4.1 表の "Backward cov3d 復元" 列で brush を "register に materialize" と修正 (verify #2)。§4.4 で splat Tg variant の threadgroup memory が reduction 用のみ、msplat batch サイズが 64 (256 ではない) と修正 (verify #7)。§4.4 で warp-level sparse skip を brush も持つと修正 (verify #8)。§4.6 で precision 軸を削除し algorithm + fusion 粒度に再構成 (verify #11)。
09

References

9.1 本プロジェクト内部ドキュメント

  • <code>docs/architecture/three-impls-arch.md</code>本ページの元 markdown ドキュメント (557 行 / 64 KB、Workflow で生成)
  • <code>docs/findings/p1-msplat-baseline-spike.toml</code>msplat M4 Max 実測、Lego 30K 3m40s/35.48dB、materials 破綻実証 (2026-06-26)
  • <code>docs/findings/brush-vs-splat-37dB-gap-analysis.md</code>brush parity gap 分析
  • <code>docs/findings/p1-axis1-phase-f1-emit-simd-falsified.toml</code><code>emit_pairs_simd</code> default OFF の根拠
  • <code>docs/strategy/2026-06-25-apple-silicon-ultracode-survey.md</code>第 2 回 ultracode 12 軸 + adversarial verify
  • <code>docs/strategy/2026-07-next-steps.md</code>A (Reframing) 確定後の戦略レイヤ
  • <code>docs/strategy/msplat-vs-otake-pareto.png</code>Pareto plot (killer figure)
  • <code>docs/architecture/brush-arch.md</code>brush v0.3 アーキテクチャ読解メモ (2026-04-24)

9.2 splat (本プロジェクト) ファイル

  • <code>shaders/forward/project.metal</code> (417 行)forward projection
  • <code>shaders/forward/tile_bin.metal</code> (380 行)tile binning & radix sort
  • <code>shaders/forward/rasterize.metal</code> (305 行)forward rasterize
  • <code>shaders/backward/project_backwards.metal</code> (472 行)backward projection
  • <code>shaders/backward/rasterize_backwards.metal</code> (517 行)backward rasterize (3 variant)
  • <code>shaders/loss/ssim.metal</code> (164 行)、<code>shaders/loss/loss.metal</code> (88 行)SSIM / L1 loss
  • <code>shaders/opt/adam.metal</code> (42 行)Adam optimizer
  • <code>crates/splat-train-v1/src/{relocate,regularize,refine,lr_schedule,config}.rs</code>MCMC paper full + refine + LR

9.3 brush ファイル

  • <code>brush/crates/brush-render/src/shaders/*.wgsl</code>helpers / sh / project_forward / project_visible / map_gaussian_to_intersects / rasterize
  • <code>brush/crates/brush-render-bwd/src/shaders/*.wgsl</code>rasterize_backwards (254 行) / project_backwards (332 行)
  • <code>brush/crates/brush-sort/src/shaders/</code>FidelityFX 6-stage radix sort
  • <code>brush/crates/brush-fused-ssim/src/lib.rs</code>988 行 CubeCL
  • <code>brush/crates/brush-train/src/</code><code>train.rs</code> / <code>config.rs</code> / <code>adam_scaled.rs</code>

9.4 msplat (rayanht v1.1.3) ファイル

  • <a href="https://github.com/rayanht/msplat" target="_blank" rel="noopener">rayanht/msplat</a>GitHub repo
  • <code>core/metal/msplat_metal.metal</code> (3,741 行)42 fused Metal compute kernels
  • <code>core/metal/msplat_metal.mm</code> (1,592 行)Metal command encoder setup / dispatch
  • <code>core/src/model.cpp</code> (597 行)Training loop orchestration / optimizer / densify / scheduler
  • <code>core/include/model.hpp</code> (102 行)Model + Adam state (6 group)
  • <code>CHANGELOG.md</code> v1.1.3SH-Adam fused、~600 MB/iter 削減、Pre-allocated per-tile bins

9.5 学術リファレンス

  • Kerbl et al. 2023"3D Gaussian Splatting for Real-Time Radiance Field Rendering", SIGGRAPH — splat / brush / msplat 共通の基礎
  • Kheradmand et al. 2024"3D Gaussian Splatting as Markov Chain Monte Carlo" — splat full / brush 簡約 / msplat 不採用
  • Niedermayr et al. 2024"StopThePop: Sorted Gaussian Splatting as a Ranked Order Renderer", arXiv:2402.00525 — brush forward (will_primitive_contribute) で採用
  • Peter-Pike Sloan 2013"Efficient Spherical Harmonic Evaluation", JCGT — splat / brush で bit-exact 採用、msplat も同等
© 2026 大竹律輝 — 松田研究室