3DGS反向传播入门指南:从数学原理到PyTorch实现

1次阅读
没有评论

共计 2173 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

3D 高斯散射(3DGS)作为神经渲染的新兴技术,能够高效建模复杂光场并实现实时渲染质量。与传统体素和点云方法相比,3DGS 通过可微分的高斯基元实现更自然的视角合成。其参数化表示与物理光照模型的兼容性,使其成为动态场景重建的热门选择。

3DGS 反向传播入门指南:从数学原理到 PyTorch 实现

数学原理拆解

  1. 3D 高斯参数化表示
    每个高斯基元定义为:
    $$G(\mathbf{x}) = \exp\left(-\frac{1}{2}(\mathbf{x}-\mu)^T\Sigma^{-1}(\mathbf{x}-\mu)\right)$$
  2. $\mu\in\mathbb{R}^3$ 为中心位置
  3. $\Sigma$ 为 3×3 协方差矩阵(需正定),实践中分解为旋转矩阵 $R$ 和缩放矩阵 $S$:$\Sigma=RS(RS)^T$

  4. 可微分渲染的雅可比计算
    像素颜色 $C$ 对高斯参数 $\theta$ 的偏导:
    $$\frac{\partial C}{\partial\theta} = \sum_{i=1}^N\frac{\partial w_i}{\partial\theta}c_i + w_i\frac{\partial c_i}{\partial\theta}$$

  5. $w_i$ 为第 $i$ 个高斯在像素点的贡献权重
  6. 需链式求导计算 $\partial w_i/\partial\mu, \partial w_i/\partial\Sigma$ 等

  7. 概率密度梯度传播
    通过重参数化技巧避免采样不可微:
    $$\nabla_\theta\mathbb{E}{\mathbf{x}\sim G}[f(\mathbf{x})] = \mathbb{E}[\nabla_\theta f(\mu + R\cdot S\cdot\epsilon)]$$}(0,I)

PyTorch 实战实现

import torch
import torch.nn as nn

class DifferentiableGaussianRender(nn.Module):
    def __init__(self, num_gaussians):
        super().__init__()
        # 初始化可学习参数
        self.means = nn.Parameter(torch.randn(num_gaussians, 3))  # [N,3]
        self.scales = nn.Parameter(torch.ones(num_gaussians, 3))  # 对角 S 矩阵
        self.rotations = nn.Parameter(torch.randn(num_gaussians, 3, 3)) # R 矩阵
        self.colors = nn.Parameter(torch.sigmoid(torch.randn(num_gaussians, 3)))

    def _build_covariance(self):
        # 保证正定性:通过 QR 分解得到正交矩阵
        R = torch.linalg.qr(self.rotations)[0]  # [N,3,3]
        S = torch.diag_embed(torch.exp(self.scales))  # 指数保证正数
        return R @ S @ S.transpose(-1,-2) @ R.transpose(-1,-2)

    def forward(self, pixels):
        cov = self._build_covariance()  # [N,3,3]
        diff = pixels[:,None] - self.means  # [P,N,3]

        # 计算马氏距离(批处理优化)inv_cov = torch.linalg.inv(cov)  # [N,3,3]
        exponent = -0.5 * (diff @ inv_cov * diff).sum(-1)  # [P,N]

        # 计算权重并归一化
        weights = torch.exp(exponent)  # [P,N]
        weights = weights / (weights.sum(-1, keepdim=True) + 1e-8)

        # 加权混合颜色
        return (weights[...,None] * self.colors).sum(-2)  # [P,3]

关键实现说明:
– 第 8 行:使用指数变换保证缩放因子为正
– 第 12 行:QR 分解强制得到正交旋转矩阵
– 第 20 行:马氏距离计算时利用广播机制避免循环

避坑指南

  1. 协方差矩阵稳定性
  2. 每次前向计算前执行 QR 分解(代码第 12 行)
  3. 对缩放参数施加 L2 正则:loss += 0.01 * self.scales.pow(2).sum()

  4. 梯度爆炸预防

  5. 限制高斯中心初始范围:means.uniform_(-1,1)
  6. 使用梯度裁剪:torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)

  7. 内存优化

  8. 分块处理像素:每次前向只计算 256×256 像素区域
  9. 混合精度训练:with torch.autocast(device_type='cuda', dtype=torch.float16):

延伸思考

  1. 如何设计自适应高斯基元数量策略?当前固定数量是否限制表达能力?
  2. 在动态场景中,能否用 RNN 或 GNN 建模高斯参数的时间演化?
  3. 现有实现是否可以利用球谐函数(Spherical Harmonics)提升光照真实性?

通过本文的代码框架,读者可快速搭建基础 3DGS 渲染器。实际部署时建议结合 CUDA 定制核函数加速,并尝试将高斯参数预测与 NeRF 等架构结合。期待看到更多关于动态分辨率与物理约束结合的创新方案。

正文完
 0
评论(没有评论)