公司动态
InfiniSplat解析:大基线单目视图合成中的隐式高斯解码实践
3D Gaussian Splatting 在近几年快速成为新视图合成的主流方法之一而 InfiniSplat 这个课题名称把三个关键点放在一起大基线、单目输入、隐式高斯解码。第一次看到这类标题时很容易把它理解成又一个 3DGS 训练技巧但实际上它要解决的是单目输入、大基线以及隐式高斯解码三者叠加后的视图合成问题。真正读懂这个方向需要先弄清楚为什么大基线会让显式高斯优化失效为什么隐式解码能提供额外约束以及从实验到工程落地时可能遇到哪些具体障碍。这篇文章会沿着这条主线把 3D Gaussian Splatting 的核心机制、InfiniSplat 的设计动机、一个可复现的最小实验框架、典型训练问题排查以及评估和工程化建议完整讲清楚。不管你是刚开始接触 3DGS还是已经在做新视角合成实验这里的内容都可以作为从论文标题到代码实现之间的一块踏板。1. 为什么“大基线单目视图合成”是 3DGS 的难点1.1 单目视图合成与多视角重建的差异单目视图合成的输入通常只有一张或少量参考图像目标是生成没有直接观测到的新视角。它的难点在于一张图像本身是三维空间在二维平面的投影深度、遮挡、材质反射和相机运动都会在图像中耦合在一起。单纯靠多视角几何恢复出的点云在视角变化足够大时往往不完整尤其是物体背面和遮挡边缘附近。多视角重建则不同。系统可以从多个角度同时看到同一物体三角化出的点云有足够的几何约束误差也被大量视角平均化。3D Gaussian Splatting 的官方实现默认依赖 COLMAP 提供的稀疏点云作为初始化这个前提在多视角场景下比较自然但在单目输入或大基线场景下就会变得脆弱。单目图像提取出的尺度不完整相机位姿可能也不稳定点云初始化一旦缺少关键几何后面的显式优化就很难收敛到合理的三维结构。这里的实际意义是如果我们要实现类似 InfiniSplat 的隐式高斯解码不能只把问题看成一个渲染器替换而要看到数据流上游的初始化、深度信息、相机位姿和特征提取都会影响最终高斯参数。1.2 大基线带来的遮挡、尺度变化和初始化困难大基线指的是参考视角之间距离足够大导致同一个空间区域在相邻视角中的投影位置、尺度、外观和可见性都发生剧烈变化。这会给新视图合成带来几个直接问题。第一个问题是遮挡变化。在左视角可见的表面在右视角可能完全被前景遮挡网络必须学会推断“这个区域看不见但它后面应该有什么”而不是简单插值。第二个问题是尺度变化。大基线下的透视投影会把近处物体的尺度放大远处物体缩小高斯原语的各向异性协方差如果估计不准渲染时就会出现拉伸或漂浮伪影。第三个问题是初始化困难。稀疏点云算法在视角跨度大的图像对上描述的匹配点很少生成的点云往往带有很多离群点或者覆盖不足。3DGS 如果从这样的点云开始优化过程很容易在错误位置生成高斯原语最终渲染结果出现重影。从设计角度说大基线问题要求模型具备某种“先验推理”能力。显式高斯只保存当前观测到的几何外观参数无法主动补全未观测区域而隐式高斯解码可以从输入特征中预测一组高斯参数即使输入图像没有直接看到全部几何也能借助网络统计先验补全一部分结构。这也是 InfiniSplat 这类名字值得关注的原因。1.3 显式高斯球的表达能力瓶颈3D Gaussian Splatting 用一组带透明度的三维高斯分布来描述场景。每个高斯原语可以表示为位置、协方差矩阵、不透明度和球谐系数。显式表示的优势是渲染快、可控性强但它也有明显的表达能力瓶颈。显式高斯球的数量是有限的训练过程中虽然可以通过密度化增加原语但每个原语仍然需要一个稳定的观察约束。对于大基线场景如果两个视角之间没有足够重叠区域同一高斯原语只能从一侧被观察另一侧完全没有梯度信号。它就会被错误放置或过度依赖单视角退化约束。而隐式解码的意义在于高斯参数不直接作为训练变量存在而是由神经网络从图像特征中解码出来。这样网络可以泛化到相似场景并在未见区域输出一个合理的“猜测”而不是像显式优化那样在无约束区域随意漂移。要注意这里的“隐式”并不等于 NeRF 中的隐式神经场。它更多是指高斯参数的生成方式是隐式的输入不是直接优化的三维坐标而是经过编码器提取的特征表示。这个区别在后面的模型结构设计和损失函数调整中非常关键。2. 3D Gaussian Splatting 的表示、渲染与训练核心2.1 高斯原语与可微光栅化要理解 InfiniSplat 的解码目标必须回到 3DGS 的基本表示。场景由大量三维高斯分布组成每个高斯原语用如下信息描述中心位置用于确定原语在三维空间中的位置。协方差矩阵常用四元数加三轴缩放来表示保证矩阵正定。不透明度用于控制该原语对像素颜色的贡献。球谐系数用于表达视角相关的外观变化。渲染时这些高斯分布被投影到二维图像平面再按从近到远的顺序进行 alpha blending。可微光栅化器会把每个像素收到的颜色与该像素处不同高斯的贡献累加。因为整个过程可微我们可以计算渲染结果与真实图像之间的损失并反向传播到高斯参数。代码层面一个高斯原语的最小数据结构类似于下面的 PyTorch 定义。这个结构只是实验框架的基础具体实现还需要根据光栅化内核的接口做适配import torch import torch.nn as nn class GaussianPrimitive(nn.Module): def __init__(self, num_points100000): super().__init__() self.num_points num_points self._xyz nn.Parameter(torch.zeros(num_points, 3)) self._rotation nn.Parameter(torch.zeros(num_points, 4)) self._scale nn.Parameter(torch.ones(num_points, 3) * 0.1) self._opacity nn.Parameter(torch.zeros(num_points, 1)) self._sh nn.Parameter(torch.zeros(num_points, 3, 16))这里_sh的最后一维 16 对应球谐阶数 3 时的系数数量实际数量要根据使用的球谐阶数调整。重点是这些参数会直接参与渲染渲染器需要对它们保持可微。2.2 从稀疏点云初始化到逐像素优化3DGS 的典型训练流程是先用 COLMAP 得到相机位姿和稀疏点云然后把点云坐标作为高斯原语的中心位置初始化。每个高斯再随机生成不透明度、尺度和旋转参数。训练时不断从训练视角渲染图像计算与真实图像的 L1 损失和 SSIM 损失再反向更新高斯参数。为了让场景细节更丰富训练过程每经过一定迭代次数会执行一次密度化操作。根据梯度和当前透明度把高斯原语分裂成更小的原语或者克隆到梯度变化剧烈的区域。同时还会删除不透明度过低或尺度异常大的原语避免内存和计算浪费。这种策略在多视角重建中非常有效但是对单目大基线输入并不友好。点云初始化本身覆盖不全密度化只能“长出”更多高斯却无法凭空生成正确几何。因此后续大量工作在尝试改变初始化方式例如使用单目深度估计产物初始化或直接用一个神经网络来预测高斯参数。InfiniSplat 属于后者。2.3 训练迭代中的关键参数训练 3DGS 时有很多参数对最终质量影响很大。下面这张表列出了常见实验中需要重点关注的参数数值并非绝对标准落地前要结合自己的数据集和光栅化实现确认。参数常见取值作用设置过大设置过小迭代次数30000 左右控制整体优化时长容易过拟合训练视角细节不足位置学习率0.00016 数量级控制高斯中心移动速度几何漂移、震动收敛缓慢球谐阶数3控制视角相关颜色表达训练变慢、容易引入噪声高光反射表达不足密度化间隔每 100 步左右控制新增高斯原语频率原语数量爆炸细节难以恢复不透明度阈值0.005 左右用于剪枝删除过多有效原语冗余原语多L1 权重0.8 左右和 SSIM 损失配合图像偏锐利但噪声大图像偏平滑这类参数在隐式高斯解码实验中同样需要调整但含义会发生变化。因为高斯参数不再是直接参数而是网络输出所以学习率和密度化策略需要移交给解码器训练流程。3. InfiniSplat 的隐式高斯解码思路3.1 为什么要引入隐式解码回到 InfiniSplat 的标题Implicit Gaussian Decoding。它公开想把高斯参数从“直接优化变量”变成“网络解码结果”。这么做至少有四个动机。第一单目输入天然缺少多视角几何约束。直接优化高斯参数时没有第二个视角提供三角形约束几何很容易退化成一个平面或一片云雾。隐式解码允许网络利用训练集中学过的先验在相似场景上输出更合理的三维结构。第二大基线会带来大量未观测区域。显式高斯只能优化那些至少被一个视角覆盖的区域未覆盖区域没有梯度。隐式解码可以通过特征图插值和邻域信息补全出这部分内容。第三解码器天然具有泛化能力。如果网络是在大量场景上训练的输入一个新场景的图像时它可能在一次前向推理中就输出一个可用的高斯表示不需要从零开始优化。这与直接拟合单个场景的 3DGS 有本质区别。第四隐式解码可以与深度估计、分割、语义等任务共享特征提取器为视图合成引入更多结构化信息。当然隐式解码不是没有代价。参数空间更大解码器需要额外训练数据并且计算量通常高于纯显式优化。这个取舍是理解整个方向的基础。3.2 隐式解码与显式高斯参数的关系所谓隐式解码并不是在三维空间中使用一个连续的神经场而是用神经网络生成一组离散高斯原语的参数。输入可以是单张或少量参考图像通过编码器提取特征再由解码器输出高斯的中心、旋转、缩放、不透明度和球谐系数。这里容易产生一个误解认为“隐式”意味着没有高斯参数。实际上高斯参数仍然存在只是它不直接作为独立的可训练变量而是作为网络输出的函数。因此最终渲染仍然使用 3DGS 的可微光栅化器网络的输出需要被结构调整成光栅化器需要的格式。以伪代码表达一个最小的隐式高斯解码器可以是class ImplicitGaussianDecoder(nn.Module): def __init__(self, feature_dim64, max_points200000): super().__init__() self.feature_dim feature_dim self.max_points max_points self.feature_encoder self._build_encoder() self.head nn.Sequential( nn.Linear(feature_dim, 256), nn.ReLU(), nn.Linear(256, 512), nn.ReLU(), nn.Linear(512, 3 4 3 1 16) ) def _build_encoder(self): # 实际可以用 ResNet、UNet 或 Vision Transformer return nn.Identity() def forward(self, image): features self.feature_encoder(image) B, C, H, W features.shape # 展成一组候选位置并为每个位置解码出高斯参数 tokens features.flatten(2).permute(0, 2, 1) params self.head(tokens) xyz params[..., :3].sigmoid() # 注意需要映射到真实坐标范围 quat params[..., 3:7] scale params[..., 7:10].exp() opacity params[..., 10:11].sigmoid() sh params[..., 11:] return xyz, quat, scale, opacity, sh这段代码只是为了说明数据结构并不是可直接训练的实现。坐标范围映射、球谐系数归一化、候选点数量控制都会在实际工程中显著影响结果。3.3 大基线场景下“先预测后优化”的可能流程在具体实现中InfiniSplat 这类方法通常不会只做一次前向预测就结束而是会采取“粗预测 细优化”或“多阶段预测”的流程。大基线场景下尤其如此。一个较通用的流程是输入参考图像提取特征图。用深度估计网络或几何先验生成粗略三维几何建立初始候选高斯位置。通过隐式解码器输出每个候选位置的高斯参数。用可微光栅化器渲染参考视角和新视角。计算渲染损失、深度一致性损失和正则化损失。反向传播更新整个编码器和解码器必要时在推理阶段再对少量高斯参数做微调。这个流程把“单目深度估计”和“高斯参数预测”结合了起来。相比直接优化显式高斯它的好处是候选点可以来自深度图而不是稀疏点云因此对遮挡边缘和未观测区域有更合理的初始分布。同时微调阶段仍然保留 3DGS 的高质量渲染能力。这类“先预测后优化”的流程是当前很多单目或稀疏视角新视角合成工作的共同范式。InfiniSplat 的名字强调的隐式高斯解码本质上就是把范围较大的显式参数搜索转换成更受控的特征解码问题。4. 一个可复现的最小实验框架4.1 数据准备选择有深度先验或相机位姿的数据集做隐式高斯解码实验数据准备与标准 3DGS 不太一样。标准 3DGS 只需要图像和 COLMAP 位姿而隐式解码训练需要大量场景数据才能让网络学到先验。建议从一个有真实深度或相机位姿的数据集开始。常见选择包括DTU室内多视角数据集有扫描深度遮挡和弱纹理区域较有代表性。Mip-NeRF 360大规模真实场景适合验证大基线下的合成分辨率。自采连续视频序列可以自己控制相机轨迹和基线跨度方便做消融实验。数据准备时要保证训练集和测试集来自不同场景否则网络只会记忆场景无法证明它有跨场景解码能力。这个点非常容易被忽略。如果用同一组场景既训练又测试评价指标会虚高且在大基线测试时会很快暴露泛化问题。4.2 模型结构从特征提取到高斯参数解码实验代码建议拆成三部分特征编码器、高斯参数解码头、可微光栅化器。编码器负责把图像转成高分辨率特征解码头把特征图上的每个位置映射成一个候选高斯原语光栅化器负责把高斯参数转换成渲染图像。特征编码器可以使用 UNet 或 Vision Transformer。对于大基线场景编码器最好有较大的感受野这样解码器可以感知远处结构。高斯解码头建议输出与任务语义解耦的中间表示例如先输出深度、法向量和特征嵌入再基于这些中间表示计算高斯参数。这样便于添加监督信号也便于调试。下面是一个更完整的训练循环伪代码。它不代表官方实现只用于演示结构for step, batch in enumerate(train_loader): ref_image batch[reference_image].cuda() target_image batch[target_image].cuda() ref_depth batch.get(reference_depth) # 可选监督 features encoder(ref_image) xyz, quat, scale, opacity, sh decoder(features) rendered rasterizer( xyzxyz, quatquat, scalescale, opacityopacity, shsh, cameratarget_camera, ) loss_l1 torch.abs(rendered[image] - target_image).mean() loss_ssim 1.0 - ssim(rendered[image], target_image) loss 0.8 * loss_l1 0.2 * loss_ssim if ref_depth is not None: predicted_depth rendered[depth] loss_depth torch.nn.functional.l1_loss(predicted_depth, ref_depth) loss 0.1 * loss_depth optimizer.zero_grad() loss.backward() torch.nn.utils.clip_grad_norm_(decoder.parameters(), 1.0) optimizer.step()伪代码中的rasterizer需要接外部的高斯光栅化实现。实际项目里gaussian-splatting官方仓库使用的diff-gaussian-rasterization需要编译并且对输入的参数格式有严格要求。建议先把渲染器单独跑通再接入解码器避免同时排查多个错误来源。4.3 训练循环与损失函数隐式高斯解码的损失函数通常不只是渲染损失。由于输入是单目图像网络很容易找到退化解把所有高斯都放到相机前方的平面上这样也能勉强拟合参考视角但新视角完全错误。为此需要加入几何相关损失。如果训练数据有深度真值可以直接在深度图上计算 L1 或尺度不变损失。如果没有深度真值可以用单目深度估计网络生成伪深度但要注意噪声。另一个更轻量的做法是加入多视角一致性损失把参考视角以外的训练视角也渲染出来和真实视图计算损失相当于让网络从多个视角监督自己。损失权重需要单独调。渲染损失权重最大几何损失和正则化损失通常只是辅助。这里有一个常见的坑几何损失权重过大会让网络输出过于平滑的结构高频细节丢失权重过小则几何漂移问题无法被抑制。建议参考已有实验设置先固定渲染损失再逐渐增大几何损失观察验证集指标变化。4.4 运行验证与输出指标一个训练实验是否成功不能只看训练损失下降。建议在固定测试视角上保存渲染图并计算 PSNR、SSIM 和 LPIPS。这三个指标分别反映整体像素误差、结构相似性和感知相似性。大基线场景下还需要额外关注新视角是否出现漂浮物。边缘是否出现重影。遮挡区域是否有合理的颜色补全。远处区域是否模糊或变成云雾。建议每隔固定迭代次数保存一次可视化结果并把渲染过程录制出来。直接看测试视角上的渲染图往往比看指标更能发现问题。下面是一个保存输出的简单示例python train.py \ --data_path /data/dtu \ --output_dir ./logs/experiment_001 \ --img_size 512 \ --num_gaussians 200000 \ --batch_size 1 \ --max_iter 30000 \ --save_interval 500这条命令只是示意。实际参数名取决于你自己写的训练脚本。关键是save_interval这类可视化间隔一定要存在否则排查问题时拿不到过程信息。5. 大基线训练中的典型问题与排查链路5.1 显存不足或解码阶段崩溃隐式高斯解码比纯 3DGS 训练更容易出现显存不足。原因有两个一是特征编码器本身占据显存二是解码器可能输出大量高斯原语光栅化器的中间缓冲区会快速膨胀。在 32GB 显存下如果输入分辨率达到 1024 且候选点数量超过几十万训练很可能直接 OOM这类报错在日志里通常表现为CUDA out of memory或更复杂的decoding response body错误。排查时先区分阶段是编码器阶段崩溃还是光栅化阶段崩溃。可以把网络前向和渲染器分开运行观察具体在哪一行报错。如果是光栅化阶段优先降低候选点数量或者把图像分成几个 patch 分别处理。如果是编码器阶段则降低输入分辨率、缩小特征通道数或使用梯度检查点。5.2 几何漂移新视图出现漂浮和重影大基线训练时最常看到的失败模式是参考视角渲染得很好但切换到新视角后画面出现大量漂浮物、半透明重影或物体位置偏移。这时通常是几何没有收敛。可能原因有三种第一候选高斯点的初始分布没有覆盖真实表面网络在错误位置生成了高斯第二深度监督缺失网络只靠渲染损失无法唯一确定三维位置第三学习率过大导致高斯中心震荡过大无法稳定停在表面上。检查方式是把训练过程中生成的深度图保存下来与参考深度或单目深度估计结果对比。如果深度图明显一片平坦或杂乱说明几何约束不足。解决方式包括加入深度损失、减少候选点数量、调整学习率调度或者在解码器输出中增加一个 depth head让网络先学习预测深度再根据深度来放置高斯。5.3 渲染结果模糊或高频细节丢失隐式高斯解码还有一个常见问题输出画面看起来平滑但缺少细节。这通常是高斯尺度初始值太大或者球谐阶数设置太低。高斯原语如果初始尺度很大优化过程中需要通过缩小尺度来恢复细节但在单目大基线场景下网络可能没有足够梯度信号去缩小尺度。处理方式是在解码器输出中显式约束尺度范围例如用sigmoid再加一个较小的 max scale而不是直接exp。同时可以调高球谐阶数但高球谐阶数在有噪声数据上容易产生闪烁伪影。建议先在球谐阶数为 2 的设置下跑通再尝试提高到 3。5.4 排查顺序表下面这张表总结了大概率方向和排查顺序适合每次实验出现异常时快速对照问题现象常见原因检查方式处理建议训练显存不足候选点过多或特征分辨率过高查看日志中 OOM 位置统计光栅化输入点数降低候选点数量、降低分辨率、使用梯度检查点新视角漂浮物几何约束不足或初始化覆盖差保存预测深度图对比单目深度估计加深度损失、调整候选点生成策略画面模糊高斯尺度偏大或球谐阶数过低查看尺度输出分布、比较不同球谐阶数结果限制尺度范围、提高球谐阶数多卡训练偶发断连网络通信或 NCCL 超时检查日志中的 transport error观察多卡进程状态降低通信频率、调大超时时间、检查网卡配置参考视角好、新视角差过拟合训练视角在测试视角上可视化渲染图增加多视角一致性损失、引入更多训练场景这里的多卡训练偶发断连本质上和模型算法无关但在工程落地时非常常见。日志里出现类似stream disconnected before completion的报错时优先检查分布式训练的超时配置和网络稳定性而不是直接改模型结构。6. 从实验到工程化参数选择、评估与发布建议6.1 关键超参数速查表隐式高斯解码实验需要关注的关键超参数比标准 3DGS 多。下面这张表可以作为每次实验的起点同时要结合自己的数据规模做修改。参数建议起点说明输入分辨率512太高容易 OOM太低损失结构细节候选高斯数量100000 到 200000数量增加会提高显存占用和渲染时间特征通道数64 或 128决定解码器的参数规模和表达力深度损失权重0.1 左右需要从 0 开始逐步增加渲染损失权重1.0作为主要监督信号球谐阶数2 到 3从低到高实验观察伪影学习率1e-4 到 3e-4使用 warmup 和余弦调度更稳定迭代次数30000大基线场景可能需要更多迭代这些参数不建议一次全部调优。先固定一组合理默认值然后每次只修改一个变量通过验证集指标判断影响。6.2 评价指标与测试协议隐式高斯解码的评价指标和标准 3DGS 类似主要使用 PSNR、SSIM、LPIPS。在大基线场景下建议把视角按照基线距离分成短期、中期、长期三档分别报告指标。只报平均指标会掩盖大基线性能下降的问题。测试协议还需要注意训练时如果使用了多视角一致性损失那么用于评估的视角可能与训练视角存在重叠。建议提前设定好遮挡关系保证测试视角与训练视角有清晰区分。如果做跨场景泛化测试训练集和测试集必须来自不同的场景集合。6.3 可复用的实验清单下面是一份可以直接用于新实验的检查清单数据集中是否包含相机位姿和深度信息没有深度时是否计划使用单目深度先验训练集和测试集是否来自不同场景高斯光栅化器是否已经单独跑通过最小样例解码器输出的参数范围是否做了合理映射训练循环里是否包含深度损失或一致性损失是否每隔固定迭代次数保存渲染图和深度图测试时是否按基线长短分档统计 PSNR、SSIM 和 LPIPS显存不足时是否已经尝试降低候选点数量或分辨率新视角出现漂浮物时是否已经检查预测深度图生产环境部署时是否考虑过高斯数量裁剪、模型量化和缓存策略这个清单的价值在于每次实验出现奇怪结果时可以先按顺序排除基础配置问题再去质疑算法设计。6.4 扩展方向模型压缩、实时渲染、多模态融合InfiniSplat 这类方法在工程化阶段还有很多可扩展方向。第一是模型压缩。隐式解码器通常是一个较大的 CNN 或 Transformer可以直接部署的成本较高。可以通过蒸馏到轻量网络、减少候选高斯基元数量、低比特量化等手段降低推理开销。第二是实时渲染。3DGS 的优势是光栅化速度快但如果每帧都要重新运行解码器生成高斯参数整体延迟就会大幅上升。实际项目里可以把参考图像的编码结果缓存下来在新视角变化时只更新相机参数避免重复解码。第三是多模态融合。如果把单目深度估计、语义分割和文本特征都接入编码器那么解码器输出的高斯参数就不再只依赖颜色信息。这种设计可以提高遮挡边缘和材质复杂区域的稳定性但需要更多监督信号和更大的数据集。对于想深入这个方向的开发者建议先动手复现一个最小版选择一个带深度真值的数据集把标准 3DGS 的点云初始化替换成深度图采样再接入一个简单的 MLP 解码头。跑通之后再逐步替换编码器、增加多视角一致性损失、扩大基线跨度。这样可以减少拼模型过程中的不确定因素。回到 InfiniSplat 这个名字本身它的核心价值不是只提供一个新场景拟合工具而是把高斯参数的生成方式从显式优化转向隐式解码从而让模型具备处理大基线单目输入的能力。对于做新视图合成、三维重建和自动驾驶数据生成的工程团队来说理解这条技术路径至少可以在面对稀疏视角输入时多一个有效选择。对于刚入门的研究者最好的学习方式不是只读论文而是把 3DGS 的渲染器、解码器的数据流和损失函数逐层拆开在真实数据上观察每个模块的行为然后再回到论文里验证自己的判断。