PCL1.8.1+Visual Studio 2015+CUDA 9.0 实现PCL-GPU计算

使用PCL处理LIDAR点云数据时,感觉计算效率不太让人满意,在不明就里的情况下想到用GPU来做点云分割、聚类的相关计算。所以自行编译了PCL以支持GPU计算。最后测试的结果不很理想,真实原因还有待探索。

关于GPU计算比CPU还慢

首先说一下GPU计算的结果,我处理的点云大概也就一万来个点,用GPU做聚类居然比CPU还要慢,查了一圈也没真正搞明白背后的原因,看了这个网页上的讨论,貌似这居然是因为我的点数太少,无法显示出GPU计算的优越性,因为时间都浪费在数据向显存中传递的过程了。我只能理解为这是PCL-GPU相关算法本身的问题,如有大神对此有更深的见解请在评论区批评指正。

其实看到这种结果时,我内心是崩溃的:这么大费周章地一次重新编译了PCL,结果居然是这样的T_T。也许最新版本的PCL和更高版本的CUDA结合会碰撞出不一样的火花?暂时没时间搞清楚这件事情了,不妨先记在这里,日后有缘再做探讨吧。看到这里如果还想在pcl里支持GPU计算的,希望后面的内容能帮到您。

为什么选择这些版本号

其实关于这点没什么好说的。我写这段就是想提醒大家,能用最新的就用最新的吧,毕竟新版会修正老版中的各种莫名其妙的问题(这个大家后面就可以看到)。
很早以前就安装过CUDA,我的显卡是GeForce 940M,貌似最高也就支持到v9.0了,而且我当然不可能卸载掉它再去尝试更高的版本。Visual Studio也是以前就安装了的,不想装最新的2017,2019什么的,就想着凑合用了。至于PCL1.8.1,一开始下All-in-one installer时看见也就它后面会跟着MSV2015这个后缀。我想这其实是没什么关系的,但保险起见也就用它了。

关于GPU的架构(CUDA版本)

对于NVIDA显卡的架构,我其实是一窍不通的,只是使用CMake时遇到了不少error,貌似根源就在硬件架构(的代别)上,这里统一罗列一下。取这个小标题只是为了省事,显然本文不可能去讨论硬件的问题的。
当然用CMake处理PCL源码时,首先出现的是一些第三方支持的相关目录找不到的问题,类似这种的:

CMake Error at D:/Program Files/CMake/share/cmake-3.15/Modules/FindPackageHandleStandardArgs.cmake:137 (message):
Could NOT find Eigen (missing: EIGEN_INCLUDE_DIR)

这个还是好办的,手动把这些目录找到并添加上就可以了。
第一次Configure不再报错以后,毫无疑问,要把下面这两项勾上:
PCL1.8.1+Visual Studio 2015+CUDA 9.0 实现PCL-GPU计算_第1张图片
然后这里就出现了一系列gpu计算的相关模块,大家根据需要勾选就可以了。
PCL1.8.1+Visual Studio 2015+CUDA 9.0 实现PCL-GPU计算_第2张图片
当然这里就会开始出问题了。如果你不幸地勾选了BUILD_gpu_people这个选项,那么CMake会报错,告诉你找不到CUDA_nppi_LIBRARY。好嘛,我们就打开CUDA的链接库目录看看到底是什么情况。
PCL1.8.1+Visual Studio 2015+CUDA 9.0 实现PCL-GPU计算_第3张图片
这里面有一堆nppixx.lib,就是没有nppi.lib。查了一圈,发现居然是因为这是个历史遗留问题,老版本的CUDA貌似确实是有nppi.lib的,但在9.0里(具体从哪个版本开始的没有调研),这个nppi.lib就被一分为N,成了上面这些nppixx.lib。然而pcl 1.8.1的CMake File似乎无视了这一点,还要强行找到那个已经不存在的nppi.lib。于是你只能强行让他别这么做了。重申一下,这个问题只有在需要用pcl_gpu_people模块时才会遇到,不选这个模块应该会啥事没有吧。
找到pcl源码的gpu_people所在的目录(比如我的目录是F:\pcl-pcl-1.9.1\gpu\people),打开CMakeList.txt,把

find_cuda_helper_libs(nppi)

改成

find_cuda_helper_libs(nppial)
find_cuda_helper_libs(nppicc)
find_cuda_helper_libs(nppicom)
find_cuda_helper_libs(nppidei)
find_cuda_helper_libs(nppif)
find_cuda_helper_libs(nppig)
find_cuda_helper_libs(nppim)
find_cuda_helper_libs(nppist)
find_cuda_helper_libs(nppisu)
find_cuda_helper_libs(nppitc)

同时把

set(CUDA_npp_LIBRARY ${CUDA_nppc_LIBRARY} ${CUDA_nppi_LIBRARY} ${CUDA_npps_LIBRARY} CACHE STRING "npp library")

改成

set(CUDA_npp_LIBRARY "${CUDA_nppc_LIBRARY};${CUDA_nppial_LIBRARY};${CUDA_nppicc_LIBRARY};${CUDA_nppicom_LIBRARY};${CUDA_nppidei_LIBRARY};${CUDA_nppif_LIBRARY};${CUDA_nppig_LIBRARY};${CUDA_nppim_LIBRARY};${CUDA_nppist_LIBRARY};${CUDA_nppisu_LIBRARY};${CUDA_nppitc_LIBRARY};${CUDA_npps_LIBRARY}")

