当前位置: 首页 > news >正文

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

在这里插入图片描述

代码: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-3error_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 = 3channel = 1window = 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_lambdaif 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 + regspot_loss.backward()
# 3.update_running_stats(info)        #----------------------cfg = self.cfg# normalize grads to [-1, 1] screen spaceif cfg.absgrad:grads = info["means2d"].absgrad.clone()else:grads = info["means2d"].grad.clone()grads[..., 0] *= info["width"] / 2.0 * cfg.batch_sizegrads[..., 1] *= info["height"] / 2.0 * cfg.batch_sizeself.running_stats["hist_err"] = (0.95 * self.running_stats["hist_err"] + info["err"])mid_err = torch.sum(self.running_stats["hist_err"]) * cfg.robust_percentileself.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_boundupper_err = torch.sum(self.running_stats["hist_err"]) * cfg.upper_boundself.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_grad2dis_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_scaleis_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_smallis_split = torch.cat([is_split,# new GSs added by duplication will not be splittorch.zeros(n_dupli, device=device, dtype=torch.bool),])n_split = is_split.sum().item()                              # 计算那些点要splitself.refine_split(is_split)                                  # 复制了原有GS,并基于原有GS的quad和scale随机扰动生成新的GSprint(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.9GBstats = {"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 限制模型的输出值,不会有太极端的变化:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

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

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

在这里插入图片描述

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

相关文章:

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

代码&#xff1a;https://spotlesssplats.github.io 论文&#xff1a;https://arxiv.org/pdf/2406.20055 来源&#xff1a;DeepMind&#xff0c;多伦多大学&#xff0c;斯坦福大学&#xff0c;西蒙弗雷泽大学 提示&#xff1a;关注B站【方矩实验室】&#xff0c;查看视频讲解…...

28. 找出字符串中第一个匹配项的下标【 力扣(LeetCode) 】

一、题目描述 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 二、测试用例 示例 1&#xff1a; 输…...

邀请函 I 松下信息和望繁信科技邀您参加「数智时代下大数据应用的“道”与“术”」闭门会议

在数字化浪潮席卷全球的今天&#xff0c;大数据与智能化的结合成为企业成功的关键。为了深入探讨这一重要议题&#xff0c;松下信息系统&#xff08;上海&#xff09;有限公司&#xff08;简称“松下信息”&#xff09;与上海望繁信科技有限公司&#xff08;简称“望繁信科技”…...

Node.js中的fs.watchFile与fs.unwatchFile:文件监控与取消监控

在Node.js中&#xff0c;对文件系统的操作是非常常见的需求。有时&#xff0c;我们需要对某个文件的变化进行实时监控&#xff0c;并在文件内容或元数据发生变化时执行相应的操作。Node.js的fs模块提供了watchFile和unwatchFile两个方法&#xff0c;用于实现文件的监控和取消监…...

Hadoop大集群配置文档-粗略版-3万字长文 (包括hive,zookeeper,hbase,flume等中间件和mysql等)

先填一下上次许诺的坑&#xff1a; &#xff08;许诺的那篇文章链接如下&#xff09; 如何用sql在1分钟从1T数据中精准定位查询&#xff1f;Hive离线数仓 Spark分析-CSDN博客文章浏览阅读1.2k次&#xff0c;点赞38次&#xff0c;收藏14次。在大数据-Hadoop体系中 &#xff0c;…...

原生html+js播放flv直播视频流【vue等皆可用】

一、前言 最近着手了一个新需求&#xff1a;将某记录仪的实时视频在页面展现。 实现步骤&#xff1a; 通过WebRtc将直播视频转码为flv/rtsp格式流&#xff1b;通过Vlc或代码中的视频播放器播放视频。 常见播放flv直播视频流软件如&#xff1a;VLC、PotPlayer等&#xff0c;…...

初学java第一天:写一下熟悉的猜数字小游戏

初学java&#xff0c;不知道bug多不多&#xff0c;为了整理凌乱的思绪&#xff0c;写一个实践一下&#xff0c;跟C好像啊 简单来说&#xff0c;初学java确实有一点难度&#xff0c;但是大部分知识和思想和C语言和python相似&#xff0c;所以写起来还行&#xff0c;注意是对一些…...

【C++】如何判断类型

typeid的缺点 typeid对多态的情况不支持 #include <iostream>class Parent { public:Parent() {} private:int a 0; };class Child :public Parent { public :Child() {} private:int b 0; };int main() {Parent* obj1 new Child();Parent* pobj1 obj1;std::cout &…...

让一切发生皆有利于我,在人生的长河中,我们常常面临诸多的不确定性和变化

