复现CLOCs中spconv v1.0 (commit 8da6f96)踩坑记录

最近看了一篇基于KITTI做2D和3D后融合的论文,CLOCs: Camera-LiDAR Object Candidates Fusion for 3D Object Detection。作者在Github上开源了自己代码,于是想着复现一下结果。结果花了几天搭环境遇到不少bug,就想着记录一下避免其他人遇到相同问题走弯路,也方便自己以后重新搭建的时候有个参照。

其中问题最大的就是那个spconv库了,其他库都是小打小闹,只有这个才是真正的坑。而我恰巧又遇到了最倒霉的情况,比正常人多走了更多的弯路(后文会介绍原因)。

一开始我刚好看到spconv库更新到2.x了,而且宣布速度比1.x快50%同时不需要自己编译了,我于是立马安装了准备用在CLOCs中。结果发现spconv 2.x移除了所有spconv.util模块,而CLOCs中使用了很多spconv.util,我懒得挨个改,就放弃了。其实spconv这个库还是有很多做KITTI数据集检测的文章用的,我想起我之前复现的OpenPCDet框架也用了,并且我还成功复现了于是切换到那个搭建好的环境。结果运行的时候遇到如下bug:

Traceback (most recent call last):
  File "./pytorch/train.py", line 918, in 
    fire.Fire()
  File "/home/feng/anaconda3/envs/OpenPCDet/lib/python3.6/site-packages/fire/core.py", line 141, in Fire
    component_trace = _Fire(component, args, parsed_flag_args, context, name)
  File "/home/feng/anaconda3/envs/OpenPCDet/lib/python3.6/site-packages/fire/core.py", line 471, in _Fire
    target=component.__name__)
  File "/home/feng/anaconda3/envs/OpenPCDet/lib/python3.6/site-packages/fire/core.py", line 681, in _CallAndUpdateTrace
    component = fn(*varargs, **kwargs)
  File "./pytorch/train.py", line 656, in evaluate
    for example in iter(eval_dataloader):
  File "/home/feng/anaconda3/envs/OpenPCDet/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 346, in __next__
    data = self._dataset_fetcher.fetch(index)  # may raise StopIteration
  File "/home/feng/anaconda3/envs/OpenPCDet/lib/python3.6/site-packages/torch/utils/data/_utils/fetch.py", line 44, in fetch
    data = [self.dataset[idx] for idx in possibly_batched_index]
  File "/home/feng/anaconda3/envs/OpenPCDet/lib/python3.6/site-packages/torch/utils/data/_utils/fetch.py", line 44, in 
    data = [self.dataset[idx] for idx in possibly_batched_index]
  File "/home/feng/CLOCs/second/pytorch/builder/input_reader_builder.py", line 18, in __getitem__
    return self._dataset[idx]
  File "/home/feng/CLOCs/second/data/dataset.py", line 70, in __getitem__
    prep_func=self._prep_func)
  File "/home/feng/CLOCs/second/data/preprocess.py", line 363, in _read_and_prep_v9
    example = prep_func(input_dict=input_dict)
  File "/home/feng/CLOCs/second/data/preprocess.py", line 225, in prep_pointcloud
    points, max_voxels)
  File "/home/feng/anaconda3/envs/OpenPCDet/lib/python3.6/site-packages/spconv/utils/__init__.py", line 173, in generate
    or self._max_voxels, self._full_mean)
  File "/home/feng/anaconda3/envs/OpenPCDet/lib/python3.6/site-packages/spconv/utils/__init__.py", line 69, in points_to_voxel
    assert block_filtering is False
AssertionError

好家伙,assert block_filtering is False是个啥,从来没见过。去SECOND-1.5下面看有人遇到过这个bug,SECOND作者说使用spconv v1.0 (commit 8da6f96)不会遇到这个问题,同时CLOCs作者也在readme中写道让用spconv v1.0 (commit 8da6f96)。第一次见到不仅仅要求库具体版本而且要体到某个commit id的,不知道这个commit id的spconv有什么魔力。这里多嘴一句,CLOCs开源版本的3D模块使用的SECOND-1.5,所以两者环境需求基本一致,如果你搭建CLOCs遇到什么问题也可以去SECOND-1.5下面看看有没有类似的。

接下来就要编译spconv v1.0 (commit 8da6f96)了,先介绍下我的环境

系统:基于WSL2的Ubuntu20.04(就是Windows环境下的Linux子系统)

CUDA版本:11.4

cuDNN版本:8.2.4

然而就是这个WSL和Ubuntu20.04还有CUDA11坑死我了,正常根本不会同时遇到这么多问题。

conda、CUDA和CUDNN安装就不赘述了。首先我们用conda创建一个新的环境

conda create -n CLOCs python=3.6 pytorch=1.1 torchvision

