资讯详情

3DGS从零实战:CUDA环境搭建、COLMAP预处理与训练踩坑指南

📅 2026/10/22 14:26:59 | 华诺云谱 👁 阅读
3DGS从零实战:CUDA环境搭建、COLMAP预处理与训练踩坑指南
在图形学和三维重建这个圈子里2023年底到2024年最绕不开的一个名字就是3DGS3D Gaussian Splatting。它用一群带颜色的三维高斯球代替传统网格配合快速光栅化把训练速度和渲染画质同时做到了一个离谱的高度。这个系列前面几篇已经把数学原理、差分渲染、球谐函数这些底子打得差不多了这篇作为04篇我直接讲实操怎么从零把环境搭起来怎么把手里的照片变成一组能实时浏览的3DGS模型以及训练过程中那些文档里不会写的坑。这篇内容适合两类人一类是刚看完论文、想跑通官方代码但被CUDA和依赖搞到怀疑人生的新手另一类是已经在用NeRF、想对比一下3DGS工作效率的老玩家。如果你是后者可以直接跳到第三、四章看参数和踩坑部分。1. 内容整体设计与思路拆解1.1 为什么3DGS的代码实践比NeRF更“亲民”相比NeRF那种隐式表达3DGS最大的优势在于它把整个场景表达为显式的高斯集合所以训练过程非常直观。你打开TensorBoard能看到点云从稀疏到稠密、从无颜色到色彩饱满的变化过程而不是对着一个抽象的体密度场发呆。代码层面官方实现图形学项目名简称INRIA版结构很清晰主入口就一个train.py核心逻辑在scene、gaussian_model、renderer几个模块里。没有复杂的网络结构堆叠也没有让人头痛的调度器配置。你只需要搞定环境训练本身几乎就是一行命令的事。我在搭建过程中最大的体会是3DGS的环境配置难点不在PyTorch而在那三个C/CUDA扩展——diff-gaussian-rasterization、simple-knn、fused-ssim。它们需要和你本机的CUDA、PyTorch版本严格匹配否则编译期就会给你脸色看。这一点我会在第二章专门展开。1.2 整套代码流程的关键节点把官方仓库跑通本质上就是走通四个环节环境准备、数据预处理、模型训练、结果导出。数据预处理部分官方默认调用COLMAP做SfM这一步很多新手觉得“多余”实际上它决定了后续训练能不能收敛、模型质量能到多高。我建议一开始不要直接上自己的数据集先用官方提供的场景数据比如那个著名的自行车场景跑通全流程确认环境没问题、代码能训练出结果再换成自己的照片。否则一旦出问题你很难判断是代码bug、环境问题还是数据问题。整套流程的关键节点我画个表给你方便对照节点作用关键产出常见问题环境配置编译CUDA扩展可导入的模块CUDA版本不匹配、编译超时SfM预处理计算相机位姿和稀疏点云sparse/目录COLMAP找不到图像、特征匹配失败高斯初始化用稀疏点云初始化高斯球3D高斯属性点云太稀疏导致初始化失败训练优化迭代更新高斯属性checkpoint和点云显存不足、loss不下降、飞点结果导出生成可交互模型ply文件、渲染视频相机路径设置错误下面我按这个顺序一步步带你把代码跑起来。2. 环境配置全记录——从显卡驱动到CUDA扩展编译2.1 硬件和驱动的基本盘3DGS不像大语言模型那样吃显存但也不是随便一台机器就能跑的。我的主力机是RTX 409024GB显存训练官方默认的自行车场景大约9分钟左右出到7K迭代显存占用在8GB左右。如果你用的是12GB显存的卡也完全够用只是需要把图像下采样比例稍微调一下。显存不够的替代方案是降低输入图像分辨率。比如把图像缩放参数从默认的1改成2或4显存占用会成倍下降但细节还原度也会肉眼可见地变差。我的建议是8GB显存跑720p左右输入12GB跑1080p24GB直接原图。这个经验值适用于大多数中小场景。驱动方面注意你的NVIDIA驱动版本必须支持你打算安装的CUDA版本。最简单的方法是用nvidia-smi看一下驱动支持的最高CUDA版本号然后往下兼容安装即可。2.2 创建干净的conda环境和CUDA选型我推荐用conda管理环境别直接在系统Python里折腾。创建命令如下conda create -n 3dgs python3.8 -y conda activate 3dgsPython版本建议选3.8或3.9实测3.10也能跑但某些C扩展的编译脚本对3.10的支持略有瑕疵没必要冒这个险。接下来安装PyTorch。这一步是整个环境配置的基石千万要看清楚自己的CUDA版本。我机器上装的是CUDA 11.8对应的PyTorch安装命令是pip install torch2.0.0cu118 torchvision0.15.0cu118 --extra-index-url https://download.pytorch.org/whl/cu118这里有一个非常关键的对应关系我直接给你结论PyTorch的CUDA版本和你要编译的CUDA扩展的版本尽量保持一致。比如你用cu118的PyTorch去编译依赖CUDA 12构建的扩展轻则报错重则运行时出诡异的内存错误。注意如果你拿到的是新版本GPU比如Ada架构也不要盲目装CUDA 12先看你的PyTorch支持什么。很多时候CUDA 11.8反而更稳因为官方验证过。2.3 克隆仓库与子模块官方代码仓库里用了submodule来管理三个关键扩展。克隆时必须加--recursive参数否则扩展目录是空的git clone --recursive https://github.com/graphdeco-inria/gaussian-splatting.git cd gaussian-splatting如果之前忘了加--recursive进目录后手动补一下git submodule update --init --recursive然后安装Python侧的依赖pip install -r requirements.txtrequirements里主要是tensorboard、plyfile、tqdm这类常规库不会有太大问题。真正的大头在后面的扩展编译。2.4 编译diff-gaussian-rasterization等三个扩展这是整个环境配置过程里最大的一道坎。官方在README里建议直接用pip install但我实测下来直接pip install扩展目录经常因为环境和编译参数问题失败。我最终能稳定跑通的方法是分别编译三个子模块# 编译diff-gaussian-rasterization pip install submodules/diff-gaussian-rasterization # 编译simple-knn pip install submodules/simple-knn # 编译fused-ssim pip install submodules/fused-ssim编译过程会调用nvcc所以你需要确保nvcc在PATH里。验证方式nvcc --version如果提示找不到nvcc说明CUDA Toolkit没装或者没有写入环境变量。我踩过这个坑系统里明明有CUDAPython侧也能用但因为没把/usr/local/cuda/bin加到PATH导致编译时找不到nvcc。编译过程通常需要几分钟到十几分钟。如果编译中途报错绝大部分情况是CUDA和PyTorch版本不匹配或者GCC版本太新GCC 12以上容易出兼容问题。我的建议是装GCC 9或10用conda装最省事conda install gcc9 gxx9 -c conda-forge编译成功的标志是import xxxx不报错。在环境里跑一下python -c import diff_gaussian_rasterization; print(ok)如果这行输出ok整个环境配置基本就大功告成了。2.5 一个更省事的方案Docker镜像如果你不想在宿主机上折腾依赖官方提供了Dockerfile。这个方案对那些实验机器多、环境容易搞脏的人特别友好。我自己在服务器上就是这样用的一条命令拉起环境不会影响别的项目。docker build -t 3dgs . docker run -it --gpus all -v /your/data:/data 3dgs bash容器里默认环境已经配好直接train.py就行。我遇到的小问题是容器内访问宿主机数据要处理好挂载路径尤其注意别把带中文的路径挂进去COLMAP对中文路径的支持非常差。3. 数据准备与预处理——这一步决定你模型的天花板3.1 COLMAP的安装与调用3DGS官方代码默认使用COLMAP做SfM目的是从一堆照片里恢复相机内外参和稀疏点云。注意COLMAP不是Python库而是一个独立的C程序。你需要单独安装它并让命令行里能直接敲colmap这个命令。Ubuntu下的安装方式sudo apt install colmap如果你用Windows就直接去COLMAP官网下载预编译的exe然后把可执行文件所在目录加入PATH。Windows下实测COLMAP的调用偶尔会有路径解析问题建议所有路径全英文无空格。3DGS仓库里有个convert.py脚本它会自动调用COLMAP处理图像python convert.py -s data/bicycle这个脚本做的事情很简单对data/bicycle/images下的所有图片做特征提取、匹配、稀疏重建最后把结果写到data/bicycle/sparse目录。训练时代码从sparse目录读取相机参数和初始点云。如果你在Windows下遇到convert.py调用COLMAP失败多数情况是spawn了子进程但找不到colmap命令。我的处理方式是在convert.py里把COLMAP路径写死为绝对路径COLMAP_PATH C:/path/to/colmap.exe3.2 数据集的目录结构说明官方推荐的数据集结构是这样的data/ └── bicycle/ ├── images/ │ ├── 00001.jpg │ ├── 00002.jpg │ └── ... ├── sparse/ │ ├── 0/ │ │ ├── cameras.bin │ │ ├── images.bin │ │ └── points3D.bin └── ...images目录存放所有输入照片sparse目录是COLMAP的输出。注意训练时3DGS只读取sparse目录里的相机参数和点云图像本身是根据sparse里的对应关系从images目录读取的。两者缺一不可。如果你用的是别人的数据集比如Mip-NeRF 360提供的数据通常会带colmap输出目录那就不需要再跑convert.py了。这时候你需要手动建立目录结构把官方expect的sparse内容放进去。3.3 用自己的相机照片建数据集的实操建议这一块是很多人第一次上手最容易翻车的地方。我来说说照片采集的要点拍摄数量我建议一个中小型场景拍150~300张照片。太少比如50张会导致稀疏重建不稳定相机位姿算不准太多比如超过1000张会让COLMAP跑上几个小时训练也慢。官方场景一般在200张左右。重叠率相邻照片之间至少要有60%以上的视觉重叠。别像拍风景一样每隔几米拍一张那会让特征匹配断掉。正确的做法是围绕目标物体或区域环扫一圈每隔一小段距离拍一张角度变化平缓。光照条件尽量在均匀光照下拍摄避免强阴影和过曝。3DGS对高光很敏感玻璃瓶、金属表面这种高反射物体会在训练后出现一层“薄雾”实际上是球谐函数无法表达镜面反射的硬伤。运动模糊手持拍摄时注意快门速度。模糊的照片会导致COLMAP特征点定位不准进而影响整个相机位姿估计。我有个朋友用手机拍了一组很多照片在走动时按下快门结果COLMAP只有一半图片匹配上了最后效果惨不忍睹。3.4 图像预处理分辨率与格式的取舍输入图像的尺寸直接影响显存和训练速度。一个取巧的做法是先用低分辨率跑通流程确认数据没问题后再用全分辨率做最终训练。我在数据准备阶段会先跑一个快速测试把图片缩小到800pxCOLMAP跑一遍确认能出模型再放大。图片格式方面官方支持.jpg和.png。JPEG体积小但压缩有损PNG无损但文件大。我的经验是日常拍摄的JPG完全够用但如果你做的是高精度的物体建模比如文物数字化建议用PNG或者高质量JPEG压缩质量95以上。注意图像命名建议统一为数字递增格式00001.jpg00002.jpg...。虽然COLMAP本身不要求但3DGS在加载图片时是按文件名排序的如果混了中文名或者特殊字符可能在训练时报错找不到图片。4. 训练实操——从命令行到参数调优4.1 train.py的使用与核心参数环境配好、数据也处理完了训练这一步理论上是很轻松的。核心命令就一行python train.py -s data/bicycle -m output/bicycle-s指定数据集目录-m指定输出目录。训练默认跑30K迭代如果是官方bicycle数据集在4090上大约需要30到40分钟。跑完后输出目录里会得到point_cloud/iteration_30000这个子目录里面就是最终的3DGS模型一个.ply文件。如果你想快速验证流程可以把迭代数调小python train.py -s data/bicycle -m output/bicycle-test --iterations 7000官方其实还提供了--test_iterations参数可以在指定的迭代步数上做评估输出。比如python train.py -s data/bicycle -m output/bicycle --test_iterations 7000 30000 --save_iterations 7000 30000这样会在7000步和30000步都保存一次模型方便你对比不同迭代量下的效果差异。4.2 训练过程中发生了什么——读懂内部机制如果你打开TensorBoard看训练过程会发现3DGS的训练分成几个阶段。前几百步主要是对初始高斯球进行位置和颜色调整粗糙地把场景大的结构撑起来。之后每隔一定步数会做一次densify稠密化把细节区域的高斯球密度提上去同时修剪掉那些透明度太低或位置太远的“飞点”。densification是在固定迭代步数触发的默认从第500步开始到第15000步结束。这期间模型会周期性地新增高斯球数量可能从几万个涨到几十万甚至上百万。如果你的场景很复杂高斯球数量会随着训练持续上涨这时显存占用会逐渐增加。我在实际训练中发现的一个经验是球谐阶数sh_degree默认3不要一上来就调低。虽然SH阶数越高颜色表达越丰富但训练前期如果只让低阶球谐优化会出现色彩过渡不自然的问题。官方默认设置已经很合理新手不要乱动这个参数。4.3 训练输出与模型文件说明训练结束后输出目录里主要包含output/bicycle/ ├── point_cloud/ │ └── iteration_30000/ │ ├── point_cloud.ply │ └── ... ├── test/ │ └── ... ├── train/ │ └── ... ├── cameras.json └── ...point_cloud.ply就是最终的3DGS模型文件可以用官方提供的SIBR viewer打开也可以配合一些Web端查看器直接拖拽浏览。test目录里是模型在测试视角上的渲染结果和GT对比train目录里则是训练集上的。train的PSNR通常会略高于test这很正常说明模型在训练集上过拟合了但如果两者差距过大比如超过3dB就要考虑是不是训练太久或者场景本身过小。cameras.json保存的是评估用相机的参数。如果你想自己渲染一段绕场景旋转的视频可以修改这个文件里的相机轨迹然后用render.py重新渲染。这里有个小技巧绕场景旋转的相机半径不要设太大否则相机跑到模型外太空渲染出来一片黑。4.4 用render.py导出视频训练完模型后你可能想生成一段展示视频或者导出某个自定义视角的静态图。官方提供了render.pypython render.py -m output/bicycle --skip_train这会用默认的相机路径渲染视频帧集分布在test目录下。如果你想生成真正的.mp4视频需要自己调用ffmpeg把帧序列合成。我在实际操作中会直接这么干ffmpeg -framerate 30 -i output/bicycle/test/ours_30000/renders/%05d.png -c:v libx264 -crf 18 output/bicycle/result.mp4这里crf值18是视觉无损的画质一般分享够用了。如果你想更小的文件可以调到23肉眼基本看不出区别。5. 常见问题与排查技巧实录5.1 编译扩展时提示CUDA版本不匹配这个坑几乎人人都会遇到。集齐了三类症状undefined symbol、gcc: error: unrecognized command-line option、nvcc fatal。原因就是编译扩展用的CUDA和PyTorch运行时用的CUDA版本不一致。我的排查思路是这样的先查PyTorch绑定的是什么CUDApython -c import torch; print(torch.version.cuda)再看nvcc版本nvcc --version两者如果不一致就用conda装一个和PyTorch一致的CUDA Toolkit并在编译前把PATH和LD_LIBRARY_PATH指过去export PATH/usr/local/cuda-11.8/bin:$PATH export LD_LIBRARY_PATH/usr/local/cuda-11.8/lib64:$LD_LIBRARY_PATHconda安装CUDA Toolkit的方式是conda install -c nvidia cuda-toolkit11.85.2 训练出来一片黑或者全是噪点模型输出全黑通常有两种情况一是相机参数错误二是初始点云崩塌。如果你用的是自己的数据集建议检查COLMAP的稀疏重建结果——用COLMAP GUI打开sparse/0目录看一眼点云是否正常分布。如果点云像一层纸片一样摊开说明SfM失败了照片之间没有足够的特征匹配。全黑还有一种可能是图像加载路径出错了模型实际上没有读到训练图像。这种情况在Windows上比较常见原因是convert.py生成的相机参数里的图像路径分隔符是反斜杠而代码在Linux风格下解析时出错。解决办法是数据路径全部用英文并尽量在Linux环境跑训练。噪点过多重建表面有一层砂砾感则通常是densify的阈值设置问题。你可以检查训练后期的高斯球数量如果涨到了几百万个还止不住大概率是场景光照变化太大模型只能用大量小高斯球去硬凑。处理方法在数据端换一个光照更均匀的时间重新拍摄。5.3 显存不足怎么办对于8GB或更小显存的卡推荐把图像分辨率降下来。train.py里有几个参数可以控制python train.py -s data/bicycle -m output/bicycle --resolution 2这里的--resolution是指图像下采样的倍数2表示原图宽高各缩小一半。实测1080p输入在8GB卡上设置resolution2后显存占用可以降到5GB左右能跑但渲染效果明显下降。另一个办法是减少迭代过程中的densify次数但对新手来说最简单还是降低分辨率。如果在训练中途显存突然暴增大概率是densify触发时高斯球数量暴涨。这时候可以试试把--densify_grad_threshold调高一点阈值越高新增的高斯球越少。默认值是0.0002你可以先试0.0005。注意这个值只影响训练后半段早期结构建立阶段不受影响。5.4 COLMAP阶段照片匹配失败具体表现是convert.py跑了好几个小时稀疏重建出来只有几十个相机位姿点云稀稀拉拉。排查思路先看数据照片是否模糊、是否有大面积重复纹理比如白墙、是否有玻璃等透明物体。另外照片的分辨率太低也会导致特征点数量不足。我的建议是先用官方bicycle数据集跑通全流程确认环境OK。如果COLMAP对你的图片匹配失败就用GUI打开看看哪些图片被估出了位姿把匹配不上的图片删掉或者补拍。补拍时注意和相邻照片保持相似视角别跳太远。这里还有一个小技巧COLMAP匹配失败时可以尝试调整convert.py里特征提取的参数比如增大--SiftExtraction.max_num_features到10000。有时候图片纹理稀疏默认的8000个特征点不够用。5.5 训练时loss不下降、指标停滞如果你看到TensorBoard里PSNR指标训练到一定程度就纹丝不动先别急着调参。先看训练集和测试集指标的差值如果两者同步停滞说明模型表达能力到上限了多半是数据本身的问题照片不够、场景太大。如果训练集还在涨、测试集不动那是在过拟合可以提前停止训练。我遇到过一种更隐蔽的情况某些场景的墙面反射、水面波动导致图像之间光度不一致。3DGS假设场景是静态的遇到雨、雾、闪烁的灯光会出现“糊成一团”的现象。这种情况任何参数调优都没用只能在数据采集时避开了。6. 应用场景延伸与进阶建议6.1 3DGS能做什么实际项目跑通官方代码之后你可以把3DGS用在很多实际方向上文物保护里的器物3D重建、电商场景的商品展示、室内装修设计的效果预览、自动驾驶仿真中的道路场景重建。每个方向需要的功夫不一样但核心模型训练方法是一致的。物体级重建相对简单几十张照片就够模型小、训练快。场景级重建比如整条街道对相机位姿精度要求极高COLMAP很容易在长走廊、无纹理墙面区域丢失尺度信息。这种场景建议分块重建再合并别指望一次跑通。6.2 从单个场景到多场景和自定义模型3DGS目前没有像NeRF那样成熟的预训练/多场景泛化范式基本还是一个场景练一个模型。但社区里已经有各种改进版本有做实时流式渲染的有压缩高斯球数量降低推理成本的有把3DGS和骨骼动画结合的。如果你有心做科研代码实践跑通之后读一读这些改进版本的源码会比重新啃论文高效得多。我个人觉得3DGS和传统网格模型最大的区别在于它把“模型”变成了可微的数据结构。这意味着你不仅可以做渲染还能把3DGS模型直接作为优化对象比如做体积编辑、动态场景重建甚至三维内容生成。这个方向目前还是蓝海代码基础打牢了后面能玩的花样非常多。6.3 训练完模型的导出与轻量化如果你想把3DGS模型部署到Web端需要处理一下点云文件大小。训练完的PLY文件动辄几百MB浏览器加载很吃力。目前社区的做法主要是做高斯球剪枝和量化原理很简单把不透明度过低的球删掉把位置、颜色、旋转、缩放的数值从float32量化为float16或int8。我自己试过一个方案先用官方代码训练出模型再用现成的剪枝脚本把高斯球从100万剪到30万渲染质量肉眼几乎无差别文件体积减小了60%多。如果你做产品原型这一步几乎是必须的。7. 最后一个建议整个3DGS代码实践流程走下来我最想跟新手说的一句话是不要被环境配置劝退。那个编译扩展的坎每个做图形学的人都跨过跨过去之后剩下的都是水到渠成。我见过有人因为diff-gaussian-rasterization编译失败就放弃了整个方向其实换个GCC版本或者CUDA版本就能解决。如果你正在卡环境我的建议是关掉多余的浏览器页面把本文第二章的步骤一行一行照着敲遇到报错先复制报错信息去搜索引擎看别急着自己瞎试。这套流程我已经在不同机器上跑了至少五遍踩过所有能踩的坑照着来基本一次过。如果你已经跑通了bicycle场景下一步不妨用自己的手机拍一组照片试试。选一个光线充足、物体纹理丰富的桌面场景拍一百张左右跑一轮低分辨率测试再跑全分辨率。第一次看到自己拍的照片变成可旋转的三维模型的那一刻你会觉得所有折腾都值了。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