让一切发生皆有利于我,在人生的长河中,我们常常面临诸多的不确定性和变化。如何在这纷繁复杂的世界中保持内心的坚定,以积极的姿态应对生活的起伏,是我们一生都需要探索的课题。“一切发生皆有利于我”,这是一种心态;“让一切发生皆有利于我”,这是一种策略。这一深刻的…...

腾讯云AI代码助手:智能AI代码助手 ,新一代的高效代码开发辅助工具

前言 近些年是一个科技大爆发的时代&#xff0c;自从大模型发布以来越来越多的科技产品出现。例如去年的智能编码助手自出现以来&#xff0c;各大老牌大厂腾讯&#xff0c;百度 阿里也都紧随其后&#xff0c;智能编码助手的出现可以说大大的节省了我们写一些冗余代码的时间成本…...

C#:索引器 集合初始化器 事件访问器 枚举器 迭代器

1.索引器 就是有参属性 ,这个属性的get访问器接受 一个或多个参数 ,set访问器接受 两个或多个参数 <<via c#>>第10.2节 索引器可以被是被智能的数组 ,属性封装了类中的一个值,而索引器 封装了一组值,使用索引器时,语法和使用数组一样 <<c#从入门到精…...

css伪类选择器、盒子模型等

一、伪类选择器 1.1查找单个元素 根据元素的结构关系查找元素 查找第一个元素&#xff1a;标签名:first-child 查找最后一个元素&#xff1a;标签名&#xff1a;last-child 查找第n个元素&#xff1a;标签名&#xff1a;nth-child(n) 1.2查找多个元素 :nth-child(公式&#xf…...

opencv-python图像增强三:图像清晰度增强

文章目录 一、简介&#xff1a;二、图像清晰度增强方案&#xff1a;三、算法实现步骤3.1高反差保留实现3.2. usm锐化3.3 Overlay叠加 四&#xff1a;整体代码实现五&#xff1a;效果 一、简介&#xff1a; 你是否有过这样的烦恼&#xff0c;拍出来的照片总是不够清晰&#xff…...

第130天:内网安全-横向移动PTH哈希PTT 票据PTK密匙Kerberos密码喷射

环境搭建 这里这个环境继续上一篇文章搭建的环境 案例一&#xff1a;域横向移动-PTH-Mimikatz&NTLM 什么是pth&#xff1f; PTH Pass The Hash &#xff0c;通过密码散列值 ( 通常是 NTLM Hash) 来进行攻击。在域环境中&#xff0c;用户登录计算机时使用的域账号&…...

SB3045LFCT-ASEMI无人机专用SB3045LFCT

编辑&#xff1a;ll SB3045LFCT-ASEMI无人机专用SB3045LFCT 型号&#xff1a;SB3045LFCT 品牌&#xff1a;ASEMI 封装&#xff1a;TO-220F 批号&#xff1a;最新 最大平均正向电流&#xff08;IF&#xff09;&#xff1a;30A 最大循环峰值反向电压&#xff08;VRRM&…...

RPA财务机器人是什么,RPA的具体应用场景有哪些?| 实在RPA研究

数字化转型关键期&#xff0c;越来越多的人工智能及超自动化技术在企业财务工作中得以普及应用&#xff0c;以提升财务工作效率&#xff0c;促进财务部门实现 RPA财务机器人是什么&#xff1f; RPA&#xff0c;即机器人流程自动化&#xff08;Robotic Process Automation&#…...

滑动窗口 | Java | (hot100) 力扣 3

力扣 3.无重复字符的最长子串 暴力法&#xff1a;双层for循环&#xff0c;i-j的字符查重 滑动窗口&#xff1a;因为这题被分在这个类别里&#xff0c;那么已知要用滑动窗口&#xff0c;思路应该是什么。 反正我想不出来…… 看了别人的题解写出来的出错点&#xff1a;特别容易…...

【产品经理】竞品分析怎么理解?拆解一下

什么叫竞品&#xff1f;&#xff08;研究的对象&#xff09; 竞品看你怎么理解&#xff0c;有时候不一定是你的竞争对手&#xff0c;有可能是其他行业也做了这个功能&#xff0c;那你也可以学习&#xff0c;有类似的功能或者策略都可以学习&#xff0c;不过这个可能在管理学上…...

合规性导航:处理爬虫数据用于机器学习的最佳实践

在数据驱动的时代&#xff0c;机器学习已成为企业和研究者的重要工具。然而&#xff0c;使用爬虫技术抓取的数据进行机器学习时&#xff0c;合规性问题不容忽视。本文将详细探讨在使用爬虫抓取的数据进行机器学习时可能遇到的合规性问题&#xff0c;并提供相应的最佳实践。 一…...