-n后面那个CLOCs是你这个环境的名字,可以随便取。剩下的是让conda安装的库,其中python版本和pytorch版本需要指定一下,因为spconv v1.0 (commit 8da6f96)有要求。而conda会自动帮你找到和这个pytorch版本匹配的torchvision,所以不需要手动指定(给我安装的是torchvision=0.3)。如果是用pip安装torchvision的话需要自己去找相匹配的版本,不然pip会自动安装最新的torchvision,而为了安装最新的torchvision他会自动卸载你的pytorch=1.1转而换成和最新的torchvision匹配的pytorch=1.10。

安装好后输入下面代码激活环境,注意这里CLOCs是你上面取的名字。

conda activate CLOCs

激活环境后首先测试一下是不是安装的cuda版本的pytorch。依次输入

python
import torch
torch.cuda.is_available()
exit()

复现CLOCs中spconv v1.0 (commit 8da6f96)踩坑记录_第1张图片

如果和上图一样输出True ,说明pytorch可以正常调用cuda。如果是False,你可能需要在conda安装的时候指定一下cuda版本,比如

conda create -n CLOCs python=3.6 pytorch=1.1 torchvision cudatoolkit=9.2

成功安装1.1.0版本pytorch后我们就可以开始编译spconv了(开始踩坑了)。首先拷贝spconv,并且切换到指定commit id的版本。

git clone https://github.com/traveller59/spconv.git --recursive
cd spconv/
git checkout 8da6f96

但先别急着编译,这里面缺失了一个第三方库pybind11,我们需要自己clone下来,同时spconv v1.0 (commit 8da6f96)指定了对应commit id的pybind11,虽然不知道有没有影响,但是我们最好也切换一下。接着上面依次输入

cd third_party/
git clone https://github.com/pybind/pybind11.git
cd pybind11/
git checkout 085a294

 接下来依次输入下面代码返回spconv根目录,并且开始编译

cd ../..
python setup.py bdist_wheel

如果你是CUDA9.X,应该会直接运行完不报错。如果你是CUDA10.X但是报错了,你可能需要运行下面代码,删掉当前环境并运行conda重装一下,同时指定一下低版本的CUDA工具包(在我借来的Ubuntu系统上这样成功了)。

conda remove -n CLOCs --all
conda create -n CLOCs python=3.6 pytorch=1.1 torchvision cudatoolkit=9.2

如果你是CUDA11,那么你也可以通过装CUDA9.X或者CUDA10.X来解决,关于多版本CUDA切换网上教程很多,你并不需要卸载掉当前的CUDA11。

但如果你和我一样是Ubuntu20.04的天选之子,那么恭喜你,如果要装一个CUDA10.X或者CUDA9.X,你需要先重装一个Ubuntu16.04的系统,因为Ubuntu20.04的gcc版本太新了,CUDA10和CUDA9无法识别,无法成功安装。甚至Ubuntu20.04源里版本最低的gcc都不支持。我甚至试过利用Ubuntu16.04的源在Ubuntu20.04上安装超低版本的gcc来编译CUDA9.X,但是也失败了。

如果你也是WSL2,我可以兴奋的告诉你,你想重装Ubuntu16.04都没可能。微软官方声明由于Ubuntu16.04的四年长期更新结束了,所以他们也从应用商店下架了Ubuntu16.04(你们真的不是单纯想偷懒不维护么???)。但是鲁迅说的对,“只有被逼到绝境的人才会疯狂去找办法”(鲁迅表示我什么时候说过这话)。

面对着不可能安装CUDA10和CUDA9的WSL2,我只能逼自己去解决大片大片的error,不过还好其实也不难,毕竟我这种菜鸡都能解决。

首先我们可以看到首先出场的bug是 

复现CLOCs中spconv v1.0 (commit 8da6f96)踩坑记录_第2张图片

The CUDA compiler is not able to compile a simple test program。笑话,我CUDA11大哥怎么可能连个简单测试都编译不过,果然继续往前看,虽然没有报错但真实的错误是

复现CLOCs中spconv v1.0 (commit 8da6f96)踩坑记录_第3张图片

没有找到CUDA编译器,那既然你没找到我直接告诉你在哪里好吧。在spconv/setup.py第48行添加

'-DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc',

添加后如图

复现CLOCs中spconv v1.0 (commit 8da6f96)踩坑记录_第4张图片

 从路径也可以看出,他搜索到的路径是/usr/bin/nvcc,但是实际nvcc路径是/usr/local/cuda/bin/nvcc,不知道是不是不同版本CUDA路径不同导致的。重新运行

python setup.py bdist_wheel

 果然一波未平一波又起,不过这次问题很类似。首先从第一个横线可以看到nvcc可以正常识别了,不过可以从第二个横线看出来又没找到cuDNN。不过这个问题我以前查找cuDNN版本时候遇到过,是因为cuDNN新版本取消了cudnn.h显示版本改成了cudnn_version.h显示版本。

