【三维重建】SpotlessSplats:去除瞬态干扰物的三维高斯喷溅(3DGS)

news2024/11/16 4:12:51

在这里插入图片描述

代码:https://spotlesssplats.github.io
论文:https://arxiv.org/pdf/2406.20055
来源:DeepMind,多伦多大学,斯坦福大学,西蒙弗雷泽大学


提示:关注B站【方矩实验室】,查看视频讲解

文章目录

  • 摘要
  • 一、前言
  • 二、相关工作
    • 2.1 NeRF的鲁棒性
    • 2.2 Precomputed features
    • 2.3 Robustness in 3DGS
  • 三、Background
    • 3.1 3DGS的鲁棒优化
  • 四、method
    • 4.1 识别干扰物(distractors)
      • 4.1.1 空间聚类(Spatial clustering)
      • 4.1.2 时空聚类(Spatio-temporal clustering)
    • 4.2 3DGS的鲁棒性优化
      • 4.2.1 计划采样来进行预热(Warm up with scheduled sampling)
      • 4.2.2 基于图像的训练中的 Trimmed estimators(裁剪估计器)
      • 4.2.3 对“重置不透明度”的替代
      • 4.2.4 Appearance modeling (外观建模)
  • 五、实验结果
    • 5.1 无干扰物的三维重建
    • 5.2 基于利用率的剪枝的效果
    • 5.3 Ablation study
  • 六、代码讲解
  • 额外知识
    • 1.层次聚类(Agglomerative clustering)
    • 2.Lipschitz constant(普希茨常数)


摘要

三维高斯喷溅(3DGS)是一种最新的三维重建技术,提供了高效的训练和渲染速度,使其适用于实时应用。然而,目前的方法需要高度控制的环境——没有移动的人或风吹的元素,以及一致的照明——以满足3DGS的视图间一致性假设。这使得重建现实世界的捕获成为问题。我们提出了无斑点斑图,一种利用预训练和通用特征结合鲁棒优化来有效地忽略瞬态干扰物的方法。我们的方法实现了最先进的重建质量。

一、前言

  利用神经辐射场(NeRF)和最近的三维高斯喷溅(3DGS)从二维图像中重建三维场景一直是视觉研究的热点。目前的大多数方法都假设图像同时捕获,完美pose,无噪声。这简化了3D重建任务,但在现实世界中很少存在,移动物体(如人或宠物)、照明变化和其他虚假的光度不一致性会降低性能,限制了应用。

  在NeRF训练中,通过基于颜色残差的大小来降低加权或丢弃不一致的观察值,已经纳入了对异常值的鲁棒性。对于3DGS,自适应稠密化引入了颜色残差的variance,当直接应用来自健壮NeRF框架的现有思想时,影响这些瞬态的检测。

  SpotlessSplats(SLS),一个用于3DGS的三维场景重建框架,通过无监督检测训练图像中的异常值。我们没有在RGB空间中检测异常值,而是 利用了 text-to-image 模型中更丰富、学习到的特征空间。该特征嵌入的有意义的语义结构,更容易检测结构化干扰物的spatial support ,例如,与单个对象相关联。我们没有使用手动指定的鲁棒kernels 来进行异常值识别[40],而是利用特征空间中的自适应方法来检测异常值 。为此目的,我们在这个框架内考虑了两种方法 第一种方法是使用局部特征嵌入的非参数化聚类,来寻找结构化异常值的图像区域第二种方法使用MLP,以无监督的方式训练来预测特征空间中可能与干扰物相关的部分进一步引入了一种(互补的和通用的)稀疏化策略,与鲁棒优化兼容,提供类似的重建质量,减少2到4倍的飞溅量 ,即使在无干扰的数据集上,显著节省计算和内存。通过对随机捕获的场景[37,40]的具有挑战性的基准的实验,SLS在重建精度方面始终优于竞争方法。

  1. 一种自适应的、鲁棒的损失,利用 text-to-image的扩散特征,可靠地识别正常的捕获中的瞬态干扰物,消除了对光度误差的过拟合问题。
  2. 一种新的稀疏化方法与我们的鲁棒损失兼容,显著减少了高斯数量,在不损失保真度的情况下节省了计算和内存

二、相关工作

  神经辐射场(NeRF),由于其高质量的重建和新颖的三维场景视图合成而得到了广泛的关注。NeRF将场景表示为与视图相关的发射体。体渲染方程]的吸收-发射部分渲染。随后又进行了多次增强。快速训练和推理[8,28,46,54]、有限或单视图(s) [15,35,55]训练和同时姿态推理[20,22,50]使辐射场更接近实际应用。最近,3D高斯溅射(3DGS)[17]被提出作为一种基于原始的替代nerf,具有显著更快的渲染速度,同时保持高质量。三维高斯分布可以有效地栅格化使用阿尔法混合[59]。这种简化的表示利用了现代GPU硬件来促进实时渲染。3DGS的效率和简单性促使了该领域内的焦点转移,许多NeRF增强被快速移植到3DGS