再Configure,就不再报错了。这也就是我为什么劝大家用最新版的PCL,因为如果你打开1.9.1版本的同样位置的这个CMakeList.txt,就会发现相应的地方被换成了如下的内容:

if(build)
  REMOVE_VTK_DEFINITIONS()
  #find_package(OpenCV QUIET)
  
  #find NPP
  unset(CUDA_npp_LIBRARY CACHE)
  if(${CUDA_VERSION} VERSION_LESS "5.5")
	find_cuda_helper_libs(npp)
  else()
    find_cuda_helper_libs(nppc)
    find_cuda_helper_libs(npps)
    if(${CUDA_VERSION} VERSION_GREATER_EQUAL "9.0")
      find_cuda_helper_libs(nppim)
      find_cuda_helper_libs(nppidei)
    else()
      find_cuda_helper_libs(nppi)
    endif()

    if(${CUDA_VERSION} VERSION_GREATER_EQUAL "9.0")
      set(CUDA_npp_LIBRARY ${CUDA_nppc_LIBRARY} ${CUDA_nppim_LIBRARY} ${CUDA_nppidei_LIBRARY} ${CUDA_npps_LIBRARY} CACHE STRING "npp library")
    else()
      set(CUDA_npp_LIBRARY ${CUDA_nppc_LIBRARY} ${CUDA_nppi_LIBRARY} ${CUDA_npps_LIBRARY} CACHE STRING "npp library")
    endif()
  endif()

这果然是CUDA版本(或者应该是PCL版本?)造成的问题。老版PCL的其他源码、相关文件,谁知道有没有更多这种陷阱呢?
然后,虽然现在CMake已经不报错了,但请再注意这个地方:
在这里插入图片描述
请一定别忘了把这里所有和 2 有关的全部干掉,不然后续编译代码的时候还是会报错,错误信息忘记记录了,隐约记得里面貌似是有 xx_20 的字样。有可能(真的只是有可能,我怎么还记得是sm_20…)是下面这个:

nvcc fatal : Unsupported gpu architecture 'compute_20

查了一下,这大概就是GPU架构造成的问题。实际上我后来只留下了 5.0 这一项(具体数字应该和GPU型号有关),但只要没有 2,似乎都不是问题,此处暂且不表。

编译过程中的其他问题

编译过程及其缓慢,其中我一共遇到了三个问题,其中一个上一部分已经提到了,接下来两个注意事项请在编译之前,甚至用CMake处理源码之前,就先处理一下,免得等了半天发现编译有误,那种感觉真的是很崩溃。
首先,打开PCL第三方支持Boost的include目录(我的情况是D:\PCL1.8.1\3rdParty\Boost\include\boost-1_64\boost\config\compiler)下的nvcc.hpp文件,把下面的几行注释掉:

// This is fixed in 7.5. As the following version macro was introduced in 7.5 an existance
// check is enough to detect versions < 7.5
#if !defined(__CUDACC_VER__) || (__CUDACC_VER__ < 70500)
#   define BOOST_NO_CXX11_VARIADIC_TEMPLATES
#endif
// The same bug is back again in 8.0:
#if (__CUDACC_VER__ > 80000) && (__CUDACC_VER__ < 80100)
#   define BOOST_NO_CXX11_VARIADIC_TEMPLATES
#endif

然后还会有一个 thrust::device_reference has no member “x” (“y”;“z”)的错误,完整的错误信息大概是这个样子的:

F:/pcl-1.8.1/cuda/sample_consensus/src/sac_model_plane.cu(195): error: class “thrust::device_reference” has no member “x”
detected during:
instantiation of “__nv_bool pcl::cuda::CountPlanarInlier::operator()(const Tuple &) [with Tuple=thrust::detail::tuple_of_iterator_references]”
…(以下省略一万字)

关于这个问题,这个网页做了一些讨论。这似乎是个只会在Window平台(坑爹啊)上出现的bug,显然,是源码里的 sac_model_plane.cu 这个源文件出了点状况。按照网页的说法,只要在出问题的行号对应的代码处使用thrust::raw_reference_cast即可解决问题。但鉴于出问题的地方实在太多,我直接下载了pcl-1.9.1的源码,并把对应文件夹下的所有源码文件都替换掉了。这里例举一下相关的行,大家可以自行体会出问题的原因。
1.8.1-sac_model_plane.cu (line192-201):

template  bool
CountPlanarInlier::operator () (const Tuple &t)
{
      if (!isfinite (thrust::get<0>(t).x))
        return (false);

      return (fabs (thrust::get<0>(t).x * coefficients.x +
                    thrust::get<0>(t).y * coefficients.y +
                    thrust::get<0>(t).z * coefficients.z + coefficients.w) < threshold);
}

1.9.1-sac_model_plane.cu (line192-201):

template  bool
CountPlanarInlier::operator () (const Tuple &t)
{
      if (!isfinite (thrust::raw_reference_cast(thrust::get<0>(t)).x))
        return (false);

      return (fabs (thrust::raw_reference_cast(thrust::get<0>(t)).x * coefficients.x +
                    thrust::raw_reference_cast(thrust::get<0>(t)).y * coefficients.y +
                    thrust::raw_reference_cast(thrust::get<0>(t)).z * coefficients.z + coefficients.w) < threshold);
}

其他的问题我就没再遇到过了。编译时成功了,gpu相关的模块貌似也可以用(当然目前我只测试过聚类相关的)。但计算速度真的是…一言难尽啊T_T。

你可能感兴趣的:(PCL)