之前在调研多视角三维重建方案时,我一直被一个场景问题困扰:当相机之间的基线拉得比较大时,NeRF 和传统 3D Gaussian Splatting(3DGS)的重建质量会明显下滑,甚至出现几何塌陷和视角伪影。后来读到 InfiniSplat 这篇工作,发现它把“隐式高斯解码(Implicit Gaussian Decoding)”的思路引入大基线单目视图合成,一下子把问题从“逐场景过拟合优化”拉到了“跨视角泛化回归”的框架里。
这篇文章会围绕 InfiniSplat 展开,从它解决什么问题、方法如何设计、工程落地时需要哪些环境与依赖,到核心代码思路、训练评估流程、常见踩坑点和最佳实践,做一个相对完整的拆解。适合对 3DGS 有一定了解、想做稀疏视角或大基线重建的同学阅读;如果你是新手,建议先补一下 3DGS 的基础渲染流程,再回来看本文会顺畅很多。
读完本文,你会理解 InfiniSplat 的核心设计逻辑,而不是只停留在论文标题层面。项目实践中,你也能知道怎么准备数据、怎么设计实验验证效果,以及遇到大基线场景重建失败时从哪些维度排查。
1. 背景与核心概念
1.1 从 3D Gaussian Splatting 说起
3D Gaussian Splatting 是近几年神经渲染领域非常热门的表示方法。它的核心思路是:用一堆带属性的三维高斯函数来表示场景,每个高斯点包含中心位置、协方差矩阵(决定椭球形状)、颜色、不透明度等参数,然后通过可微的光栅化过程把三维高斯投影到二维图像平面上,用 alpha blending 得到最终渲染图。
相比 NeRF 的隐式体渲染,3DGS 的优势很明显:
- 渲染速度快,能够达到实时级别;
- 显式点云表示,方便编辑和控制;
- 训练速度相比 NeRF 也有明显提升。
但 3DGS 的传统用法是“逐场景优化”。也就是说,给定一个场景的多张图片和对应相机位姿,从随机初始化的高斯点开始,通过不断渲染、计算损失、反向更新参数,最终得到一个属于这个场景的 3DGS 模型。
这种方式在视角密集、基线较小的场景下效果很好,但有几个隐患:
- 如果输入视角跨度大,场景重叠区域小,优化过程容易陷入局部最优;
- 对每个新场景都要重新训练,无法复用;
- 几何信息不足时,高斯点会“漂移”到错误位置,产生大量飞散点。
1.2 大基线单目视图合成难在哪里
“大基线(Large-Baseline)”指的是相机拍摄位置之间的距离比较大。相邻两帧视角之间的重叠区域小,视图变化剧烈。
大基线单目视图合成的挑战主要来自几何不确定性:
- 视角差异越大,同一 3D 点在两张图上的投影位置差异越大,特征匹配越困难;
- 遮挡区域明显增加,很多像素只在部分视角可见;
- 单目输入本身缺少深度真值,几何推理只能依赖多视图一致性;
- 如果只用简单回归网络去预测高斯参数,很难保证预测结果在不同视角下一致。
所以,大基线场景需要更强的几何感知能力,而不只是“图像到图像的翻译”。
1.3 InfiniSplat 的核心思路
InfiniSplat 全称是InfiniSplat: Implicit Gaussian Decoding for Large-Baseline Monocular View Synthesis。
它要解决的问题很直接:给定一组大基线、稀疏视角的单目图像,如何通过前向网络直接生成 3D 高斯参数,从而合成新视角。
这里的核心是“隐式高斯解码”。传统做法可能是让网络直接输出每个高斯的显式参数,例如直接回归一个 N×C 的参数矩阵;而 InfiniSplat 选择先提取多视图特征,再通过一个隐式解码器(通常是 MLP 或基于特征查询的网络)在三维空间中解码出高斯参数。这样做的优势是:
- 参数预测更加连续;
- 对特征表达有更强的容错性;
- 更容易引入多视角几何约束;
- 不需要逐场景优化,具备泛化能力。
结合大基线场景,InfiniSplat 还会重点考虑多视角特征如何聚合,以及如何在不连续视角之间形成稳定的三维特征场。
下面我们从方法层面拆解这些设计。
2. 方法原理拆解
2.1 整体 Pipeline
从工程实现的角度看,InfiniSplat 的完整流程大致可以分为五个模块:
- 多视图图像特征提取;
- 跨视图特征聚合与几何先验构建;
- 三维空间中的高斯参数解码;
- 可微高斯光栅化渲染;
- 损失函数约束与梯度回传。
用一句话概括:输入 N 张图像,输出一组能够渲染出新视角图像的 3D 高斯参数,全程不需要对单个场景做额外优化。
下面逐个模块说明。
2.2 多视图特征提取
特征提取器通常采用卷积神经网络(CNN),例如 ResNet 或 UNet 风格的编码器。每一张输入图像都会被编码成多尺度特征图。
对于大基线场景,单张图像的特征不足以解决遮挡和视角歧义,所以必须把多张图像的特征融合起来。常用的做法包括:
- 在特征图上计算相关性(correlation);
- 构建代价体(cost volume);
- 使用 Transformer 的跨视图注意力机制。
InfiniSplat 强调“隐式解码”,意味着三维空间中的任意查询点都可以通过解码器获得对应的属性。为了让解码器感知全局上下文,跨视图聚合后的特征会作为解码器的条件输入。
2.3 隐式高斯解码器
隐式高斯解码是整篇论文最核心的设计。
它的输入通常包含:
- 三维查询点的坐标(x, y, z);
- 多视图聚合得到的特征向量;
- 可选的视角方向信息。
输出则是该点对应的高斯属性,常见属性包括:
- 中心位置偏移;
- 协方差矩阵(或对应的缩放与旋转四元数);
- 颜色;
- 不透明度。
之所以叫“隐式”,是因为它不直接维护一个显式的高斯列表,而是通过神经网络在查询时解码出参数。这样做的好处是可以通过 MLP 对连续三维空间建模,网络学习到的是一个“场景函数”,而不是离散的点集。
从工程角度理解,你可以把这一步类比成:用一个 MLP 替代了传统 3DGS 训练中的“可学习参数表”。
2.4 可微渲染与损失约束
得到高斯参数后,渲染过程和 3DGS 保持一致:
按深度排序,对每个像素做 alpha blending 合成颜色,得到预测图像。
损失函数方面,常见的组合是:
- L1 颜色损失;
- SSIM 结构相似性损失;
- 必要时加入深度一致性或特征一致性约束,帮助大基线场景稳住几何。
由于整个链路是可微的,梯度可以一路回传到特征提取和解码器,完成端到端训练。
2.5 InfiniSplat 与普通 3DGS 的差别
| 对比项 | 普通 3DGS | InfiniSplat 思路 |
|---|---|---|
| 生成方式 | 逐场景随机初始化,梯度优化参数 | 前向网络预测高斯参数 |
| 是否泛化 | 每个场景单独训练 | 训练后可直接推理新场景 |
| 对视角密度的要求 | 密集视角效果更稳定 | 面向大基线、稀疏视角设计 |
| 几何建模 | 依赖优化的隐式几何约束 | 通过隐式解码器建模三维分布 |
| 输入 | 多视图图像 + 相机位姿 | 多视图图像 + 相机位姿,输出高斯参数 |
这种从“优化”到“回归”的转变,是近两年 generalizable 3DGS 方向的共性趋势。InfiniSplat 的特色在于,把隐式解码结构和大基线场景难题结合起来,从设计上提升了跨视角泛化能力。
3. 环境准备与工程依赖
3.1 运行环境建议
因为 InfiniSplat 属于 3DGS 技术路线,工程实现通常依赖 PyTorch、CUDA 以及高斯光栅化相关的自定义算子。这里给出一套通用环境建议:
- 操作系统:Ubuntu 20.04 或 22.04(Windows 也能跑,但编译自定义算子会更费劲)
- GPU:建议 NVIDIA 显卡,显存 12GB 以上,训练时越大越好
- Python:3.8 或 3.10
- CUDA Toolkit:11.x 或 12.x,取决于 PyTorch 版本
- PyTorch:2.0 以上
- 其他依赖:numpy、opencv-python、tqdm、tensorboard 等
版本需要根据你的项目实际情况调整。如果你使用的不是论文官方代码,而是第三方复现实现,务必先看仓库的 requirements。
3.2 高斯光栅化算子
3DGS 的核心渲染依赖自定义 CUDA 算子,常见的是diff-gaussian-rasterization子模块。安装时一般需要编译:
git clone --recursive <项目地址> cd <项目目录> pip install -r requirements.txt pip install ./submodules/diff-gaussian-rasterization实际使用时,仓库结构不同,路径也会变化。这里只演示思路,具体以你克隆的项目 README 为准。
3.3 相机位姿准备
无论是训练还是推理,都需要相机内参和外参。常见方案:
- 使用 COLMAP 做运动恢复结构(SfM),得到相机参数和稀疏点云;
- 使用已知的仿真数据集(如 Blender、Unity 渲染生成)直接导出位姿文件;
- 使用 AR 设备或 SLAM 系统输出位姿。
大基线场景下,位姿精度非常关键。如果相机位姿误差大,后续特征聚合和高斯解码都会受影响。
3.4 示例项目结构
一个典型的项目结构如下:
InfiniSplat-Project/ ├── configs/ │ └── train.yaml ├── data/ │ ├── train/ │ │ ├── images/ │ │ ├── poses/ │ │ └── intrinsics/ │ └── test/ ├── models/ │ ├── encoder.py │ ├── cost_volume.py │ ├── decoder.py │ └── renderer.py ├── scripts/ │ ├── train.py │ └── eval.py ├── requirements.txt └── README.md这个结构只是参考,实际以官方代码为准。重点是分层清晰:数据、模型、训练、评估分开管理。
4. 核心代码思路(伪代码级讲解)
需要说明的是,目前公开的论文复现版本可能各不相同,这里给出的是“思路级伪代码”,用于帮助你理解模块之间的流转,不能直接复制运行。真正复现时,你需要根据论文内容和具体框架补齐细节。
4.1 特征提取模块
特征提取的目的是从多视图图像中得到统一的特征表达。
import torch import torch.nn as nn class FeatureEncoder(nn.Module): def __init__(self, in_channels=3, out_channels=64): super().__init__() # 实际实现中常用 UNet 风格结构,这里用简单卷积示意 self.conv_block = nn.Sequential( nn.Conv2d(in_channels, 32, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(32, out_channels, kernel_size=3, padding=1), nn.ReLU(inplace=True), ) def forward(self, images): """ images: [B, V, C, H, W] return: [B, V, D, H, W] """ B, V, C, H, W = images.shape images = images.reshape(B * V, C, H, W) features = self.conv_block(images) _, D, Hf, Wf = features.shape features = features.reshape(B, V, D, Hf, Wf) return features这里把多视角图像统一编码,后续就可以在这个特征基础上做跨视图聚合。
4.2 跨视图特征聚合
大基线场景下,单视图特征不够,需要把多视图信息融合到参考视图中。
class CostVolumeAggregation(nn.Module): def __init__(self, feature_dim=64): super().__init__() self.depth_samples = 128 # 深度采样数量 # 后续 3D 卷积正则化代价体 self.cost_regularizer = nn.Sequential( nn.Conv3d(feature_dim, 32, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv3d(32, 1, kernel_size=3, padding=1), ) def forward(self, ref_feature, src_features, ref_pose, src_poses, intrinsics): """ 根据深度假设,将源视图特征 warp 到参考视图,构建代价体。 只是思路示意,实际需要处理相机投影矩阵。 """ B = ref_feature.shape[0] D = self.depth_samples cost_volume = torch.zeros(B, D, ...) # 需要根据实际特征尺寸填写 for d in range(D): depth = ... # 当前深度假设 warped_features = self.warp_features(src_features, src_poses, intrinsics, depth) cost_volume[:, d] = self.compute_correlation(ref_feature, warped_features) cost_volume = self.cost_regularizer(cost_volume) return cost_volume这种“基于深度假设的可微 warp + 代价体”的思路,在 MVS 类方法中很常见。InfiniSplat 的隐式解码框架也依赖类似的几何先验,让三维查询点能够感知多视图一致性。
4.3 隐式高斯解码器
这部分是核心中的核心。输入一个三维查询点,输出高斯属性。
class ImplicitGaussianDecoder(nn.Module): def __init__(self, feature_dim=64, hidden_dim=128): super().__init__() self.mlp = nn.Sequential( nn.Linear(3 + feature_dim, hidden_dim), nn.ReLU(inplace=True), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(inplace=True), nn.Linear(hidden_dim, 9), # 3位置偏移 + 4旋转 + 2缩放 ) self.color_head = nn.Sequential( nn.Linear(hidden_dim, hidden_dim), nn.ReLU(inplace=True), nn.Linear(hidden_dim, 3), nn.Sigmoid(), ) self.opacity_head = nn.Sequential( nn.Linear(hidden_dim, hidden_dim), nn.ReLU(inplace=True), nn.Linear(hidden_dim, 1), nn.Sigmoid(), ) def forward(self, points, features): """ points: [N, 3] 三维查询点 features: [N, feature_dim] 从多视图特征中查询到的聚合特征 return: gaussian_params, color, opacity """ x = torch.cat([points, features], dim=-1) base = self.mlp(x) offset = base[..., :3] quaternion = base[..., 3:7] scale = torch.exp(base[..., 7:9]) color = self.color_head(base.detach()) # 实际实现中不建议 detach,这里仅为示意 opacity = self.opacity_head(base) return offset, quaternion, scale, color, opacity这段代码主要帮助理解“隐式解码”是什么意思:网络不是直接存一组高斯参数,而是根据三维坐标和聚合特征动态预测参数。
4.4 训练流程主循环
训练主循环可以按下面这个思路组织:
# 伪代码,仅展示训练流程 for batch in dataloader: # batch 包含:多视角图像、相机位姿、目标视角图像 images = batch["images"] # [B, V, C, H, W] poses = batch["poses"] # [B, V, 4, 4] intrinsics = batch["intrinsics"] # [B, V, 3, 3] target_image = batch["target_image"] # [B, C, H, W] features = encoder(images) # 多视图特征 cost_volume = aggregation(features, poses, intrinsics) # 几何先验 points = sample_3d_points() # 生成三维查询点 gaussians = decoder(points, cost_volume_features) # 解码高斯参数 rendered_image = rasterizer(gaussians, target_pose, intrinsics) # 渲染 loss = l1_loss(rendered_image, target_image) + ssim_loss(rendered_image, target_image) optimizer.zero_grad() loss.backward() optimizer.step()实际复现时,还需要处理高斯点的数量控制、协方差矩阵的约束、可见性裁剪等工程细节。
5. 训练与评估流程
5.1 数据组织方式
建议把数据按以下方式组织:
data/ ├── train/ │ ├── scene_001/ │ │ ├── images/ │ │ │ ├── 000000.png │ │ │ └── 000001.png │ │ ├── poses/ │ │ │ └── poses.txt │ │ └── intrinsics/ │ │ └── intrinsics.txt每张图像对应一个相机位姿,训练时随机采样一个参考视角和若干源视角,目标视角可以是其中一个源视角,也可以是独立的新视角。
5.2 训练命令示例
假设你正在使用某个包含train.py的项目,训练命令通常长这样:
python train.py \ --config configs/train.yaml \ --data_path data/train \ --log_dir logs/experiment_001 \ --batch_size 1 \ --num_workers 4 \ --max_epochs 100强烈建议训练前先跑通一个 sample 数据,确认数据读取、前向传播、反向传播都没有问题,再启动完整训练。
5.3 评估指标
视图合成任务通常用以下指标评估:
- PSNR:峰值信噪比,越高越好;
- SSIM:结构相似性,越高越好;
- LPIPS:感知相似度,越低越好。
大基线场景下,除了平均指标,还要关注边缘视角的表现。很多方法在中间视角指标好看,一到边缘视角就崩,所以评估时要分视角区间统计。
5.4 与基线方法对比
实验阶段,建议至少和以下方法做对比:
- NeRF 系列:可以体现连续优化类方法的不足;
- 普通 3DGS:可以体现逐场景优化的局限;
- 其他 generalizable 3DGS 方法:比如基于 cost volume 或 transformer 聚合的同类工作。
对比时重点观察:
- 新视角合成质量;
- 几何一致性;
- 推理速度;
- 是否需要测试时优化(test-time optimization)。
从工程角度看,如果某个方法推理前还要在新场景上微调,那它就不是真正的“泛化方法”,在实际应用中会有很多限制。
6. 常见问题与排查思路
6.1 常见问题速查表
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 自定义光栅化算子编译失败 | CUDA 版本与 PyTorch 不匹配 | 检查nvcc --version与torch.version.cuda,统一 CUDA 环境 |
| 显存不足 | 三维查询点过多或特征图分辨率过高 | 降低批量大小,减少深度采样数,使用混合精度训练 |
| 渲染结果出现大量彩色飞点 | 高斯协方差未约束或几何不稳定 | 检查协方差初始化,必要时加入正则化项 |
| 大基线训练不收敛 | 位姿误差大、特征聚合弱 | 优先校正位姿;增加跨视图特征聚合模块的表达能力 |
| 训练集指标很好,测试集很差 | 过拟合场景偏向 | 增加训练场景数量,调整数据增强策略 |
| 新场景推理效果差 | 训练分布与新场景差异大 | 检查数据分布、图像分辨率、光照差异 |
6.2 渲染出现空洞
空洞通常意味着三维空间中缺少高斯点覆盖。可能原因:
- 查询点采样密度不够;
- 几何先验把概率质量分配到了错误位置;
- 遮挡区域的可见性判断不准确。
排查思路:
- 可视化三维点位置,确认分布是否合理;
- 检查遮挡区域是否被采样;
- 增大采样密度,观察空洞是否改善。
6.3 训练 loss 下降但渲染不清晰
这种情况下,通常是几何信息没有有效进入解码器。模型可能只是通过颜色信息“硬背”了训练视角。需要:
- 增加多视图一致性约束;
- 增大特征聚合的视野;
- 加入几何正则项,如深度平滑或左右视角重投影误差。
6.4 大基线视角伪影严重
大基线场景下,视角变化剧烈,容易出现拖影、重影、几何错位。建议按顺序排查:
- 相机位姿是否准确;
- 输入图像是否畸变校正;
- 特征聚合是否覆盖到了所有源视角;
- 解码器是否对三维坐标敏感;
- 是否存在遮挡导致的信息冲突。
实际项目中,位姿问题是最常见的“隐形杀手”。
7. 最佳实践与工程建议
7.1 先跑通最小示例,再上完整方案
不管官方代码还是复现代码,第一件事一定是跑通一个最小示例,比如一个场景、几个视角、几步迭代。不要一开始就追求完整训练。最小示例能最快暴露环境问题、数据格式问题、代码路径问题。
7.2 相机位姿宁可保守,不要将就
大基线方法对位姿非常敏感。如果你的输入是手机拍摄或机器人采集的视频帧,建议先用 COLMAP 做完整的 SfM 流程,检查重投影误差。位姿误差过大的数据,直接过滤掉,不要指望网络“自己学出来”。
7.3 监控三维高斯分布
训练时只盯着 tensorboard 的 PSNR 不够,强烈建议定期输出高斯点云的可视化结果。你可以在训练循环中把高斯中心位置保存成 PLY 文件,用 CloudCompare 或 MeshLab 查看。
如果高斯点云出现大量飞散点、长条状异常椭球,说明几何约束已经失效,需要回调超参数或增加正则项。
7.4 显存优化
大基线场景往往需要处理多张高分辨率图像,显存压力非常大。工程上常用的手段:
- 使用混合精度训练(AMP);
- 降低输入图像分辨率;
- 减少源视角数量,例如从 5 个视角降到 3 个;
- 分块渲染测试图像,再拼接结果;
- 使用梯度检查点(gradient checkpointing)减少中间激活显存。
7.5 数据多样性比模型复杂度更重要
如果你的目标是训练一个泛化的大基线视图合成模型,数据多样性远比堆参数重要。多收集不同场景类型、不同光照条件、不同相机轨迹的数据,比单纯调大模型更有效。
从实验安排上,建议:
- 训练集和测试集场景完全隔离;
- 测试时直接推理,不允许 test-time optimization;
- 每个场景固定随机种子,保证可复现。
7.6 代码与实验管理
建议用配置文件管理所有超参数,不要每次改参数都改代码。一个简单的 YAML 配置文件如下:
model: encoder_out_channels: 64 decoder_hidden_dim: 128 depth_samples: 128 data: image_size: [512, 512] num_source_views: 4 training: batch_size: 1 learning_rate: 0.0001 max_epochs: 100 mixed_precision: true logging: log_dir: "logs/exp_001" save_every: 5这样每次实验只要复制一份配置文件,改两个参数,就能对比不同设置的效果。
7.7 安全与合规提示
如果要在真实场景数据上训练,务必确认数据来源合规,尤其是涉及人脸、车牌、私密空间、商业场所的数据。个人项目尽量使用公开数据集或自己渲染的合成数据,避免隐私和法律风险。涉及他人数据时,遵循最小必要原则,并在发布内容前做脱敏处理。
8. 总结与学习路线
这篇内容从大基线视图合成的问题出发,梳理了 InfiniSplat 的核心设计思路:多视图特征提取、跨视图特征聚合、隐式高斯解码、可微渲染与端到端训练。希望读者能理解,这类方法的价值在于“从逐场景优化转向前向泛化推理”,而隐式解码器的设计则是让网络具备连续三维建模能力的关键。
如果你打算深入研究这个方向,建议按下面路线推进:
- 先彻底搞懂 3D Gaussian Splatting 的基础渲染流程,包括高斯参数的含义、投影公式、alpha blending 原理;
- 再研究多视图几何中的代价体构建和可微 warp,这是提升大基线几何感知的基础;
- 然后阅读近两年 generalizable 3DGS 方向的类似工作,例如基于 cross-attention 或 cost volume 的稀疏视图重建方法,对比它们在不同输入数量、不同基线长度下的表现;
- 最后回到 InfiniSplat 论文原文,逐段对照本文提到的模块,补充公式级细节。
实际做项目时,优先级排序建议是:数据质量大于模型设计,位姿精度大于网络深度,稳定复现大于指标刷点。先跑通一条完整链路,再逐步增加模块和调优,过程中一定要重视可视化——不管是渲染图还是三维高斯点,可视化能帮你快速定位问题,远比盯着 loss 曲线猜问题高效。
如果这篇文章对你有帮助,可以收藏备用。后续我会继续写 3DGS 相关的工程落地笔记,欢迎交流你在复现过程中遇到的问题。