spring中使用到的设计模式有哪些

Spring 框架是一个高度模块化和灵活的框架&#xff0c;广泛使用了各种设计模式来实现其核心功能和架构。这些设计模式帮助 Spring 提供了高可配置性、可扩展性和可维护性。以下是 Spring 框架中使用到的一些关键设计模式&#xff1a;...

splitcontainer控件设置固定大小

要设置SplitContainer控件以固定的大小&#xff0c;可以通过设置SplitContainer的FixedPanel属性来实现。您还需要设置IsSplitterFixed属性为true来锁定分割条的大小&#xff0c;并且通过设置SplitterWidth或SplitterLength属性来调整分割条的宽度或高度。 以下是一个示例代码…...

最近在写的支付模块

最近再写支付模块就到处借鉴 旨在回顾一下。 1.确认订单功能 使用场景是&#xff1a;用户在选择好购物车后&#xff0c;或者是直接选择商品后&#xff08;选择商品封装为购物车&#xff09; 这样做是根据尚硅谷来学习的 目前需要这些属性&#xff0c;原因是在确认订单页面后…...

解决域名加别名后再代理或者映射到fastadmin项目

如果遇到微应用不想再添加或者不方便添加单独的二级域名时&#xff0c;就需要用到代理或者映射来进入到我们的微应用项目中。 可以修改route.php路由文件的下面这个参数 __alias__ > [别名 > 模块/控制器] 如图 然后再修改config.php文件里面的view_replace_str参数…...

Armv9.5架构新增的关键扩展--精简版

Armv9.5架构扩展是对Armv9.4的扩展。它增加了强制性和可选的架构特性。有些特性必须一起实现。实现是符合Armv9.5规范,需要满足以下条件: 符合/兼容Armv9.4规范包含所有Armv9.5架构的强制性特性。符合Armv9.5规范的实现还可以包括: Armv9.5的可选特性以下是arm9.5架构中关键…...

STM32 GPIO 模块

B站视频地址&#xff1a;芯片内部GPIO模块细节 引脚 将 STM32 芯片&#xff0c;类比为【大脑】 而旁边的引脚&#xff0c;类比为【神经】 通过引脚&#xff0c;使得&#xff0c;STM32&#xff0c;可以和外部世界&#xff0c;进行交流 比如&#xff0c;当我们和别人说话时&am…...

网络剪枝——network-slimming 项目复现

目录 文章目录 目录网络剪枝——network-slimming 项目复现clone 存储库Baselinevgg训练结果 resnet训练结果 densenet训练结果 Sparsityvgg训练结果 resnet训练结果 densenet训练结果 Prunevgg命令结果 resnet命令结果 densenet命令结果 Fine-tunevgg训练结果 resnet训练结果 …...

Spring 懒加载的实际应用

引言 在 Spring 框架中&#xff0c;懒加载机制允许你在应用程序运行时延迟加载 Bean。这意味着 Bean 只会在第一次被请求时才实例化&#xff0c;而不是在应用程序启动时就立即创建。这种机制可以提高应用程序的启动速度&#xff0c;并节省内存资源。 Spring 的懒加载机制 懒…...

PyQT 串口改动每次点开时更新串口信息

class MainWindow(QWidget, Ui_Form):def __init__(self):super().__init__(parentNone)self.setupUi(self)self.comboBox.installEventFilter(self) # 加载事件过滤器self.comboBox.addItems(get_ports())def eventFilter(self, obj, event): # 定义事件过滤器if isinstance(o…...

三级_网络技术_19_路由器的配置及使用

1.在Cisco路由器上配置DHCP服务&#xff0c;使得客户端可以分配到的地址范围是222.28.71.2-222.28.71.200地址租用时间是2小时30分钟&#xff0c;不记录地址冲突日志默认路由是222.28.71.1&#xff0c;分配的dns服务器地址是222.28126.27和222.28.126.26。以下配置完全正确的是…...

【STM32 Blue Pill编程】-STM32CubeIDE开发环境搭建与点亮LED

开发环境搭建与点亮LED 文章目录 开发环境搭建与点亮LED1、STM32F103C8T6及STM32 Blue Pill 介绍2、下载并安装STM32CubeIDE3、编程并点亮LED3.1 在Stm32CubeIDE中编写第一个STM32程序3.1.1 创建项目3.1.2 设备配置3.1.2.1 系统时钟配置3.1.2.2 系统调试配置3.1.2.3 GPIO配置3.…...