复现CLOCs中spconv v1.0 (commit 8da6f96)踩坑记录_第5张图片

 知道问题就好办了,我们去报错的路径(图中第三个红线处)修改就好。将137行cudnn.h改为cudnn_version.h

复现CLOCs中spconv v1.0 (commit 8da6f96)踩坑记录_第6张图片

 编译通过,高兴的手舞足蹈。各种重装CUDA,去查相关bug,来来回回花了好几天时间,终于成功了。哦对,这时候还没完,我第一次编译通过就兴奋的睡觉去了,结果第二天发现不能用。最后检查半天才发现编译完了忘记安装了 

cd ./dist
python -m pip install spconv-1.0-cp36-cp36m-linux_x86_64.whl

 spconv安装到这里就结束了。如果是复现CLOCs的接下来照着作者readme来就好,除了WSL2用户安装numba的时候需要注意。

如果你在运行CLOCs的时候遇到如下bug

Traceback (most recent call last):
  File "./pytorch/train.py", line 16, in 
    from second.builder import target_assigner_builder, voxel_builder
  File "/home/feng/CLOCs/second/builder/target_assigner_builder.py", line 3, in 
    from second.core.target_assigner import TargetAssigner
  File "/home/feng/CLOCs/second/core/target_assigner.py", line 1, in 
    from second.core import box_np_ops
  File "/home/feng/CLOCs/second/core/box_np_ops.py", line 5, in 
    from second.core.non_max_suppression.nms_gpu import rotate_iou_gpu_eval
  File "/home/feng/CLOCs/second/core/non_max_suppression/__init__.py", line 2, in 
    from second.core.non_max_suppression.nms_gpu import (nms_gpu, rotate_iou_gpu,
  File "/home/feng/CLOCs/second/core/non_max_suppression/nms_gpu.py", line 24, in 
    @cuda.jit('(int64, float32, float32[:, :], uint64[:])')
  File "/home/feng/anaconda3/envs/CLOCs/lib/python3.6/site-packages/numba/cuda/decorators.py", line 95, in kernel_jit
    return Dispatcher(func, [func_or_sig], targetoptions=targetoptions)
  File "/home/feng/anaconda3/envs/CLOCs/lib/python3.6/site-packages/numba/cuda/compiler.py", line 899, in __init__
    self.compile(sigs[0])
  File "/home/feng/anaconda3/envs/CLOCs/lib/python3.6/site-packages/numba/cuda/compiler.py", line 1102, in compile
    kernel.bind()
  File "/home/feng/anaconda3/envs/CLOCs/lib/python3.6/site-packages/numba/cuda/compiler.py", line 590, in bind
    self._func.get()
  File "/home/feng/anaconda3/envs/CLOCs/lib/python3.6/site-packages/numba/cuda/compiler.py", line 433, in get
    cuctx = get_context()
  File "/home/feng/anaconda3/envs/CLOCs/lib/python3.6/site-packages/numba/cuda/cudadrv/devices.py", line 212, in get_context
    return _runtime.get_or_create_context(devnum)
  File "/home/feng/anaconda3/envs/CLOCs/lib/python3.6/site-packages/numba/cuda/cudadrv/devices.py", line 138, in get_or_create_context
    return self._get_or_create_context_uncached(devnum)
  File "/home/feng/anaconda3/envs/CLOCs/lib/python3.6/site-packages/numba/cuda/cudadrv/devices.py", line 151, in _get_or_create_context_uncached
    with driver.get_active_context() as ac:
  File "/home/feng/anaconda3/envs/CLOCs/lib/python3.6/site-packages/numba/cuda/cudadrv/driver.py", line 393, in __enter__
    driver.cuCtxGetCurrent(byref(hctx))
  File "/home/feng/anaconda3/envs/CLOCs/lib/python3.6/site-packages/numba/cuda/cudadrv/driver.py", line 280, in __getattr__
    self.initialize()
  File "/home/feng/anaconda3/envs/CLOCs/lib/python3.6/site-packages/numba/cuda/cudadrv/driver.py", line 240, in initialize
    raise CudaSupportError("Error at driver init: \n%s:" % e)
numba.cuda.cudadrv.error.CudaSupportError: Error at driver init: 
[100] Call to cuInit results in CUDA_ERROR_NO_DEVICE:

需要在~/.bashrc中添加一句

export NUMBA_CUDA_DRIVER=/usr/lib/wsl/lib/libcuda.so.1

这是我翻了好久才在两个大佬的对话中发现的,只针对wsl有用,大佬意思是好像是numba作者找的是默认CUDA驱动,而wsl的驱动位置由于是用Windows装的所以在另外地方。

你可能感兴趣的:(自动驾驶,pytorch,人工智能)