
Spirula Studio的反向传播如何把图像梯度精准送回每个高斯【免费下载链接】spirula-studioCross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA.项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studioSpirula Studio 是一个跨厂商的 3D Gaussian Splatting3DGS训练器从原始照片/视频一路训练到 splat 再到带纹理网格全程只需一个独立二进制文件无需 Python/PyTorch 或 COLMAP。本文拆解它反向传播的核心链路训练时每个像素上的图像误差是如何被层层倒推最终精准落到数百万乃至上千万个高斯的六个属性位置、旋转、尺度、不透明度、DC 颜色、SH 系数上的。一、先看全景一次训练步的正向 → 反向在 3DGS 训练中反向传播的目标很简单把渲染图与真实图之间的差距换算成每个高斯该往哪个方向微调。Spirula Studio 在 docs/architecture.md 中给出了正向的组成顺序渲染 → 背景混合 → [PPISP] → 显示色空间编码 → 双边网格(bilagrid) → [PPISP] → 损失反向传播就是严格按相反顺序把这条链拆开。引擎的完整编排集中在 src/engine/EngineLoss.cpp其中engine_compute_loss_backward是整个反向流程的入口而 src/engine/Engine.h 则把 API 明确分组为生命周期、setup、forward、lossbackward、优化器步进等。二、第一步逐像素损失产出图像梯度 反向传播的种子是每个像素的损失实现在 Slang 着色器 src/shaders/per_pixel_losses.slang 中。它把渲染结果与真值GT放在一起同时计算多项监督RGBL1 L2以及 YUVBT.601分量损失深度log 空间的 Pearson 相关法线余弦相似度损失含渲染法线 vs 深度法线的一致性正则Alpha透射率BCE 掩码监督 推向 0/1 的正则畸变图、中值深度等附加项这份 shader 里最关键的设计损失函数用[Differentiable]标记Slang 编译器会自动为其生成反向版本bwd_diff(per_pixel_losses)。也就是说图像对每个中间量的梯度对渲染 RGB、渲染深度、透射率 Ts 的导数是编译器帮你算好的你只需手写正向公式。产出的三个每像素输出梯度——v_render_rgb、v_render_depth、v_render_Ts——就是接下来所有反向步骤的起点见 src/engine/EngineLoss.cpp 中的PerPixelGrads结构。三、第二步按逆序解开图像空间修正链 正向时图像经过了背景混合、PPISP、色空间转换、双边网格等修正反向时必须逐一倒放。EngineLoss.cpp中有一段清晰的逆序钩子代码正向顺序后执行者反向钩子作用损失—产出像素梯度双边网格 / PPISP / 色空间_bilagrid_bwd→_ppisp_bwd→_color_space_bwd把梯度还原回修正前的空间同时顺手累积修正参数自身的梯度背景混合_engine_background_backward_hook把透射率梯度叠加进v_render_Ts深度 → 法线depth_to_normal_backward把法线梯度折回深度梯度这些钩子的精妙之处在于每个钩子会就地改写v_render_rgb把修正后空间的梯度换成修正前空间的梯度后一个钩子直接消费它——梯度像接力棒一样一路传递而 bilagrid/PPISP 的自身参数梯度则被分流走交给各自的优化器。四、第三步光栅化反向——从像素回到屏幕空间 ️拿到像素梯度后进入 src/kernels/raster/RasterizationBwd.cuh 中的rasterize_to_pixels_3dgs_bwd。正向光栅化时每个高斯被投影成一个屏幕椭圆与若干图像 tile 相交并按深度排序混合。反向时它做三件事复用正向保存的现场tile 偏移、相交列表flatten_ids、每个像素最后的可见高斯last_ids、透射率累积render_Ts——这些缓存让反向无需重新求交把像素梯度按 alpha 贡献分摊沿着正向的混合顺序把v_render_rgb、v_render_Ts等权重地拆回每个落在该像素上的高斯原子累加同一个高斯可能出现在成百上千个像素中各像素的贡献通过atomicAdd汇总得到该高斯在屏幕空间的梯度v_splats_s。这正是 3DGS 反向传播最昂贵的一步——它直接按可见 (相机, 高斯) 对的数量nnz增长。Spirula Studio 为此做了大量内存工程屏幕行与其梯度共享布局、16 位打包 AABB 等细节写在 docs/notes/vram-splat-x-img.md。五、第四步投影反向——从屏幕空间回到世界坐标 屏幕空间梯度还差最后一跳。src/kernels/projection/ProjectionBwd.cuh 中的projection_3dgs_backward把每个高斯在屏幕上的梯度通过相机内参/外参的链式法则换算成世界空间中六个属性的梯度属性梯度去向位置 meansgrad.means旋转 quatsgrad.quats尺度 scalesgrad.scales不透明度 opacitygrad.opacitiesDC 颜色grad.features_dcSH 系数grad.features_sh其中 SH 颜色项有个细节若启用了 SH 值量化8/16 位压缩存储见 docs/notes/sh-quant-layout.md投影反向会直接从量化码本读取源系数来计算 vjp而梯度本身始终保持 fp32保证优化精度不受压缩影响。六、省显存的两个关键技巧 这也是 Spirula Studio 能用8GB 显存训练 1000 万 SH3 高斯的核心原因1. 分块量化梯度累积grad-quant普通 fp32 梯度缓冲对 1000 万高斯是天文数字。EngineLoss.cpp的_alloc_grad_buffers支持把每个属性按256 个高斯为一块做 16 位量化累积投影反向内核对每个子批次解码 → 累加 → 重新量化显存占用骤降而精度损失可忽略。2. 融合投影反向 优化器FPBO启用use_fused_proj_bwd_optim后世界梯度累加被直接折叠进 Adam 优化器的寄存器里整个 fp32 梯度缓冲可以完全不分配grad.means等直接置空。代码中还能看到子批次训练的巧妙配合只有第一个子批次清零累积器后续批次atomicAdd进同一块缓冲优化器再一并消费。一句话总结这条链路逐像素损失自动微分→ 逆序解图像修正 → 光栅化反向像素→屏幕原子累加→ 投影反向屏幕→世界六属性→ 量化累积/融合优化。七、动手体验与源码索引 构建 Vulkan 后端支持 NVIDIA / AMD / Intel / Apple GPUgit clone https://gitcode.com/GitHub_Trending/sp/spirula-studio cd spirula-studio/ bash build_develop.bash -DSS_BACKENDvulkan -DSS_ENABLE_PATENTEDON反向传播源码导航模块路径损失 反向总编排src/engine/EngineLoss.cpp逐像素损失Slang 可微分src/shaders/per_pixel_losses.slang光栅化反向内核src/kernels/raster/RasterizationBwd.cuh投影反向内核src/kernels/projection/ProjectionBwd.cuh量化梯度 / SH 量化布局src/core/GradQuant.cuh、docs/notes/sh-quant-layout.md引擎分层与顺序规则docs/architecture.mdsplat × 图像 显存工程docs/notes/vram-splat-x-img.md理解了这条梯度高速公路你再去看 Spirula Studio 的量化训练、融合优化器等高级特性就会发现它们不过是同一条链路上更省、更快的变体而已。【免费下载链接】spirula-studioCross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA.项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考