简介:面向希望部署与训练3D Gaussian Splatting的开发者与研究者,这是一套在非官方推荐环境下验证可运行的完整项目源码,重点解决Python 3.10、CUDA 12.3与PyTorch 2.2.1组合下的环境配置、依赖安装、数据下载与格式转换、模型训练及结果查看等环节的实操问题。压缩包共3个文件,包含inscode配置、HTML说明文档和gitignore过滤规则,整体约7KB,结构精简,适合快速对照学习。作者不仅给出了从官方预训练数据到自定义图片训练的完整路径,还结合视频抽帧、数据预处理等进阶技巧说明如何准备非标准数据集,并补充了训练结果查看方式,帮助读者少走弯路。目前已有200人学习下载,对于刚接触3DGS的初学者、需要环境排错参考的工程人员,以及希望将三维重建方法迁移到个人课题的研究者,都具有直接参考价值。 最近上手跑了一轮 3DGS 的部署和训练,整个流程走下来,最大的感受就是:官方文档看着简单,实操全是坑。3DGS(3D Gaussian Splatting)作为三维重建方向这几年最热的技术之一,论文和示例视频都做得非常漂亮,但真正从零开始把源码跑通、把自己的场景数据训出能看的效果,中间隔着大量版本兼容、编译报错、参数调优的问题。这篇把我在 3DGS 部署与训练上的完整过程、验证过的参数、踩过的坑一次性记录下来,适合正在折腾这个项目源码的算法工程师、三维视觉研究者,也适合想把手头设备测一测的 AR/VR 从业者。
从我自己的经验看,部署阶段的核心是 CUDA 工具链、PyTorch 版本、子模块编译这三件事,只要版本矩阵不乱,基本半天能跑通。训练阶段的核心则是场景数据质量、稀疏点云结果、密度控制参数这三个环节,数据拍得不好,后续所有调参都是白费。下面按我自己的实操顺序,把每个环节展开讲清楚。
1. 项目整体认知与部署方案设计
1.1 3DGS到底解决什么问题
在拆部署步骤之前,先把 3DGS 解决的核心问题讲清楚。传统三维重建基本围绕 NeRF 和点云展开,NeRF 的渲染质量高,但训练几小时到几天、渲染一张图也要秒级,根本没法做实时交互。3DGS 的思路是把场景表示成一大团三维高斯分布点,每个点都带自己的位置、协方差、颜色和透明度,通过可微光栅化直接往图像平面上投影,配合自适应的密度控制,既能表达复杂几何,又能用 GPU 并行渲染。实际效果就是训练时间从 NeRF 的天级压缩到分钟到小时级,渲染速度直接跑到实时帧率。
你可以把 3DGS 理解成“会呼吸的点云”:普通点云是静态的、不可微的;3DGS 里每个点是一个有梯度、能学习形状和颜色的软椭球。场景里的镜面反光、细碎结构,靠的是球谐系数(SH)去拟合视角相关的颜色变化,这也是后面训练参数里sh_degree的由来。
1.2 硬件与环境版本选型
官方的训练代码是 CUDA 深度绑定的,别指望纯 CPU 环境能跑。我自己实测,普通的小物体场景在 RTX 3080 10GB 上能训,但显存会比较紧张;场景稍微大一点、图片分辨率再高一点,20GB 显存才算舒适。官方仓库里给出的参考配置是 24GB 以上的专业卡,实际做项目的话,RTX 4090 或者 A5000 往上会比较省心。渲染端倒是不挑,任意带 CUDA 的 N 卡都能跑实时查看器。
环境版本是最容易翻车的地方,先说结论,我在多台机器上验证过比较稳的组合:
| 组件 | 推荐版本 | 备注 |
|---|---|---|
| 操作系统 | Ubuntu 20.04 / 22.04 | Windows 也能跑,编译坑更多 |
| Python | 3.7 ~ 3.10 | 太新或太旧都可能翻车 |
| CUDA | 11.8 或 12.1 | 必须和 PyTorch 匹配 |
| PyTorch | 2.0.1 / 1.13.1 | 对应 CUDA 版本,别用 CPU 版 |
| g++ / MSVC | Linux 需 7.0+,Windows 需 VS2019+ | 编译子模块必需 |
为什么强调 CUDA 和 PyTorch 的匹配?因为官方仓库里的diff-gaussian-rasterization子模块是直接编译扩展的,编译时会调用 PyTorch 自带的 CUDA 扩展机制,如果 PyTorch 内置的 CUDA 版本和系统里不一致,轻则编译警告,重则运行时直接段错误。所以我的建议是:先用nvcc --version确认系统 CUDA,再按对应版本安装 PyTorch,别盲目上最新版。
2. 环境部署完整实操
2.1 克隆源码与创建环境
部署第一步是拉取官方源码。这里有一个非常容易踩的坑:3DGS 仓库用到了子模块,如果直接git clone不带--recursive,后面积木一样的子模块目录是空的,编译时直接报找不到头文件。正确做法如下:
git clone --recursive https://github.com/graphdeco-inria/gaussian-splatting cd gaussian-splatting conda env create --file environment.yml conda activate gaussian_splattingenvironment.yml里会装好基础的 Python 依赖,包括 PyTorch、tqdm、plyfile 等。不过要注意的是,这个文件里默认的 PyTorch 版本可能和你的 CUDA 不匹配,建议在执行之前先手动装 PyTorch,再让environment.yml跳过重装。更保险的流程是:
conda create -n gaussian_splatting python=3.8 -y conda activate gaussian_splatting pip install torch==2.0.1 torchvision==0.15.1 --index-url https://download.pytorch.org/whl/cu118 pip install plyfile tqdm为什么不直接用environment.yml?因为我试过几台机器,那个文件里钉死的版本和你本机驱动之间多少有点偏差,不如手动执行来得干净。装完 PyTorch 后,可以用python -c "import torch; print(torch.__version__, torch.cuda.is_available())"快速验证一下 GPU 是否可见。
2.2 编译子模块与验证
源码里有三个和 CUDA 强相关的子模块:diff-gaussian-rasterization、simple-knn,以及用于实时查看器的SIBR_viewers。训练和渲染只需要前两个,查看器是额外的,不着急装。
编译的命令也很直接:
pip install submodules/diff-gaussian-rasterization pip install submodules/simple-knn这一步在 Linux 上通常顺序执行就能过,但在 Windows 上坑很多:需要先安装 Visual Studio 2019 或 2022,并且要勾选“使用 C++ 的桌面开发”工作负载;系统 PATH 里必须能定位到cl.exe;如果遇到C1083头文件找不到,多半是 Windows SDK 版本没对齐。还有一个小细节,diff-gaussian-rasterization的setup.py在构建时会根据CUDA_HOME环境变量查找 CUDA 工具包,Windows 下如果没有自动识别,手动set CUDA_HOME=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8再重新编译。
编译完成后可以做一个快速验证:在官方仓库的scene模块里随便导入一个高斯模型类,或者直接跳到训练环节用一个小数据集试跑。我自己的经验是,只要diff-gaussian-rasterization能 import 成功,部署阶段就已经完成了一大半。
3. 数据准备与COLMAP稀疏重建
3.1 拍摄数据的采集规范
3DGS 训练效果好不好,60% 的功劳在数据采集。很多朋友拿着手机随便绕一圈拍个几十张,丢进去训练,出来的模型一团糊,然后以为是代码问题,其实大概率是数据不达标。
我总结的拍摄规则有三条:第一,相邻图像的重叠率保证在 60% 到 80% 之间,不要跳拍,宁多勿少;第二,尽量避免反光、透明材质和纯色无纹理区域,玻璃杯、白墙、镜面金属对 COLMAP 的特征匹配极其不友好;第三,固定曝光和焦距,不要边走边变焦,也不要触发自动 HDR,不然同一个点在不同帧里的颜色基准都不一样。
图像数量方面,单个简单物体 50 到 150 张够用,房间级的场景建议 300 到 600 张。分辨率建议控制在 1600 到 2000 像素的短边,太高的分辨率对 COLMAP 特征提取和后续训练显存都是压力,但也不要压得过低,否则重建出的几何会丢细节。
3.2 COLMAP处理与数据格式转换
3DGS 官方不直接吃原始图像,它需要先用 COLMAP 做一次稀疏重建,得到相机位姿和稀疏点云。手动操作 COLMAP 的图形界面也可以,但批量处理强烈建议用命令行。我的常用命令如下:
colmap feature_extractor --database_path database.db --image_path images --ImageReader.single_camera 1 colmap exhaustive_matcher --database_path database.db mkdir sparse colmap mapper --database_path database.db --image_path images --output_path sparseexhaustive_matcher适合图像数量不超过 500 张的场景,数量再大就需要切换成顺序匹配或词汇树匹配,否则匹配速度会让人怀疑人生。mapper跑完之后,会生成sparse/0目录,里面是cameras.bin、images.bin、points3D.bin三个二进制文件。如果sparse/0目录没生成或者只有空文件夹,说明特征匹配或三角化失败了,建议回头检查图像清晰度和重叠率。
拿到稀疏重建结果后,用仓库里的convert.py把数据转成训练需要的格式:
python convert.py -s /path/to/your/dataset这个脚本会从sparse/0里读位姿,生成sparse/0下的cameras.bin等数据的副本,再在images目录里生成去畸变后的图片版本(存在images的副本目录里,原始图像不会被覆盖)。完成后,你还需要确认最终目录结构是否是这样的:
dataset/ ├── images/ ├── sparse/ │ └── 0/ │ ├── cameras.bin │ ├── images.bin │ └── points3D.bin记得把convert.py跑完后的输出目录和原始目录对上,否则训练脚本会提示找不到相机参数文件。
4. 训练实操与关键参数解析
4.1 训练命令与参数清单
数据准备到位后,训练就是一个命令的事:
python train.py -s /path/to/your/dataset -m /path/to/output默认会训练 30000 步迭代,在 RTX 4090 上一个 200 张图的小场景大约需要 20 到 40 分钟。官方代码里比较常用的参数我整理了一下:
| 参数 | 默认值 | 说明 |
|---|---|---|
-i | images | 输入图像子目录名 |
-m | 无 | 输出目录 |
--iterations | 30000 | 总迭代数 |
--sh_degree | 3 | 球谐最大阶数 |
--densify_until_iter | 15000 | 密度控制截止迭代 |
--densify_from_iter | 500 | 开始密度控制 |
--densify_grad_threshold | 0.0002 | 梯度阈值 |
--opacity_reset_interval | 3000 | 透明度重置间隔 |
--lambda_dssim | 0.2 | SSIM 损失权重 |
--start_checkpoint | 无 | 加载已有模型继续训练 |
这些参数里,我实际体验下来最影响最终效果的三个是sh_degree、densify_until_iter和lambda_dssim。sh_degree默认 3,对应 16 个球谐系数,能表达比较复杂的视角相关高光;如果场景里都是漫反射材质,降到 2 反而能减少过拟合和闪烁。densify_until_iter控制高斯点分裂/克隆的截止时间,超过这个步数后点云数量基本冻结,如果发现模型细节不足,可以适当往后延到 20000 甚至 25000。
4.2 密度控制与学习率为什么这么设
3DGS 的密度控制是整个算法的灵魂。简单来说,训练过程中每个高斯点会计算位置梯度,梯度大说明这个点在移动且还没有被优化好,此时有两种处理方式:如果点在场景中处于欠重建状态(大概率是小尺度高斯),就克隆一份;如果点是大尺度且覆盖面太广,就分裂成两个更小的点。从第 500 次迭代开始,每 100 步做一个这样的自适应增密,一直到 15000 步停止。这样点云数量会从初始 COLMAP 稀疏点的几千个,增长到几万甚至几十万,最终精确覆盖场景表面。
学习率方面,官方实现里最值得关注的是位置学习率,它采用了延迟指数衰减策略:训练初期位置学习率是 0.00016,随着迭代从 0.01 倍开始逐步上升,在训练后期指数衰减到 0.0000016。这种设计是为了让模型前期快速找到大致结构,后期微调细节而不会震荡。我一开始不懂,直接改成一个常数学习率,结果 30000 步下来点云分布非常散,渲染画面一直在抖。
有个容易被忽略的点是--lambda_dssim,它让损失函数是 L1 和 SSIM 的加权组合(默认 0.2 的 SSIM 权重)。SSIM 只管局部结构相似,L1 管像素值差异,两者配合能让渲染结果既有结构感又不会色彩偏移。实测下来,如果场景纹理简单,把lambda_dssim降到 0.1 会更快收敛;纹理复杂则维持 0.2 更稳。
4.3 增量训练与衍生方案
训练是一次性的需求吗?做项目时经常要在已训好的模型上继续迭代。官方支持--start_checkpoint加载已有的 checkpoint 做增量训练,例如:
python train.py -s /path/to/your/dataset -m /path/to/output --start_checkpoint /path/to/output/point_cloud/iteration_20000/point_cloud.ply增量训练适合两类场景:一是原始数据增加了新视角图像,需要把新信息并入现有模型;二是第一次训练只跑了 10000 步,想在保留已有结构的基础上继续补细节。要注意的是,加载点云后密度控制会从头开始计数,你可能需要把--densify_from_iter调小一点,否则加载的模型在前几百步里不会新增点。
最近社区里还有很多衍生方案,比如 3DGS-ppisp 把渲染分解成近景和远景两个阶段,解决了场景深度跨越太大时的质量问题;SIGMA 则用硬件混合渲染来做远近视角的过渡。这些都是在官方部署框架基础上做的优化,建议先把基础版跑通,再按需去研究衍生的渲染管线。
5. 常见问题与排查技巧实录
5.1 问题速查表
把这段时间遇到的高频问题整理成了一张速查表,按出现频率排序:
| 问题现象 | 直接原因 | 解决办法 |
|---|---|---|
编译子模块时报错No such file or directory | 子模块未拉取完整 | git submodule update --init --recursive |
训练中CUDA out of memory | 场景点云过多或图像分辨率过高 | 降低--sh_degree、缩小输入图片、用--iterations减少总步数 |
train.py报找不到cameras.bin | 目录结构不对或 COLMAP 没跑完 | 确认sparse/0下三个 bin 文件存在 |
| 渲染结果大片黑色空洞 | 稀疏重建质量差,初始点云缺失 | 重新采集数据,增加重叠率,检查 COLMAP 输出 |
| 画面闪烁、重影 | SH 阶数过高或学习率不合适 | 降低sh_degree,检查位置学习率 |
| 训练始终不收敛,loss 不降 | 图像间曝光差异太大 | 统一曝光,关闭自动白平衡 |
5.2 排查思路与避坑心得
遇到问题先别急着改代码。我的排查顺序是:先确认 COLMAP 重建是否正常,再确认训练日志里 loss 是否持续下降,最后才检查渲染结果。很多人一上来就调训练参数,结果数据源就是脏的,等于白忙。
这里分享几个文档里不会写的经验。第一,COLMAP 重建完一定要打开稀疏点云看一眼,哪怕是用 COLMAP GUI 拉一下视角,如果点云稀稀拉拉或者有大片空洞,后面 3DGS 怎么训都补不回来。第二,训练的初始迭代阶段大概前 1000 步,渲染画面会很粗糙,这是正常的,别在中途停下来判断效果;建议至少等 5000 步再去看中间结果。第三,如果场景里有大量相似纹理(比如草地、砖墙、地毯),COLMAP 很容易匹配错位,可以考虑在feature_extractor时把--SiftExtraction.max_num_features调大,或者用已知相机参数的方式跳过 COLMAP 直接训练。
关于显存紧张的问题,我有一个实测有效的技巧:把训练数据里的images文件夹做一次批量缩放,短边压到 1280 或 1600。这个操作对最终渲染质量影响很小,但显存占用能下降 30% 以上。很多人舍不得压分辨率,其实 3DGS 在 1600px 下已经能出非常细腻的细节,再往上多的主要是存储和算力成本。
5.3 多场景并行训练的经验补充
如果是团队项目,需要同时对多个场景做训练,我建议每个任务单独开一个 conda 环境或者至少用不同的输出目录。官方代码在保存中间结果时不会自动加时间戳,两个任务共用输出目录会互相覆盖。另外,如果条件允许,可以在训练脚本外面套一层nohup或者用 tmux 管理会话,避免 SSH 断连导致训练中断。我试过直接挂后台,三天没关机的训练任务跑了 6 个场景,没有任何异常,稳定性还是可以的。
多场景并行还有一个收益点:可以把 COLMAP 重建好的数据预先转换好,等到要用时直接开训,省掉每次重新跑 SIFT 的时间。特别是图像多的数据集,COLMAP 特征提取这一步往往比训练本身还耗时。
写在最后的实操心得
我个人在实际操作中的体会是,3DGS 的部署难度其实不高,真正的门槛在于“数据采集”和“参数理解”。我第一次跑通官方示例花了整整一天,其中大部分时间消耗在 Windows 编译和 CUDA 版本匹配上,剩下的时间都浪费在不合格的拍摄数据上。后来改成先拿官方提供的tandt数据集验证环境,再拍自己的场景,整个流程就顺畅很多。
最后再分享一个小技巧:训练完成后,渲染视频时不要只盯着 PSNR 指标看,一定要用 SIBR 查看器或者自带的render.py生成一段新视角视频,肉眼观察有没有“气泡感”和“抖动”。数值指标高但在新视角上穿帮的情况,我见过太多次了。如果发现穿帮,优先检查相机位姿和稀疏点云密度,这两个是最基础也是最关键的环节。
本文还有配套的精品资源,点击获取