前言
本节记录基于 OpenPCDet 训练 检测模型,通过 进行部署;
训练环境配置
对于路侧设备,单纯做雷达3D目标检测,最开始用 MMDetection3D 训练自定义数据集,训练一直报错。 后来发现, MMDetection3D 不支持自定义数据集训练。

切换到 OpenPCDet 项目训练点云模型。需要特别注意版本选择——OpenPCDet 0.6 之前的版本并不支持自定义数据集训练,因此建议下载最新版本,并按要求配置训练环境。
# 在当前项目下创建环境
python3 -m venv .venv
source .venv/bin/activate
1.pip install pytorch-gpu # 官网查找与cuda对应的安装即可
2.pip install -R requirements.txt
3.pip install spconv-cu118 # 与GPU版本相同就好
4.python setup.py develop
如果有不同版本CUDA,可以用下面方法临时切换CUDA版本
export PATH=/usr/local/cuda-11.8/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-11.8/lib64:$LD_LIBRARY_PATH
export CUDA_HOME=/usr/local/cuda-11.8
nvcc -V
python setup.py clean
python setup.py develop
模型训练
处理点云坐标系为: z 轴负方向指向地面,x 轴正方向指向前方,y 轴正方向指向左侧。如果原始点云坐标系与此不一致,需要进行坐标转换。此外,如果雷达安装存在俯仰角或倾斜,需要通过旋转矩阵将点云调整到与地面平行或重合的水平位置。
完成数据预处理后,需要根据实际数据在配置文件中设置以下参数:point_cloud_range、voxel_size、各类别对应参数:anchor_sizes、anchor_rotations、anchor_bottom_heights,更改 custom.yaml
、custom_dataset.yaml
,然后执行下面的命令进行训练验证。
# 生成数据集
python -m pcdet.datasets.custom.custom_dataset create_custom_infos tools/cfgs/dataset_configs/custom_dataset.yaml
# 训练
python train.py --cfg_file ./cfgs/custom_models/custom.yaml --batch_size=4 --epochs=30
# 测试
python test.py --cfg_file=../output/cfgs/custom_models/custom/default/custom.yaml --batch_size=4 --ckpt=../output/cfgs/custom_models/custom/default/ckpt/checkpoint_epoch_70.pth
# 推理
python demo.py --cfg_file ../output/cfgs/custom_models/custom/default/custom.yaml --ckpt ../output/cfgs/custom_models/custom/default/ckpt/checkpoint_epoch_20.pth --data_path=../data/custom/points/000018.npy
模型导出
要将训练好的模型部署到边缘计算单元,需要先将其转换为 TensorRT 模型。本项目采用 CUDA-PointPillars 进行部署。
如果使用的是最新版本的 OpenPCDet,可以通过 /CUDA-PointPillars/tools/export_onnx.py
导出模型。但直接运行该脚本会报错:
forward() missing 1 required positional argument: 'batch_dict'
虽然可以通过编写包装器来绕过此问题,但在后续自定义算子环节仍会遇到错误。这是因为 CUDA-PointPillars 在导出 ONNX 模型后,会对模型结构进行修改,并引入自定义插件 PPScatterPlugin 用于输入数据的处理。因此,第一步需要先解决 forward() missing 1 required positional argument: 'batch_dict'
的问题。可参考以下链接中的解决方案:
Support latest version of OpenPCDet v0.6.0
使用上述导出程序,可以顺利解决基于 OpenPCDet 官方配置 pointpillar.yaml
的模型导出问题。但在训练自定义数据集时,我们通常会修改 POINT_CLOUD_RANGE
等参数,此时原始的导出脚本就无法直接适配了。原因在于 simplify_postprocess()
和 replace_with_clip()
等函数中,部分维度是以固定值写死的。
因此,如果要导出自定义模型,需要对导出脚本进行相应修改。可以参考这里的实现:
parameterise for custom models
另外需要注意,在 simplifier_onnx.py
文件中,存在如下定义:
VOXEL_ARRAY = np.array([int(VOXEL_SIZE_Y), int(VOXEL_SIZE_X)])
这里 X
和 Y
的顺序写反了,必须手动修复,才能确保自定义模型正常导出。
还有一个需要特别注意的地方:在 simplifier_onnx.py
文件中,VOXEL_SIZE_Y
被直接转换为 int
。但是计算的 VOXEL_SIZE_Y
可能不是一个整数,比如,我的边界设置为:
POINT_CLOUD_RANGE = [0.0, -60.8, -4.0, 204.8, 59.52, 4.0]
VOXEL_SIZES = [0.16, 0.16, 8.0]
VOXEL_SIZE_X = abs(POINT_CLOUD_RANGE[0] - POINT_CLOUD_RANGE[3]) / VOXEL_SIZES[0]
VOXEL_SIZE_Y = abs(POINT_CLOUD_RANGE[1] - POINT_CLOUD_RANGE[4]) / VOXEL_SIZES[1]
print(VOXEL_SIZE_Y) # 751.9999999999999
# 下面执行后,VOXEL_SIZE_Y 就会变为 751
VOXEL_ARRAY = np.array([int(VOXEL_SIZE_X),int(VOXEL_SIZE_Y)])
如果直接进行 int
转换,可能会造成维度被截断,进而导致模型在导出后出现维度缺失的问题。因此,建议在模型导出完成后,结合配置文件检查并验证 PPScatterPlugin
的维度,确保其与训练时的设定完全一致。
基于此,可以正确导出自定义数据训练的自定义模型。
模型部署
直接使用 trtexec
转换 TRT 模型时会报错,这是因为导出的 onnx 文件中包含了自定义插件。在部署设备上需要先编译插件文件,并在导出时正确加载这些插件,才能完成转换。需要注意的是:
- 在旧版本中,只需直接替换
params.h
文件即可完成参数配置。 - 在新版本中,
params.h
文件已经移除,需要手动修改:lidar-postprocess.hpp
中的PostProcessParameter
,根据训练时的配置文件参数进行调整。main.cpp
中create_core()
的VoxelizationParameter
,同样需要修改为与训练配置一致的值。
然后编译后根据 CUDA-PointPillars
页面的转换教程转换自己的 TRT 模型。
如果设备上有多个 TRT 环境时,可以按下面方法设置 trt 环境:
# 当前终端生效,设置trt环境
export LD_LIBRARY_PATH=/usr/src/TensorRT-8.5.2.2/lib:$LD_LIBRARY_PATH
错误排查
在此处记录下当 TRT 推理结果与 PyTorch 模型结果不一致时,排查思路:
- 预处理验证:分别保存 python 与 C++ 端的预处理结果(模型输入前的数据),对比是否一致;也可以将 C++ 的预处理结果输入到 python 模型中,根据 python 输出结果验证 C++ 预处理环节是否正确。
- 后处理验证:保存 python 模型推理输出结果,用 TRT 程序去处理模型输出结果,验证trt后处理部分是否正常;
- 模型推理验证:保存 TRT 模型的推理输出,再交给 Python 的后处理程序处理,确认问题是否出在模型推理或模型导出阶段。 本例就是此处有异常,才不断排查模型导出的原因。