ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

COLMAP编译实战:Ceres启用CUDA加速的完整攻略

COLMAP编译实战:Ceres启用CUDA加速的完整攻略 搞三维重建的朋友对 COLMAP 这套开源流程应该不陌生。采集图像、特征提取、稀疏重建、稠密重建每一步都有现成命令行跑起来确实方便。真正让人头疼的是从源码编译尤其是想让核心优化库 Ceres Solver 把 CUDA 能力打开的时候——很多人卡在这一步少则半天多则两三天。网上搜到的教程不少但好多还停留在老版本参数上照着敲完照样报错。这篇文章我直接从实操角度出发把“Ceres 开 CUDA → COLMAP 识别 CUDA → 验证生效”这条链路完整捋一遍。不管你是自己从源码编译 COLMAP还是被 “ceres-solver has no CUDA support” 这种提示折磨的人下面这套步骤和避坑清单应该都能帮上忙。先说一个常见误区很多人以为装了 NVIDIA 驱动再装个 CUDA ToolkitCOLMAP 就自动用上 GPU 了。实际上 COLMAP 的核心优化库 Ceres 如果没有在编译阶段开启 CUDA 后端那么后面的一切都白搭COLMAP 即使编过了跑 Bundle Adjustment 时还是 CPU 在硬扛GPU 占用率基本是零。所以这个问题的关键不在 COLMAP 本身而是在 Ceres 的编译配置上。1. 先搞清楚COLMAP 卡脖子到底卡在哪1.1 Ceres 在 COLMAP 里扮演什么角色COLMAP 做三维重建核心是不断求解非线性最小二乘问题。图像之间匹配出来的特征点动辄几万几十万要把相机位姿、三角化点坐标尽可能优化到和观测一致这个优化过程就是 Bundle Adjustment业内一般直接叫 BA。BA 求解的效率和稳定性直接决定了重建能不能收敛、能不能跑得快。而 COLMAP 的 BA 求解器就是 Ceres Solver。Ceres 本身是一个通用的非线性最小二乘库Google 出品COLMAP 只是它的一个重量级用户。Ceres 在编译的时候可以选择用不同的线性代数后端比如 LAPACK、BLAS、SuiteSparse以及 CUDA。如果你在编译 Ceres 时没有把 CUDA 打开那 COLMAP 在 BA 阶段就只能用 CPU 求解器。小数据集看不太出来一旦场景变大、特征点变多CPU 和 GPU 的求解耗时差距能到数倍乃至一个数量级。1.2 Ceres 的 CUDA 后端到底加速了什么Ceres 从 2.1 版本开始正式支持 CUDA 后端主要用于稠密 Cholesky 分解、稠密 QR 分解等线性代数运算这些运算在求解 BA 的 Hessian 矩阵时会被高频调用。Ceres 的官方文档里明确写过CUDA 后端依赖 CUDA 10.1、Eigen 3.3.7、CMake 3.18以及算力 3.5 以上的 NVIDIA 显卡。需要说明的是这不是说 Ceres 里所有计算都能甩给 GPU。稀疏部分很多时候还是要靠 CPU 上的 SuiteSparse 来完成。但光是稠密求解那一段的 GPU 加速就已经能带来非常明显的体感差异了。我自己的直观感受是同一个数据集Ceres 不带 CUDA 时 BA 一轮迭代要等十几秒开了 CUDA 之后基本两三秒就过。这种差距不是玄学真正跑过的人都有感觉。所以回到题目解决 COLMAP 编译中的 Ceres CUDA 支持问题本质上就是两步——第一步把 Ceres 的 CUDA 后端编出来第二步让 COLMAP 在查找依赖时认准这个带 CUDA 的 Ceres。2. 编译前的环境体检这些基础没打牢后面全是坑2.1 驱动、CUDA Toolkit、编译器版本必须一起看很多人一上来就 git clone 然后 cmake结果报错报得莫名其妙其实就是环境没对齐。编译带 CUDA 的 Ceres至少有三样东西要确认NVIDIA 驱动、CUDA Toolkit、以及 C 编译器版本。先看驱动nvidia-smi如果这条命令能正常输出显卡信息说明驱动已经装好。右上角会显示一个 CUDA Version 字样比如 12.4。这代表你的驱动支持的 CUDA 最高版本它并不代表你已经安装了对应版本的 CUDA Toolkit。再看 Toolkitnvcc --version如果显示 command not found说明你只装了驱动还没装 CUDA Toolkit。那就需要去 NVIDIA 官网下载对应版本的 CUDA Toolkit 安装包。常见做法是选择 runfile 或 deb 方式这里不展开装完之后把环境变量配上export CUDA_HOME/usr/local/cuda export PATH$CUDA_HOME/bin:$PATH export LD_LIBRARY_PATH$CUDA_HOME/lib64:$LD_LIBRARY_PATH然后还有一个很容易被忽略的版本匹配问题nvcc 对 GCC 的版本有上限要求。比如 CUDA 11.x 高版本和 CUDA 12.0/12.1 一般最高支持 GCC 12如果用 Ubuntu 22.04 默认的 GCC 11配合 CUDA 12.1 通常没问题。但如果你的系统默认 GCC 是 13而 CUDA 是 11.xnvcc 在编译阶段会直接报 “unsupported GNU version”这时候就得装一个兼容的 GCC 版本或者换更新的 CUDA。为了省事我给一个常见组合参考系统环境GCC 版本推荐 CUDA 版本注意事项Ubuntu 20.049CUDA 11.0~11.8很稳Ceres 2.1 没问题Ubuntu 22.0411CUDA 11.8~12.1最常见组合不建议用 GCC 13Ubuntu 22.0412CUDA 12.2需要手动确认 nvcc 兼容Ubuntu 24.0413CUDA 12.4老 CUDA 容易报 GCC 版本错误2.2 系统依赖安装和源码准备Ceres 编译还依赖一堆数值库。为了避免后面缺这个缺那个先把系统依赖一次装齐sudo apt update sudo apt install -y cmake libeigen3-dev libsuitesparse-dev libtbb-dev \ libboost-all-dev libgoogle-glog-dev libgflags-dev libatlas-base-dev这里有几个关键点。libeigen3-dev 是 Ceres 的模板头文件库几乎必须。libsuitesparse-dev 提供稀疏 Cholesky 分解相关的能力比如 CHOLMOD、CXSparse对 Ceres 的稀疏求解很重要。如果你不装它Ceres 也会编过去但配置阶段会显示 SuiteSparse 没找到COLMAP 后面某些功能会受到限制。源码建议直接从官方拉git clone https://ceres-solver.googlesource.com/ceres-solver git clone https://github.com/colmap/colmap.git这里要特别提醒不要图省事直接 apt install libceres-dev。Ubuntu 源里的 Ceres 版本通常比较老而且一般不带 CUDA 支持。你后面就算费尽力气把 COLMAP 编出来它找到的还是那个没开 CUDA 的 Ceres等于白忙。3. Ceres 编译CUDA 开关和架构参数是灵魂3.1 关键 CMake 选项逐项拆解进入 Ceres 源码目录后核心操作就是 CMake 配置。这里最关键的几个选项我一个个说清楚。第一个是-DCERES_CUDAON。这是 Ceres 2.1 之后专门控制 CUDA 后端的开关。有些老教程写的是-DCERES_USE_CUDAON那是旧版参数新版 Ceres 根本不认。如果你照抄老教程CMake 配置阶段不会报错但 CUDA 实际没开等 COLMAP 那边提示 “Ceres has no CUDA support” 的时候才知道被坑了。第二个是-DCMAKE_CUDA_ARCHITECTURES80这类架构参数。这里的数字必须和你的显卡算力对应。RTX 30 系列是 Ampere 架构算力 8.6所以写 86。RTX 40 系列是 Ada 架构算力 8.9写 89。V100 是 Volta算力 7.0写 70。A100 是 Ampere 数据中心卡算力 8.0写 80。很多人喜欢直接写-DCMAKE_CUDA_ARCHITECTURESall意思是把能支持的架构全部编一遍。这样确实能保证兼容性但代价是编译时间会变得很长而且容易在某些环境上因为其他架构的设备代码生成问题而失败。除非你就是想在一台机器上编出到处能跑的版本否则我还是建议明确指定你自己的架构。第三个是-DCUDA_TOOLKIT_ROOT_DIR/usr/local/cuda。如果你的 CUDA 装在了非标准路径这个选项能帮 CMake 准确找到 Toolkit。一般 /usr/local/cuda 是个软链接指向你实际安装的 CUDA 版本目录。查显卡算力可以用这条命令nvidia-smi --query-gpucompute_cap --formatcsv输出类似 8.6那你 CMake 里就写 86。如果是多卡异构环境可以用分号分隔比如-DCMAKE_CUDA_ARCHITECTURES86;75但非必要不建议这么搞因为会增加编译耗时。3.2 完整编译命令与验证下面是一套我在 Ubuntu 22.04 CUDA 12.1 RTX 4090 环境下验证过的完整命令cd ceres-solver mkdir build cd build cmake .. \ -DCMAKE_BUILD_TYPERelease \ -DCERES_CUDAON \ -DCMAKE_CUDA_ARCHITECTURES89 \ -DCUDA_TOOLKIT_ROOT_DIR/usr/local/cuda \ -DCMAKE_PREFIX_PATH/usr/local make -j$(nproc)make 完成之后安装sudo make install安装完成后建议检查一下 CMake 缓存确认 CUDA 真的开了grep -i cuda CMakeCache.txt正常应该能看到类似CERES_CUDA:BOOLON的输出。如果这里显示 OFF或者没找到相关条目说明你的 Ceres 版本不对或者配置有问题先别急着往下走。另外注意 CMake 配置阶段的输出。你会看到类似SuiteSparse: YES CUDA: YES如果 CUDA 显示 NO那就先不要 make回头检查 CMake 选项和环境变量。如果 SuiteSparse 显示 NO建议先补齐依赖再继续否则即使 Ceres 编过了COLMAP 后面的稀疏求解能力也会缩水。3.3 为什么编译位置和安装路径这么重要COLMAP 在编译时通过 find_package(Ceres) 来找 Ceres而这个查找过程依赖 Ceres 的 CMake 配置文件 CeresConfig.cmake。如果你把 Ceres 装到了 /usr/localCOLMAP 默认也能找到。但如果你自定义了安装路径比如装到 /opt/ceres那就必须在编译 COLMAP 时通过 CMAKE_PREFIX_PATH 告诉它去哪个目录找。我在实际中遇到不少人是把 Ceres 源码放某个目录直接 build没有 make install然后就跑去编 COLMAP。COLMAP 的 find_package 不一定能定位到那个 build 目录里的 CeresConfig.cmake。所以稳妥做法就是先 install 到系统路径或者至少把 build 目录里的 CeresConfig.cmake 路径通过 Ceres_DIR 显式传给 COLMAP 的 cmake 配置。4. COLMAP 编译让它认准带 CUDA 的 Ceres4.1 COLMAP 的 CMake 配置与 GUI 开关Ceres 搞定之后COLMAP 这边就轻松多了。进入 COLMAP 源码目录cd colmap mkdir build cd build cmake .. \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_PREFIX_PATH/usr/local \ -DCUDA_ENABLEDON这里的-DCUDA_ENABLEDON是 COLMAP 自己的选项控制是否启用 COLMAP 自带流程里的 GPU 加速比如特征提取里的 SIFT 部分。注意它和 Ceres 的 CUDA 是两码事。如果你的 Ceres 没有开 CUDA那 COLMAP 配置时就会出现红色警告或者提示找不到带 CUDA 的 Ceres但不会立刻中断等运行的时候才会发现 BA 完全不吃 GPU。如果你不需要 COLMAP 的 GUI 界面可以不装 QtCMake 会自动把 GUI 相关部分关掉只编命令行工具。这样能省不少编译时间。如果要 GUI提前装sudo apt install -y qtbase5-dev libqt5opengl5-dev我在实际使用中其实很少开 GUI大部分情况都是直接用 colmap feature_extractor、colmap mapper、colmap model_converter 这些命令行工具。所以没有 GUI 并不影响正常使用。4.2 确认 CMake 配置摘要里的关键项COLMAP 的 CMake 配置阶段会打印一个摘要重点看几行CUDA 是否 ONCeres 的路径和版本是否找到 SuiteSparse如果摘要里 Ceres 版本显示的是老版本或者路径指向了你压根不记得的某个目录那就要小心了。可以显式指定 Ceres 的位置cmake .. -DCeres_DIR/usr/local/lib/cmake/Ceres或者如果你没有 install Ceres直接指向 Ceres 的 build 目录cmake .. -DCeres_DIR/path/to/ceres-solver/build这样能最大程度避免 find_package 找到了系统里其他位置的 Ceres。配置没问题后执行编译make -j$(nproc) sudo make installCOLMAP 编译量不小如果是第一次编译建议先确认内存和磁盘空间够用。我见过有人 make 到一半进程被杀就是因为内存不足。加 -j 参数的时候可以适当保守一些比如 -j8。5. 编译报错与排查实录5.1 高频报错速查表实际折腾过程中报错基本集中在下面几个场景。我把它们整理成表格方便你对照着处理。报错特征根本原因解决方法Could NOT find Ceres / Package Ceres not foundCeres 没安装或 CMake 找不到配置文件检查 Ceres 是否 make install通过 Ceres_DIR 显式指定路径ceres-solver has no CUDA supportCeres 版本太老或编译时没开 CERES_CUDA确认 Ceres 在 2.1 以上重新编译 Ceres 并检查 CMakeCacheUnsupported gpu architecture compute_xxCMAKE_CUDA_ARCHITECTURES 填错用 nvidia-smi --query-gpucompute_cap 查实际算力nvcc fatal: unsupported gnu versionGCC 版本超出当前 CUDA 支持范围安装兼容的 GCC或升级 CUDA ToolkitCUDA_cublas_LIBRARY / CUDA_cusolver_LIBRARY not foundCUDA Toolkit 安装不完整或路径错误重新安装 CUDA Toolkit核对 CUDA_TOOLKIT_ROOT_DIRSuiteSparse not found缺少 libsuitesparse-devapt install libsuitesparse-dev 后重新配置 CeresCMake Error: no known features for CUDAToolkitCMake 版本过低升级 CMake 到 3.18 以上建议 3.215.2 几个容易误判的隐蔽场景这里有几个我踩过坑后总结的经验藏得比较深值得单独拿出来说。第一个是 CMake 缓存残留。如果你之前用默认配置编过一次 Ceres后来又加了 CUDA 相关选项重新 cmake有时候会因为 CMakeCache.txt 里的旧变量没清干净导致 CUDA 相关的选项没有真正生效。遇到这种情况最省心的方式是把 build 目录整个删掉重新 mkdir build重新 cmake。我后来几乎都是这么干的比在旧缓存上反复试探要靠谱得多。第二个是显卡算力写得太高。比如你的显卡明明是 RTX 3060算力 8.6但你参考网上别人的教程写成了 89那是 RTX 40 系列的算力编译时 nvcc 会报不认识的 gpu architecture。反过来如果你写低了比如 70虽然能编过但运行时可能因为找不到对应的 SASS 或者 PTX 代码而无法加载内核表现就是 COLMAP 好像没报错但 GPU 利用率死活上不去。所以架构参数一定不能拍脑袋必须查准确。第三个是 CUDA Toolkit 装了两份。有时候系统里既有通过 deb 方式装的 CUDA又有 runfile 方式装的另一套导致 /usr/local/cuda 这个软链接指向混乱。现象是 nvcc --version 和 CMake 找到的版本不一致。我建议检查一下 /usr/local/cuda 到底指向哪个目录必要时手动修改软链接确保 CMake 找到的就是你预期的那一套。第四个是 COLMAP 和 Ceres 的 CUDA 概念被混淆。COLMAP 配置界面里 CUDA_ENABLED 只是它自己业务的开关不代表 Ceres 的 CUDA 状态。哪怕 COLMAP 这边 CUDA_ENABLEDON如果 Ceres 没开 CUDABA 还是 CPU 求解。反之亦然Ceres 开了 CUDA但 COLMAP 自己的特征提取没开 CUDA那么 SIFT 匹配那部分也会走 CPU。最理想的情况当然是两端都打开。6. 安装后的验证怎么确认 CUDA 真的在干活6.1 从 CMake 输出和文件入手Ceres 编译完装好之后有几个最直接的检查点。第一看 Ceres 装出来的 CMake 配置文件。比如 /usr/local/lib/cmake/Ceres/CeresConfig.cmake 里会有和 CUDA 相关的变量。你可以搜索里面是否有 CUDA 目录。如果全部是 OFF 或空说明这个 Ceres 没有启用 CUDA。第二编译 COLMAP 时看配置摘要。前面提到了摘要里如果 CUDA 是 ON、Ceres 路径也正确说明链接关系大概率没问题。这一步虽然简单但很多人不看等编译完跑起来才发现不对。第三看编译产物。如果你用 ldd 查看 COLMAP 的可执行文件动态库依赖理论上能看到链接了 ceres 相关的库。虽然 ceres 很多时候是被静态链接的但如果能看到 libcuda、libcublas 之类的依赖也能侧面说明链路确实接通了。6.2 从运行状态来验证上面的检查都通过之后最直观的验证方式是跑一次实际重建流程。拿一个小场景比如二三十张图片执行colmap feature_extractor --database_path db.db --image_path images colmap mapper --database_path db.db --image_path images --output_path out在 mapper 阶段另开一个终端执行 nvidia-smi观察是否有 colmap 进程以及 GPU 利用率是否波动。如果 BA 真的用上了 GPU你会看到显存有占用GPU-Util 会跳动。如果跑完整个流程 GPU 利用率都是 0%那大概率 Ceres 的 CUDA 后端没有真正生效。还有一个更细的观察角度是看日志耗时。开启详细日志后BA 迭代过程会有迭代次数和耗时信息。如果你对比过 CPU 和 GPU 版本你会发现每轮迭代的耗时差距明显。我自己在测一个一万多张图片的数据集时CPU 版本 BA 单轮迭代要二十多秒GPU 版本只要几秒整体重建流程时间差距立竿见影。最后分享一个我自己的使用习惯后来每次在干净服务器上编译这套流程我都会先在 Ceres 的 CMake 配置阶段停一下确认 SuiteSparse、CUDA 都是 YES然后再往下走。这个前置检查花不了两分钟但能避开后面一大堆莫名其妙的连锁报错。编译这种依赖链路很长的项目前期多花一点时间把环境确认清楚永远比后期排错省时间。
返回列表