OpenCV是一个基于(开源)发行的跨平台计算机视觉库。CUDA是由NVIDIA所推出的一种集成技术,透过这个技术,用户可利用NVIDIA的GeForce 8以后的GPU和较新的QuadroGPU进行计算。本文将不涉及OpenCV或者CUDA的更多介绍和使用,主要是提供了对特定版本编译时遇到问题的解决方案。
日前一个项目中的算法部分,一直是依赖于OpenCV2和CUDA8,在项目测试阶段也是完美通过。可在正式上线的时候却在编译OpenCV就一直出错,查到最后才发现生产机器的CUDA版本被人给「偷偷」升级到了CUDA9,也是因此踏上了一条填坑路,记录于下,以被自己所需和他人使用。
如果你是一台全新的环境,当然是按照需要的环境来安装,比如旧版本的OpenCV2 + CUDA8,或者是最新版本的OpenCV4+CUDA10这样的搭配,那么也就不需要再继续阅读下面的内容,因为理论上不会遇到下面的问题。
但是,如果你是在一台已有的环境,且被安装了CUDA9,同时你的代码又依赖于OpenCV2,那么你一定遇到了同样的问题,通过阅读这边文章,你就可以完美的编译并运行你的代码了。
在CUDA9下,我们编译OpenCV2的时候,会遇到了不少报错,主要原因是而相对于CUDA8,在CUDA9中的修改主要是2点:
在CUDA9里面,NVIDIA把 libnppi.so换成libnppc.so libnppial.so libnppicc.so libnppicom.so libnppidei.so libnppif.so libnppig.so libnppim.so libnppist.so libnppisu.so libnppitc.so libnpps.so
CUDA9.x+里面不支持compute_20 (Fermi)
我们在编译OpenCV2时遇到了报错,提示:
nvcc fatal : Unsupported gpu architecture 'compute_20'
这时候,在OpenCV2解压后的{OPENCV_CODE_PATH}/cmake/目录下找到这两个文件:
并使用下文中的直接完整替代(可先备份旧文件)
上文中,主要是修复了针对问题1和2的修复(如果希望了解具体的替换内容,可参考此链接)。
需要注意的是,当我们根据上文进行更改之后,在cmake时需要通过-DCUDA_GENERATION=xxx来指定CUDA的generation信息(如"Fermi" "Kepler" "Maxwell" "Pascal" "Volta")。如果不指定的话,在cmake时OpenCVDetectCUDA.cmake会基于上述所有已知架构完整编译,也是因此,会尝试编译Fermi架构并出现同样的Unsupported gpu architecture错误。
所以,如果我们未知上述的CUDA GENERATION信息的话,需要对OpenCVDetectCUDA.cmake文件再做两处修改,去除关于compute_20 arch的编译信息,因为如上文所说:CUDA9中不再支持2.0框架:
1. 删除Fermi架构的编译分支选项,将下文:
set(__cuda_arch_ptx "")
if(CUDA_GENERATION STREQUAL "Fermi")
set(__cuda_arch_bin "2.0")
elseif(CUDA_GENERATION STREQUAL "Kepler")
set(__cuda_arch_bin "3.0 3.5 3.7")
elseif(CUDA_GENERATION STREQUAL "Maxwell")
set(__cuda_arch_bin "5.0 5.2")
替换为:
set(__cuda_arch_ptx "")
if(CUDA_GENERATION STREQUAL "Kepler")
set(__cuda_arch_bin "3.0 3.5 3.7")
elseif(CUDA_GENERATION STREQUAL "Maxwell")
set(__cuda_arch_bin "5.0 5.2")
2. 针对CUDA版本9(大于cmake中的6.5),删除2.x的arch信息,将:
if(${CUDA_VERSION} VERSION_LESS "5.0")
set(__cuda_arch_bin "1.1 1.2 1.3 2.0 2.1(2.0) 3.0")
elseif(${CUDA_VERSION} VERSION_GREATER "6.5")
set(__cuda_arch_bin "2.0 2.1(2.0) 3.0 3.5")
else()
set(__cuda_arch_bin "1.1 1.2 1.3 2.0 2.1(2.0) 3.0 3.5")
endif()
替换为:
if(${CUDA_VERSION} VERSION_LESS "5.0")
set(__cuda_arch_bin "1.1 1.2 1.3 2.0 2.1(2.0) 3.0")
elseif(${CUDA_VERSION} VERSION_GREATER "6.5")
set(__cuda_arch_bin "3.0 3.5")
else()
set(__cuda_arch_bin "1.1 1.2 1.3 2.0 2.1(2.0) 3.0 3.5")
endif()
最后一步,根据 CUDA 9.0 manual所说:
Unsupported Features General CUDA ‣ CUDA library. The built-in functions __float2half_rn() and __half2float() have been removed. Use equivalent functionality in the updated fp16 header file from the CUDA toolkit.
因此我们需要在OpenCV中common.hpp里单独添加该头文件(在{OPENCV_CODE_PATH}目录下通过find命令找到该文件)
#include <cuda_fp16.h>
这时候,我们再次创建编译子目录{OPENCV_CODE_PATH}/mybuild/,并重新进行一次完整的opencv编译操作(在cmake时不必再指定-DCUDA_GENERATION参数了),就可以完美通过了。
经过上述的操作,OpenCV的编译环节应该没有任何问题了。然而,在编译我们自己项目代码的时候,依然会遇到链接报错。
/usr/bin/ld: cannot find -lopencv_dep_nppial
/usr/bin/ld: cannot find -lopencv_dep_nppicc
/usr/bin/ld: cannot find -lopencv_dep_nppicom
/usr/bin/ld: cannot find -lopencv_dep_nppidei
/usr/bin/ld: cannot find -lopencv_dep_nppif
/usr/bin/ld: cannot find -lopencv_dep_nppig
/usr/bin/ld: cannot find -lopencv_dep_nppim
/usr/bin/ld: cannot find -lopencv_dep_nppist
/usr/bin/ld: cannot find -lopencv_dep_nppisu
/usr/bin/ld: cannot find -lopencv_dep_nppitc
collect2: error: ld returned 1 exit status
这是因为,如我们上文所说,在CUDA9中更改了nppi的命名规范,这时候,我们需要去CUDA9的lib下找到对应的so文件,并建立正确的软链接。在我的机器上,CUDA9的lib库路径为/usr/local/cuda-9.0/lib64/,遇到同样问题的朋友,可以找到自己机器伤的PATH并替换下面的命令,再执行软连接操作:
ln -s {CUDA9_LIB_PATH}/libnppial.so /usr/local/lib/libopencv_dep_nppial.so
ln -s {CUDA9_LIB_PATH}/libnppicc.so /usr/local/lib/libopencv_dep_nppicc.so
ln -s {CUDA9_LIB_PATH}/libnppicom.so /usr/local/lib/libopencv_dep_nppicom.so
ln -s {CUDA9_LIB_PATH}/libnppidei.so /usr/local/lib/libopencv_dep_nppidei.so
ln -s {CUDA9_LIB_PATH}/libnppif.so /usr/local/lib/libopencv_dep_nppif.so
ln -s {CUDA9_LIB_PATH}/libnppig.so /usr/local/lib/libopencv_dep_nppig.so
ln -s {CUDA9_LIB_PATH}/libnppim.so /usr/local/lib/libopencv_dep_nppim.so
ln -s {CUDA9_LIB_PATH}/libnppist.so /usr/local/lib/libopencv_dep_nppist.so
ln -s {CUDA9_LIB_PATH}/libnppisu.so /usr/local/lib/libopencv_dep_nppisu.so
ln -s {CUDA9_LIB_PATH}/libnppitc.so /usr/local/lib/libopencv_dep_nppitc.so
通过上述操作,再重新编译我们的代码,这次就全部没有问题了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。