2.1 NeRF的鲁棒性

  最初的NeRF论文对捕获设置做出了强有力的假设:场景需要是完全静态的,并且在整个捕获过程中照明应该保持不变。最近 ,NeRF已经扩展到对违反这些约束的非结构化“in the wild”捕获图像进行训练。两项有影响力的工作,NeRF-W [25]和RobustNeRF [40]解决了瞬态干扰物的问题,都使用光度误差作为指导。NeRF-W [25]建模了一个三维不确定性场渲染到二维异常掩模,降低了高误差像素的损失,以及一个防止退化解的正则化器。NeRF-W [25]还通过学习到的嵌入来建模全局外观,这对于在广泛变化的光照和大气条件下捕获的图像很有用。城市辐射场(URF)[36]和Block-NeRF [47]同样将学习到的外观嵌入应用于大规模重建。HA-NeRF [7]和Cross-Ray[53]模型的2D离群值掩模,而不是3D场,利用CNN或Transformer进行交叉射线相关。

  RobustNeRF [40]从鲁棒估计的角度来处理这个问题,使用二值权值由阈值渲染误差确定,并使用模糊核来反映属于干扰物的像素是空间相关的假设。然而,RobustNeRF和NeRF-W变体[7,53]都完全依赖于RGB残差,因此,它们经常用与背景相似的颜色错误地分类瞬态数据;参见图2中的稳健性mask。为了避免这种情况,以前的方法需要仔细调整超参数,即RobustNeRF中的模糊核大小和阈值,以及NeRF-W中的正则化器权重。相反,我们的方法使用文本到图像模型的丰富表示来进行语义离群值建模。这避免了直接的RGB错误监督,因为它依赖于特征空间的相似性来进行聚类。

在这里插入图片描述

  最近的NeRF On-the-go[37]发布了一个随意捕获的视频数据集。与我们的方法类似,它使用DINOv2 [31]的语义语义特征通过一个小MLP预测离群mask。然而,它也依赖于 structural rendering error的直接监督,导致超出或分割不足;参见图3。NeRF-HuGS [6]结合了来自COLMAP的鲁棒稀疏点云[43]的启发式方法,以及现成的语义分割来去除干扰物。这两种启发式方法在[37]数据集的严重瞬态occlusions下都失败了。

2.2 Precomputed features

  使用强大的预计算的视觉特征,如DINO [4,31],已经证明了推广到多个视觉任务的能力。DDPM扩散模型[13,39,45]因其从文本提示[30,34,38,41]中获得的逼真图像生成能力而引起了人们的关注。这些模型的内部特征已被证明是同样强大的,并能够推广到许多领域,如分割和关键点配准。

2.3 Robustness in 3DGS

  多个工作解决了对野外捕获数据的3DGS训练。SWAG [10]和GS-W [57]模型外观变化使用学习的全局和局部每个原型外观嵌入。类似地,WE-GS [49]使用一个图像编码器来学习对每个图像的颜色参数的适应。Wild-GS [52]学习了一个用于外观嵌入的空间三平面场。所有这些方法[49,52,57]都采用了像NeRFW [25]这样的干扰物的mask预测方法,通过预测二维干扰物mask来降低高误差渲染像素的权重。SWAG [10]学习每个高斯分布的每幅图像的不透明度,并将具有高不透明度方差的原型表示为瞬态。值得注意的是SWAG [10]和GS-W[57],当将额外的学习瞬态掩模应用于Phototourism scenes场景[44]时,它们比本地/全局外观建模没有或几乎没有改进。SLS专注于具有较长时间瞬变和最小外观变化的临时捕获,这在视频捕获中很常见,如数据集[37]。

三、Background

  三维高斯溅射(3DGS)将三维场景表示为三维各向异性高斯 G = G= G={ g i g_i gi}的集合。每个splat g i g_i gi,由一个均值 µ i µ_i µi,一个正半定协方差矩阵 Σ i Σ_i Σi,一个不透明度 α i α_i αi,并由球谐系数 c i c_i ci参数化。

  3D场景表示通过栅格化呈现到屏幕空间。我们表示W为透视变换矩阵,三维协方差的投影二维屏幕空间可以近似为: Σ ~ = J W Σ W T J T \tilde{Σ}=JWΣW^TJ^T Σ~=JWΣWTJT,J是投影矩阵的雅可比矩阵,它提供了一个用线性近似非线性投影的过程。

  为了确保Σ在整个优化过程中表示协方差(即正半定),协方差矩阵参数化为 Σ = R S S T R T Σ=RSS^TR^T Σ=RSSTRT,其中尺度S=diag (s)与s∈R3,旋转R从一个单位四元数q计算。一旦计算了屏幕空间中的分割位置和协方差,图像形成过程执行体积渲染作为alpapha混合,这反过来需要沿视图方向排序。请注意,与NeRF每次渲染一个像素不同,3DSG以一次向前传递的方式渲染整个图像。

  

3.1 3DGS的鲁棒优化

  与之前的作品[18,26,47]不同,我们没有对瞬态对象类、外观和/或形状进行假设。

  我们通过借鉴RobustNeRF来解决这个问题,通过识别输入图像中应该被mask的部分来消除干扰物。该问题简化为预测(无监督)每个训练图像的内部/外部点的maks { M n M_n Mn} n = 1 N ^N_{n=1} n=1N,并通过mask L1损失来优化模型:

在这里插入图片描述

  其中 I ^ n ( t ) \hat{I}^{(t)}_n I^n(t) 是在训练迭代(t)时的渲染结果。RobustNeRF 通过观察训练过程中的光度不一致来检测瞬态效应;即,具有大的损失值的图像区域。通过用 R n ( t ) = I n − I ^ n ( t ) R^{(t)}_n =I_n - \hat{I}^{(t)}_n Rn(t)=InI^n(t) 表示残差的图像(轻微滥用符号,因为1范数是沿颜色通道像素执行的),mask计算为:

在这里插入图片描述

  其中 1 1 1是一个指示函数(为真则返回1,否则为0),ρ是一个广义中位数,τ是一个超参数,控制cut-off percentile;B是一个(标准化)3×3box 滤波器,通过卷积(~)执行 a morphological dilation。直观地说,上面(2)总结的RobustNeRF [40]通过假设内部值/异常值是空间相关的,扩展了trimmed robust estimator[9]。我们发现,直接将[40]的想法应用到3DGS中,即使不受如图2中所示的误导性颜色残余情况的限制,也不能有效地去除异常值。相反,为了适应3DGS的表现和训练过程中的差异,需要进行一些调整(4.2节);

四、method

  以上方法中的干扰物mask 是基于新视图的光度误差而建立的。相反,我们建议根据干扰物的语义来识别它们,在训练过程中,识别其的再次出现。我们把语义看作是从一个自监督的二维基础模型(如[48])计算出来的特征映射。从训练图像中去除干扰物的过程,转化为识别可能导致大光度误差的特征子空间的过程。举个例子,一只狗在静态场景中散步。要么在每张图像(4.1.1节),要么或更广泛地说,在数据集中(4.1.2节)中识别“狗”的像素(可能是重建中出现问题的原因),并自动从优化中删除它们。SpotlessSplats旨在减少对局部颜色残差的离群值检测和对颜色误差的过拟合,而强调依赖像素之间的语义特征相似性,也称为“clustering”。

4.1 识别干扰物(distractors)

  给定输入图像{ I n I_n In} n = 1 N ^N_{n=1} n=1N,使用 Stable Diffusion提取特征图{ F n F_n Fn} n = 1 N ^N_{n=1} n=1N。这个预处理步骤在训练开始之前执行一次,使用其计算 inlier/outlier masks M ( t ) M^{(t)} M(t);我们删除图像索引n以简化符号,因为训练过程涉及每批一个图像。现在详细介绍检测outliers 的两种不同的方法:

4.1.1 空间聚类(Spatial clustering)

  预处理阶段,额外对图像区域进行无监督聚类。与超像素技术[14,21]类似,我们将图像过度分割成C个空间连接组件的固定基数集合;参见“聚类特征”图2。具体说,在特征图 F F F上执行层次聚类[2011年],其中每个像素都连接到它周围的8个像素。将像素p分配给聚类c表示为 C [ c , p ] C[c,p] C[c,p]∈{ 0 , 1 0,1 0,1},并将聚类初始化为每个像素其自身聚类。融合簇间特征方差最少的集群(collapsing those that cause the least amount of inter-cluster feature variance differential before/post collapse)。当C=100集群仍然存在时,集群将终止( Clustering terminates when C=100 clusters remain)。

  然后,从公式(2)的mask内部像素的百分比,计算出簇c是一个内部像素的概率:
在这里插入图片描述

  然后将簇标签传播回像素:

在这里插入图片描述

使用 M a g g ( t ) M^{(t)}_{agg} Magg(t),而不是 M ( t ) M^{(t)} M(t),作为 inlier/outlier的mask来训练(1)中的3DGS模型。这个模型配置指定为“SLS-agg

4.1.2 时空聚类(Spatio-temporal clustering)

  第二种方法是训练一个分类器,根据像素的相关特征来决定像素是否应该被(1)优化。为此,我们使用一个带有参数θ的MLP,从像素特征中预测每个像素的inlier概率:

在这里插入图片描述

  分类器参数 θ ( t ) θ^{(t)} θ(t)与3DGS优化同时更新。H用1×1卷积实现,MLP和3DGS交替优化。MLP分类器损失为:
在这里插入图片描述

在这里插入图片描述
λ=0.5,U和L是由当前残差的mask计算出的自监督标签:

在这里插入图片描述

  换句话说,我们只在像素上直接监督分类器,这样我们就可以根据重构残差来确定 inlier
status,否则我们就严重依赖于特征空间中的语义相似性;见图4。为了进一步正则化H,将相似的特征映射到相似的概率,我们通过 L r e g L_{reg} Lreg最小化它的 Lipschitz constant[文献23]。

在这里插入图片描述

  然后使用 M m l p ( t ) M^{(t)}_{mlp} Mmlp(t),而不是 M ( t ) M^{(t)} M(t),作为 inlier/outlier的mask来训练(1)中的3个DGS。我们将此模型配置指定为“SLS-mlp”

4.2 3DGS的鲁棒性优化

  直接将任何鲁棒的mask 技术应用于3DGS,会导致mask 过拟合到一个过早的3DGS模型(见4.2.1节),比如基于图像的训练(4.2.2节),或3DGS的密集化策略(见4.2.3节)使得inlier estimator产生偏差。下面我们提出了解决方案。

4.2.1 计划采样来进行预热(Warm up with scheduled sampling)

  逐步应用mask很重要,因为初始残差是随机的。如果我们使用学习到的聚类来mask,这是双重正确的,因为MLP在优化的早期不会收敛,并随机预测mask。此外,直接使用 outlier mask 往往导致 quickly overcommit to outliers,防止有价值的错误的反向传播,并从这些区域学习。我们通过将每个像素的mask策略,制定为基于mask的伯努利分布的采样来缓解这种情况:

在这里插入图片描述

  其中,α是一个阶梯指数调度器( staircase exponential scheduler),从1到0,提供了一个热身。这使得我们仍然可以在我们不确定的区域中稀疏地采样梯度,从而可以更好地分类离群值。

  

