确保数值稳定性

在上一篇文章中,我们已经成功将协方差矩阵投影到了屏幕的二维空间(Screen Space),得到了 \Sigma'

在理想的数学世界里,一切都很完美:这个二维协方差矩阵 \Sigma' 理应是对称的(Symmetric),并且是半正定的(Positive Semi-Definite)。但在实际的计算机编程中,由于浮点数运算(Floating Point Operations)固有的精度限制和四舍五入误差,这个矩阵可能会悄悄失去这些优良的数学性质。

在这篇文章中,我们就来聊聊如何通过几步“数值稳定性技巧”,把偏离轨道的矩阵拉回正轨,并过滤掉那些异常的数据。


强制对称

当我们对一个矩阵进行多次乘法操作后,微小的误差累积可能会导致它不再严格对称(即矩阵的转置不再等于它本身)。为了修复这个问题,我们可以使用一个非常经典且简单优雅的代数技巧:强制对称。

对于任意一个方阵 A,如果你将它与它的转置矩阵 A^T 相加,然后再取平均值,得到的新矩阵必定是对称的。

A_{sym} = 0.5 \times (A + A^T)

  1. sigma_camera_v = (sigma_camera_v + sigma_camera_v.transpose(1, 2)) * 0.5

确保半正定

虽然矩阵对称了,但我们还必须保证它是半正定的(通俗来说,高斯分布的方差不能是负数,且不能无限趋近于零导致奇异)。为此,我们需要深入矩阵的内部,对其进行特征值分解(Eigen Decomposition)。

其核心操作步骤为:

1. 分解矩阵:计算出矩阵的特征值(Eigenvalues)和特征向量(Eigenvectors)。

2. 截断特征值(Clamping):将过小的特征值拉上来,将过大的特征值压下去。

3. 重构矩阵:用修改后的特征值和原来的特征向量重新拼装出协方差矩阵。

  1. evals, evex = torch.linalg.eigh(sigma_camera_v)
  2. evals = torch.clamp(evals, min=1e-6, max=1e4)
  3. sigma_camera_v = evex @ torch.diag_embed(evals) @ evex.transpose(1, 2)

异常数据过滤

经过上述两步,我们的数学模型已经很稳定了。但在极少数情况下,如果初始数据极其离谱,甚至出现了无穷大(Inf)或非数字(NaN),我们必须在把它们送入下一步之前将其彻底剔除。

我们需要创建一个名为 keep 的布尔掩码(Boolean Mask),用来记录哪些高斯点是健康、有限的。

  1. # 异常数据过滤 (Guardrail Masking)
  2. flat_sigma = sigma_camera_v.reshape(sigma_camera_v.shape[0], -1)
  3. keep = torch.isfinite(flat_sigma).all(dim=-1)

此处 torch.isfinite 会返回一个形状为 [N, 4] 的布尔张量(全是 True 或 False)。

但我们需要的是一个形状为 [N] 的一维掩码,用来决定每个高斯点是去是留。.all(dim=-1) 沿着最后一个维度(即包含 4 个数值的维度)进行逻辑“与”运算。