4.2.2 基于图像的训练中的 Trimmed estimators(裁剪估计器)

  [40]实现了一个修剪后的估计器,其基本的假设是每个minibatch(平均)包含相同比例的异常值。这个假设在3DGS训练运行中被打破了,其中每个minibatch都是一个完整的图像,而不是从训练图像集中随机抽取的一个像素集。这给实现(2)的广义中值带来了挑战,因为异常值的分布在图像之间是有偏颇的

  我们通过跟踪多个训练批次上的残差量级来解决:将残差的magnitudes离散为B个直方图buckets,宽度等于渲染误差的下界( 1 0 − 3 10^{−3} 103)。我们通过对bucket population的有折扣的更新,来升级每次迭代中每个bucket的似然,类似于快速中值滤波方法[32]。这保持了残差分布的移动估计,内存消耗不变,从中我们可以提取出广义中值 ρ ρ ρ作为直方图总体中的 τ τ τ 分位数

4.2.3 对“重置不透明度”的替代

  原始GS每M次迭代,会重置所有高斯分布的不透明度opacity reset处理两个问题:首先,在具有挑战性的数据集中,在相机附近的优化容易积累高斯分布,常被称为floater。这很难处理,因为它迫使相机光线尽早饱和于透光率,因此梯度没有机会流通到场景的遮挡部分。opacity reset降低了所有高斯分布的不透明度,这样梯度就可以沿着整个射线再次流动第二,opacity reset控制高斯数量。将不透明度重置为一个低值,允许(永远无法恢复到更高不透明度的GS)通过自适应密度控制机制进行修剪。

  然而,opacity reset干扰了残差分布跟踪,导致残影在opacity reset 后的迭代中变大。简单的禁用并不能work,因为是优化必须的。根据文献[11], 我们采用基于利用率的修剪(UBP:utilization-based pruning)我们跟踪渲染的颜色相对于每个高斯 g g g的投影位置 x g x_g xg的梯度 。与3D位置相比,计算关于投影位置的导数,允许一个更少的内存密集型的GPU实现,同时提供了一个与[Bayes’ Rays: Uncertainty quantification in neural radiance fields. CVPR, 2024]中类似的度量。其中,利用率 utilization定义为:

在这里插入图片描述

  我们在图像全局 (W×H)来平均该指标,在前一组 ∣ N T ( t ) ∣ = 100 |N_T(t)|=100 NT(t)=100张图像中,每100步计算一次。当 u g < κ u_g<κ ug<κ, with κ = 1 0 − 8 κ = 10^{−8} κ=108时,裁剪高斯。基于利用率的剪枝替换opacity reset,实现了两个原始目标,同时减轻了对残差分布跟踪的干扰。基于利用率的剪枝通过使用更少的高斯原型显著地压缩了场景表示,同时即使在无离群值的场景中也能实现高重建质量;参见第5.2节。它还能有效地处理floater(见图10)。floater的利用率很低,因为他们参与渲染很少的视图。此外,使用(11)中所示的masked derivatives, 可以去除在 warm-up阶段的 any splat that has leaked through the robust mask。

4.2.4 Appearance modeling (外观建模)

.
  原始GS假设场景的图像(包括干扰物)在光度上是完全一致的,无法应用于自动曝光和白平衡。SpotlessSplats结合文献[36]的方案,适用于文献[17]的球谐表示的视图依赖的颜色。详细的,共同优化了每个输入摄像机视图的latent z n ∈ R 64 z_n∈R^{64} znR64,并通过MLP将其映射到作用于谐波系数 c c c 的线性变换:

在这里插入图片描述

  其中 ⚪ 是 Hadamard 乘积(矩阵的逐元素相乘),b模型改变了图像的亮度,a提供了表达能力来补偿白平衡。在优化过程中,可训练的参数还包括 θ Q θ_Q θQ和{ z n z_n zn}。这种简化的模型可以有效地防止 z n z_n zn在按图像调整时过度解释干扰物,就像在一个更简单的GLO [NeRF in the Wild]中发生的那样;参见Rematas等人的[ Urban Radiance Fields ]进行分析。

  

  

五、实验结果

  数据集。我们在随机捕获的 RobustNeRF [40] 和 NeRF on-the-go[37]数据集上评估。RobustNeRF数据集包括四个充满干扰和无干扰训练分割的场景。 ‘Crab’ 和 ‘Yoda’场景具有不同的干扰物,不是在一个休闲视频中捕获的。NeRF on-the-go数据集有6个场景,有三个水平的瞬态干扰物遮挡(低、中、高)和一个单独的干净测试集用于定量比较。

  基线。三维高斯喷射方法尚未广泛解决无干扰物重建的问题。现有方法主要关注全局外观变化,如亮度变化[10,19,49],而不是关注为此任务策划的随机捕获数据集。此外,这些方法还没有公开可用的源代码。因此,我们与普通的3DGS方法和稳健的NeRF方法进行了比较。我们比较了最先进的NeRF方法,NeRFon-go[37],NeRF-hugs[6]和RobustNeRF[40],MipNeRF-360

  指标。PSNR、SSIM和LPIPS的重建指标(LPIPS指标使用标准化的VGG特征)。NeRF-HuGS [6]报告来自AlexNet特性的LPIPS指标;为了公平比较,我们计算并报告其发布的VGG LPIPS指标。

  实施细节。模型都经过了30k次迭代的训练。我们关闭不透明度重置,在第8000步,只重置非扩散球谐系数到0.001。这确保了在MLP训练的早期阶段泄露的任何干扰物都不会被建模为视图依赖效应。我们每500步到15000步,每100步运行UBP。对于MLP训练,我们使用具有0.001学习率的Adam优化器。我们从SD v2.1的第2个上采样层计算图像特征,去噪时间步长为261,和一个空提示符中计算图像特征。Tang等人[48]发现这种配置对分割和关键点匹配任务最有效。我们将degree 20的位置编码拼接作为MLP的输入。

5.1 无干扰物的三维重建

  RobustNeRF [40] 和 NeRF on-the-go评估我们的方法。在图5定量地显示了SLS-mlp在RobustNeRF数据集上优于所有稳健的基于nerf的基线。对原始3DGS的改进,性能更接近理想的干净模型,特别是在“Yoda”和“Android”上。定性结果表明,原始3DGS试图将干扰物建模为noisy的floater((‘Yoda’, ‘Statue’))或视角依赖效应(“Android”)或两者的混合物(“Crab”)。NeRF-HuGS [6]使用基于分割的掩模显示s signs of over masking(去除四个场景中的静态部分),或under-mask in challenging sparsely sampled views letting in transient objects(“Crab”)。

  图3和图6中,对NeRF on-the-go数据集进行了类似的分析。对于低遮挡场景,来自COLMAP [42]点云的原始3DGS的鲁棒初始化,特别是RANSAC对异常值的拒绝,足以产生良好的重建质量。然而,随着干扰物密度的增加,3DGS重建质量下降,定性结果显示干扰物瞬态泄漏。此外,定性结果显示,NeRF在工作时没有去除训练早期阶段的一些干扰物((‘Patio’, ‘Corner’, ‘mountain’ and ‘Spot’),这显示出与渲染错误过拟合的进一步迹象。这也可以看到在细节的over-masking(‘Patio High’)或更大的结构(“喷泉”)被完全去除。

在这里插入图片描述

在这里插入图片描述

5.2 基于利用率的剪枝的效果

  在我们所有的实验中,使我们提出的基于利用的修剪(UBP)(Sec。4.2.3),将高斯数从4×减少到6×。这种压缩意味着启用UBP的训练时间至少减少了2×,在推理期间减少了3×。图10显示,启用UBP可能会略微降低定量测量值,但在实际应用中,最终的渲染效果更干净,漂浮物更少(例如,图像的左下角)。类似的观察结果表明,PSNR和LPIPS等指标可能不能像渲染的视频那样清晰地完全反映飞蚊群的存在。考虑到高斯数的大幅减少,我们提出UBP作为一种适用于杂乱和干净的数据集的压缩技术。图7显示,在干净的MipNeRF360 [2]数据集上,使用UBP而不是不透明度重置,在保持渲染质量的同时,将高斯数从2×减少到4.5×

5.3 Ablation study

  在图8中,我们比较了SLS的性能与其他健壮的掩蔽技术的进展。该进展始于简单地应用一个鲁棒过滤器(2),然后应用SLS-agg,最后在SLS-mlp中使用MLP。我们证明了SLS-agg和SLS-mlp都能够有效地从重建的场景中去除干扰物,同时保持对场景的最大覆盖范围。此外,在图9和图10中,我们减少了我们在架构设计和第4.2节中提出的调整中的选择。图9显示,使用一个MLP而不是一个小的CNN(都大约有30K参数,和两个非线性激活)可以更好地适应微妙的瞬变,如阴影。选择正则化器权重的λ似乎没有什么影响。在凝聚聚类中,更多的聚类通常会得到更好的结果,在100个聚类后收益减少。图10进一步说明了UBP在去除泄漏的干扰物方面的有效性。我们的其他适应能力,GLO,热身阶段和伯努利抽样都显示出了改进。

在这里插入图片描述

六、代码讲解

# 1.渲染图像-------------------------------------------------------------------
renders, alphas, info = self.rasterize_splats(
   camtoworlds=camtoworlds,
   Ks=Ks,
   width=width,
   height=height,
   sh_degree=sh_degree_to_use,
   near_plane=cfg.near_plane,
   far_plane=cfg.far_plane,
   image_ids=image_ids,
   render_mode="RGB+ED" if cfg.depth_loss else "RGB",
)
colors, depths = renders[..., 0:3], renders[..., 3:4]
# 2.robust loss(loss_type)---------------------------------------------------
error_per_pixel = torch.abs(colors - pixels)           # torch.Size(1, 377, 503, 3)
pred_mask = self.robust_mask( error_per_pixel, self.running_stats["avg_err"]=1)                                                      
# 像素误差小于阈值,或邻居中至少一个误差小于阈值,则为1,否则为 0。具体代码为:

    def robust_mask(
        self, error_per_pixel: torch.Tensor, loss_threshold: float
    ) -> torch.Tensor:
        epsilon = 1e-3
        error_per_pixel = error_per_pixel.mean(axis=-1, keepdims=True)
        error_per_pixel = error_per_pixel.squeeze(-1).unsqueeze(0)
        is_inlier_pixel = (error_per_pixel < loss_threshold).float()
        window_size = 3
        channel = 1
        window = torch.ones((1, 1, window_size, window_size), dtype=torch.float) / (
            window_size * window_size
        )                                                                                # 每个像素是否有至少一个邻居,误差小于阈值
        if error_per_pixel.is_cuda:
            window = window.cuda(error_per_pixel.get_device())
        window = window.type_as(error_per_pixel)
        has_inlier_neighbors = F.conv2d(
            is_inlier_pixel, window, padding=window_size // 2, groups=channel
        )
        has_inlier_neighbors = (has_inlier_neighbors > 0.5).float()
        is_inlier_pixel = ((has_inlier_neighbors + is_inlier_pixel) > epsilon).float()
        pred_mask = is_inlier_pixel.squeeze(0).unsqueeze(-1)  
        return pred_mask 

if cfg.semantics:
    sf = data["semantics"].to(device)                  # (1,1280,50,50)

sf = nn.Upsample(
    size=(colors.shape[1], colors.shape[2]),
    mode="bilinear",
)(sf).squeeze(0)                               # # (1,1280,377, 503)

pos_enc = get_positional_encodings(
    colors.shape[1], colors.shape[2], 20
).permute((2, 0, 1))                           # torch.Size([80, 377, 503])

sf = torch.cat([sf, pos_enc], dim=0)           # (1,1360, 377, 503)
sf_flat = sf.reshape(sf.shape[0], -1).permute((1, 0))    # (189631, 1360)
self.spotless_module.eval()
pred_mask_up = self.spotless_module(sf_flat)   # MLP+sigmoid(1360->1)
pred_mask = pred_mask_up.reshape(
    1, colors.shape[1], colors.shape[2], 1
)                                              # torch.Size([1, 377, 503, 1])

# 计算 lower and upper bound masks for spotless mlp loss
lower_mask = self.robust_mask(
    error_per_pixel, self.running_stats["lower_err"]
)
upper_mask = self.robust_mask(
    error_per_pixel, self.running_stats["upper_err"]
)

alpha = np.exp(cfg.schedule_beta * np.floor((1 + step) / 1.5))   # alpha 值在01之间变化,表示当前训练的"温度",用于控制后续的随机采样过程
pred_mask = torch.bernoulli( torch.clip(
        alpha + (1 - alpha) * pred_mask.clone().detach(),
        min=0.0, max=1.0, ))
        
rgbloss = (pred_mask.clone().detach() * error_per_pixel).mean()
ssimloss = 1.0 - self.ssim(pixels.permute(0, 3, 1, 2), colors.permute(0, 3, 1, 2))
loss = rgbloss * (1.0 - cfg.ssim_lambda) + ssimloss * cfg.ssim_lambda


if self.mlp_spotless:
    self.spotless_module.train()
    spot_loss = self.spotless_loss(
        pred_mask_up.flatten(), upper_mask.flatten(), lower_mask.flatten()
    )
    reg = 0.5 * self.spotless_module.get_regularizer()
    spot_loss = spot_loss + reg
    spot_loss.backward()
# 3.update_running_stats(info)        #----------------------

   cfg = self.cfg

   # normalize grads to [-1, 1] screen space
   if cfg.absgrad:
       grads = info["means2d"].absgrad.clone()
   else:
       grads = info["means2d"].grad.clone()

   grads[..., 0] *= info["width"] / 2.0 * cfg.batch_size
   grads[..., 1] *= info["height"] / 2.0 * cfg.batch_size

   self.running_stats["hist_err"] = (
       0.95 * self.running_stats["hist_err"] + info["err"]
   )
   mid_err = torch.sum(self.running_stats["hist_err"]) * cfg.robust_percentile
   self.running_stats["avg_err"] = torch.linspace(0, 1, cfg.bin_size + 1)[
       torch.where(torch.cumsum(self.running_stats["hist_err"], 0) >= mid_err)[0][
           0
       ]
   ]

   lower_err = torch.sum(self.running_stats["hist_err"]) * cfg.lower_bound
   upper_err = torch.sum(self.running_stats["hist_err"]) * cfg.upper_bound

   self.running_stats["lower_err"] = torch.linspace(0, 1, cfg.bin_size + 1)[
       torch.where(torch.cumsum(self.running_stats["hist_err"], 0) >= lower_err)[
           0
       ][0]
   ]
   self.running_stats["upper_err"] = torch.linspace(0, 1, cfg.bin_size + 1)[
       torch.where(torch.cumsum(self.running_stats["hist_err"], 0) >= upper_err)[
           0
       ][0]
   ]
# 如果iter大于500且为100倍数 step > cfg.refine_start_iter and step % cfg.refine_every == 0
grads = self.running_stats["grad2d"] / self.running_stats[
   "count"].clamp_min(1)
   
	# 4.grow GSs------------------------------------------------------------------
	is_grad_high = grads >= cfg.grow_grad2d                     # "高梯度" GS:2D梯度是否大于等于阈值cfg.grow_grad2d
	is_small = (
	   torch.exp(self.splats["scales"]).max(dim=-1).values
	   <= cfg.grow_scale3d * self.scene_scale 
	)            # 0.01*1.77                                    # "小尺度" GS:3D尺度self.splats["scales"] 是否小于cfg.grow_scale3d * self.scene_scale
	is_dupli = is_grad_high & is_small                          # 同时满足             
	n_dupli = is_dupli.sum().item()
	self.refine_duplicate(is_dupli)                             # 对is_dupli标记的GS进行复制扩大,包括复制参数、优化器状态以及一些统计量
	
	is_split = is_grad_high & ~is_small
	is_split = torch.cat(
	   [
	       is_split,
	       # new GSs added by duplication will not be split
	       torch.zeros(n_dupli, device=device, dtype=torch.bool),
	   ]
	)
	n_split = is_split.sum().item()                              # 计算那些点要split
	self.refine_split(is_split)                                  # 复制了原有GS,并基于原有GS的quad和scale随机扰动生成新的GS
	print(
	   f"Step {step}: {n_dupli} GSs duplicated, {n_split} GSs split. "
	   f"Now having {len(self.splats['means3d'])} GSs."
	)
	
	# 4.prune GSs-------------------------------------------------------------
	is_prune = torch.sigmoid(self.splats["opacities"]) < cfg.prune_opa     # 0.0005
# 5. optimize
for optimizer in self.optimizers:
    optimizer.step()
    optimizer.zero_grad(set_to_none=True)
for optimizer in self.pose_optimizers:
    optimizer.step()
    optimizer.zero_grad(set_to_none=True)
for optimizer in self.app_optimizers:
    optimizer.step()
    optimizer.zero_grad(set_to_none=True)
for optimizer in self.spotless_optimizers:
    optimizer.step()
    optimizer.zero_grad(set_to_none=True)
for scheduler in schedulers:
    scheduler.step()

# 5.Save the mask image
# 保存模型权重 checkpoint
if step in [i - 1 for i in cfg.save_steps] or step == max_steps - 1:      # 在设置的7000或者30k保存一次
    mem = torch.cuda.max_memory_allocated() / 1024**3                     # 占GPU 4.9GB
    stats = {
        "mem": mem,
        "ellapsed_time": time.time() - global_tic,
        "num_GS": len(self.splats["means3d"]),
    }

    with open(f"{self.stats_dir}/train_step{step:04d}.json", "w") as f:
        json.dump(stats, f)
        
    torch.save({
            "step": step,
            "splats": self.splats.state_dict(),
        },  f"{self.ckpt_dir}/ckpt_{step}.pt")

# self.splats.state_dict()共包含5部分:'means3d', 'opacities', 'quats', 'scales', 'sh0', 'shN'
维度分别为(N3)(N1)(N,4)(N,3)(N,1,3(n,15,3)
 
 

  







d \sqrt{d} d 1 8 \frac {1}{8} 81 x ˉ \bar{x} xˉ x ^ \hat{x} x^ x ~ \tilde{x} x~ ϵ \epsilon ϵ
ϕ \phi ϕ


额外知识

1.层次聚类(Agglomerative clustering)

  层次聚类顾名思义就是按照某个层次对样本集进行聚类操作,这里的层次实际上指的就是某种距离定义。
  层次聚类最终的目的是消减类别的数量,所以在行为上类似于树状图由叶节点逐步向根节点靠近的过程,这种行为过程又被称为“自底向上”。
  更通俗的,层次聚类是将初始化的多个类簇看做树节点,每一步迭代,都是将两两相近的类簇合并成一个新的大类簇,如此反复,直至最终只剩一个类簇(根节点)。
  与层次聚类相反的是分裂聚类(divisive clustering),又名 DIANA(Divise Analysis),它的行为过程为“自顶向下”。

在这里插入图片描述

  聚类过程:

1.数据准备;
2.计算数据集中各样本之间的距离(相似度信息);
3.使用 连接函数(linkage function)将样本进行分组形成层次聚类数(分组依据是上一步计算出来的距离信息),距离相近的样本会被链接在一起;
4.决定在什么地方将层次聚类树截断成多个聚类。
  

  


2.Lipschitz constant(普希茨常数)

对抗样本:在分类器中,引起错误预测的不可察觉的扰动输入。

在这里插入图片描述

一、用Lipschitz常量来度量和控制网络的不稳定性
二、Lipschitz常量与网络鲁棒的关系,从而加强型的鲁棒性
三、平衡网络的表达能力(准确率)和稳定性


定义

K 0 K_0 K0 限制模型的输出值,不会有太极端的变化:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
控制模型的平滑

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2034285.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SQL】有趣的电影

目录 题目 分析 代码 题目 表&#xff1a;cinema -------------------------- | Column Name | Type | -------------------------- | id | int | | movie | varchar | | description | varchar | | rating | float | -…

JDBC如何避免SQL注入

JDBC如何避免SQL注入 一 . 什么是SQL注入 SQL注入&#xff08;SQL Injection&#xff09;是一种代码注入技术&#xff0c;它允许攻击者将或“注入”恶意的SQL命令到后端数据库引擎执行。这些恶意的SQL命令可以执行未授权的数据库查询、修改数据、管理数据库服务器上的文件系统…

2024.8.12 作业

TCP服务器端代码实现 #include <myhead.h> #define SER_PORT 6666 #define SER_IP "192.168.254.129" int main(int argc,const char *argv[]) {//1.创建套接字文件int sfd socket(AF_INET,SOCK_STREAM,0);if(sfd-1){perror("socket error");retur…

Echarts-GL和three.js对比,实力在一个档次么?

我们都知道echarts非常好用&#xff0c;简单配置就可以实现各式各样的图表下过&#xff0c;echarts有一个扩展叫echarts-GL&#xff0c;可以实现三维图表效果&#xff0c;那么和three.js相比呢&#xff1f; 一、Echarts-GL的来源 ECharts-GL 是百度开源的一款基于 WebGL 的数据…

PMP和PMI-ACP 考哪个证书好,还是两个都考?

PMP是一个由美国项目管理协会&#xff08;PMI&#xff09;发起的项目管理专业人士或专家资格认证&#xff0c;它评估从业者领导和引导项目团队的能力。PMP在中国早已推广&#xff0c;基于系统项目管理的框架体系&#xff0c;是项目管理领域的基本要求。这个证书知名度很高&…

为什么要加强产供协同管理?可以从哪些方面提高产供协同效率?

随着市场竞争的加剧和客户需求的多变&#xff0c;企业之间的竞争已经转变为供应链之间的竞争。在这一背景下&#xff0c;产供协同管理显得尤为重要。本文将概述加强产供协同管理的必要性&#xff0c;探讨其在提升企业响应速度、优化库存、增强客户满意度和降低成本方面的作用&a…

【数学建模备赛】Ep02:TOPSIS模型(优劣解距离法)

文章目录 一、前言&#x1f680;&#x1f680;&#x1f680;二、TOPSIS法&#xff1a;☀️☀️☀️1. 引入&#xff08;综合类评价问题&#xff09;1.1 分析层次分析法的局限1.2 小例子①给出评分类比权重②构造计算评分的公式③解释④拓展问题&#xff08;增加指标个数&#x…

JVM知识总结(类加载器)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 类加载器 Bootstrap引导类加载器 引导类加载器也被称为启动类加载…

计算机系统基础知识:数据表示及运算

计算机系统基础知识 1. 计算机系统基本组成2. 数据表示及运算2.1 数据表示进位计数值及其转换机器数和码制定点数和浮点数十进制编码ASCII码汉字编码Unicode 2.2 校验码2.3 逻辑代数及运算2.4 机器数的运算机器数的加减运算机器数的乘除运算浮点运算 1. 计算机系统基本组成 计…

opencv-python图像增强二:图像去雾(暗通道去雾)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、简介&#xff1a;二、暗通道去雾方案简述&#xff1a;三、算法实现步骤3.1最小值滤波3.2 引导滤波3.3 计算图像全局光强 四&#xff1a;整体代码实现五&#xf…

iLight混合点光源 激光与LED技术的结合

51camera机器视觉产品资料查询平台的光源种类比较丰富&#xff0c;今天我们一起来看看其合作厂商iCore的明星产品iLight混合点光源&#xff0c;该产品提供了比LED更高的亮度&#xff0c;作为传统LED和氙气灯的替代品&#xff0c;它将激光和LED技术的结合&#xff0c;提供了长达…

创建vscode debug环境

c语言或者其他语言在 字符串指针使用细节很多&#xff0c;你不能编译整个镜像下载在设备里来调试。这些在一个.c文件里需要验证的细节&#xff0c;可以在vscode里创建一个main函数调试 1&#xff0c;环境创建 主要参考下面链接&#xff1a; 如何在VScode中让printf输出中文…

【项目】基于Vue2+Router+Vant 前端面经项目

环境配置 Vue脚手架的创建 在终端中打开输入 vue create 项目包名 -m npm注意⚠️&#xff1a;项目名称不再允许包含大写字母。 选择第三项 3.选择要安装的模块 从上到下的功能模块&#xff1a; Babel - ES&#xff1a;降级处理Router-Vue&#xff1a;路由插件CSS预处理器E…

基于STM32开发的智能家居照明控制系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 初始化代码控制代码应用场景 家庭照明自动化节能照明管理常见问题及解决方案 常见问题解决方案结论 1. 引言 智能家居照明控制系统通过整合各种传感器和控制器&#xff0c;能够实现对家居照…

[全文]买椟还珠和坏事变好事?《分析模式》漫谈19

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 “Analysis Patterns”的第一章有这么一句&#xff1a; Modeling in a programming language also presents the danger of tying the models to that language. The model may use f…

pythonUI自动化008::allure测试报告(安装及应用)

allure报告预览 1 下载jdk&#xff0c;配置jdk Path变量&#xff1a; https://www.cnblogs.com/FBGG/p/15103119.html&#xff08;这里不作阐述&#xff0c;请看该偏文章配置即可&#xff09; 2 下载allure驱动&#xff0c;配置allure Path变量&#xff1a; 下载allure驱动&a…

Springboot 开发之 Quartz 任务调度框架简介

引言 Quartz Scheduler是一个功能丰富的开源作业调度库&#xff0c;它允许开发人员以灵活的方式创建和管理定时任务。以下是对Quartz Scheduler的详细解析&#xff1a; 官网地址&#xff1a;https://www.quartz-scheduler.org/w3cschool 官方文档&#xff1a;https://www.w3c…

离子交换技术:助力电池材料纯度提升的环保解决方案

在新能源技术迅猛发展的今天&#xff0c;电池正极材料的生产和性能成为了科研与工业界的关注焦点。特别是锂离子电池&#xff0c;其广泛运用于电动汽车和各类便携式电子设备中&#xff0c;对电池性能的要求日益严苛。电池正极材料中的球形氢氧化镍直接影响着电池的充放电效率、…

PhotoShop - 初级抠图

1. 调整边缘 1.1 快速选择工具 使用快速选择工具&#xff0c;photoshop会智能的去识别图像中的边缘部分并以此选区 1.2 参数调整 使用快速选择工具选区之后&#xff0c;实际上很多边缘部分是识别不明确的&#xff0c;所以我们需要进一步调节参数使得选区中的边缘识别更加明…

区分恶意加密货币地址:基于西里尔字母伪装的安全隐患分析

引言 在当前的网络环境中&#xff0c;安全威胁变得越来越复杂&#xff0c;特别是在涉及加密货币交易时&#xff0c;攻击者常常利用各种手段来欺骗用户。最近&#xff0c;研究人员发现了一种利用西里尔字母&#xff08;Cyrillic alphabet&#xff09;伪装的恶意手法&#xff0c…