专栏算法工具链【参考算法】地平线 Pointpillars 参考算法-v1.2.1

【参考算法】地平线 Pointpillars 参考算法-v1.2.1

颜值即正义2023-02-14
703
15

0 概述

在自动驾驶应用中,除了在2D图像中检测目标之外,还必须在3D空间中检测某些目标的类别,如汽车、行人、自行车等。LiDAR通过构建3D空间的点云,可以提供一种精确、高空间维度、高分辨率的数据,可以弥补对3D空间的距离信息。随着深度学习架构的进步逐渐出现了许多基于LiDAR的3D目标检测器。本文在kitti3d数据集下基于pillar-based的pointpillars算法的介绍和使用说明。

该示例为参考算法,仅作为在J5上模型部署的设计参考,非量产算法

1 性能精度指标

数据集

backbone

精度

infer+后处理

帧率(J5/双核)

Kitti3D

RPN

76.69(99.12%)

25.8ms+ 2.6ms

116 fps

模型配置:

点云数量

点云范围

Voxel 尺寸

最大点数

最大pillar数

检测类别

15W

[0, -39.68, -3, 69.12, 39.68, 1]

[0.16, 0.16, 4.0]

100

12000

"car"

2 模型介绍

PointPillars的最大贡献是在VoxelNet中Voxel的基础上提出了一种改进版本的点云表征方法Pillar,可以将点云转换成伪图像,进而通过2D卷积实现目标检测。PointPillars整个网络结构分为三个部分:

  • Pillar Feature Net:将输入的点云转换为稀疏的Pseudo image;

  • Backbone:处理Pseudo image得到高层的特征;

  • Detection Head:检测和回归3D框.

2.1 模型改动点

在网络结构上,相比于官方实现,我们做了如下更改:
  • 前处理 point encoder部分,仅使用4维(官方9维),并做归一化处理,耗时减小4ms;精度表现: 浮点相比官方几乎不掉点(官方浮点77.42),但是对量化训练更友好;

  • PillarFeatutreNet 中的 PFNLayer 使用 Conv2d + BathNorm2d + ReLU,替换原有的 Linear + BatchNorm1d + ReLU,便于模型量化;

  • PillarFeatutreNet 中的 PFNLayer 使用 MaxPool2d,替换原有的 torch.max,便于性能的提升;

  • Scatter过程使用horizon_plugin_pytorch的point_pillars_scatter,便于模型推理优化,逻辑与公版相同。

2.2 源码说明

Config文件

configs/detection/pointpillars/pointpillars_kitti_car.py 为 pointpillars 的配置文件,定义了模型结构、数据集加载,和整套训练流程,所需参数的说明在算子定义中会给出。配置文件主要内容包括:
# Voxelization 配置
pc_range = [0, -39.68, -3, 69.12, 39.68, 1] #截取稀疏和未标记数据
voxel_size = [0.16, 0.16, 4.0]
max_points_in_voxel = 100
max_voxels_num = 12000
class_names = ["Car"]
...
# 模型结构定义
model=dict(
type="PointPillarsDetector", #model training structure
feature_map_shape=get_feature_map_size(pc_range, voxel_size),
pre_process=dict(
type="PointPillarsPreProcess",
pc_range=pc_range,
voxel_size=voxel_size,
max_voxels_num=max_voxels_num,
max_points_in_voxel=max_points_in_voxel,
),
reader=dict(
type="PillarFeatureNet",
with_distance=False,
quantize=True,
use_4dim=True, #对应改动点1
pool_size=(1, max_points_in_voxel), #对应改动点3
...
),
backbone=dict(
type="PointPillarScatter",
use_horizon_pillar_scatter=True, #对应改动4
...
),
neck=dict(
type="SequentialBottleNeck",
...
use_tconv=True,
),
head=dict(
type="PointPillarHead",
...
use_direction_classifier=True,
),
anchor_generator=dict(
type="Anchor3DGeneratorStride",
anchor_sizes=[[1.6, 3.9, 1.56]], # noqa B006 Anchor的尺寸
...
unmatch_thresholds=[0.45],
),
targets=dict(
type="LidarTargetAssigner",
...
region_similarity_calculator=dict(type="NearestIouSimilarity"),
),
loss=dict(
type="PointPillarsLoss",
num_classes=len(class_names),
loss_cls=dict(
type="SigmoidFocalLoss",
...
),
loss_bbox=dict(
type="WeightedSmoothL1Loss",
...
),
loss_dir=dict(
type="WeightedSoftmaxClassificationLoss",
...
),
),
postprocess=dict(
type="PointPillarsPostProcess",
...
use_direction_classifier=True,
# test_cfg
use_rotate_nms=False,
nms_pre_max_size=1000,
...
post_center_limit_range=[0, -39.68, -5, 69.12, 39.68, 5],
),
)
#deploy model and input
deploy_model=dict(...)
deploy_inputs = dict(
points=[
torch.randn(150000, 4),
],
)
#train数据处理
train_set=dict(
...
)
# 数据加载相关定义
dataloader=dict(...)
val_data_loader=dict(...)
#callbacks 定义
stat_callback = dict(...)
ckpt_callback = dict(...)
val_callback = dict(...)
#训练策略配置
float_trainer=dict(...)
calibration_trainer=dict(...)
qat_trainer=dict(...)
int_infer_trainer=dict(...)
#编译设置
compile_cfg = dict(...)
# predictor
float_predictor = dict(...)
calibration_predictor = dict(...)
qat_predictor = dict(...)
int_infer_predictor= dict(...)

注: 如果需要复现精度,config中的训练策略最好不要修改。否则可能会有意外的训练情况出现。

Voxelization
该接口是在horizon-plugin中实现,preprocess实现voxelization过程,主要是将点云数据根据预设size划分为一个个的网格。凡是落入到一个网格的点云数据被视为其处在一个 voxel里,或者理解为它们构成了一个 voxel。voxelization的实现流程见下图:
对应代码:horizon_plugin_pytorch/nn/quantized/functional_impl/_voxelization
PillarFeatureNet
为了应用 2D 卷积架构,最终要实现将点云(P,N,4)转换为伪图像,整体步骤如下图:
伪图像处理包括三个步骤,stack pillars、learn features、pseudo image。PFN层主要完成learn features步骤,对应代码路径:hat/models/task_modules/lidar/pillar_encoder.py
该算法主要实现将点云数据的shape (1,D,P,N)经过pfn_layers后变换为(1,1,P,C)
对应代码:hat/models/task_modules/lidar/pillar_encoder.py
PointPillarScatter
该层实现伪图像转换的最后一个步骤。为了获得伪图片特征,将 P 转化为(W, H),由于预先设定pillar最大值以及去除了一些空pillar,因此P<H*W,最终可以通过映射获得形如(C, H, W) 的伪图像。
对应代码: hat/models/task_modules/lidar/pillar_encoder.py

Scatter实现代码在horizon_plugin_pytorch下实现,见代码:

SequentialBottleNeck
该模型的backbone用是SequentialBottleNeck,使用多个 Conv2D + BN + ReLU 的结构将特征进行融合处理,通过多个卷积和反卷积的组合,最后在dim=1维做concat。RPN结构见下图:
对应代码:hat/models/necks/sequential_bottleneck.py
Detection Head
pointpillars模型 head 层的输出为box_preds, cls_preds, dir_preds。对应代码路径为:
hat/models/task_modules/pointpillars/head.py
PointPillars Loss

由3部分构成:loss_cls+loss_reg+loss_dir。其中,loss_cls=SigmoidFocalLoss;loss_bbox=WeightedSmoothL1Loss;loss_dir=WeightedSoftmaxClassificationLoss
对应代码:hat/models/losses/pointpillar_loss.py
前/后处理

pointpillars 在infer中前后处理部分主要为以下部分:

前处理:
  • 点云pillar化(具体实现过程见voxelization章节);

  • 对coors 0维添加batch_id,以便scatter时P到H*W的映射;

  • 对voxel_feature归一化
    对应路径:hat/models/task_modules/pointpillars/pre_process.py

后处理:

  • 生成anchor;

  • NMS去除低质量高重叠的框;

  • 生成camera、image坐标下的box
    对应路径:hat/models/task_modules/pointpillars/postprocess.py

3 浮点模型训练

3.1 Before Start

3.1.1 环境部署

pointpillars示例集成在OE包中,获取方式见:J5芯片算法工具链OpenExplorer 版本发布
pointpillars示例位于ddk/samples/ai_toolchain/horizon_model_train_sample下,其结构为:

release_models获取路径见:horizon_model_train_sample/scripts/configs/detection/pointpillars/README.md

拉取docker环境

如需本地离线安装HAT,我们提供了训练环境的whl包,路径在ddk/package/host/ai_toolchain

3.1.2 数据准备

在开始训练模型之前,第一步是需要准备好数据集,我们在KITTI官网下载 3DObject据集 , 包括4个文件:
  • left color images of object data set,

  • velodyne point clouds,

  • camera calibration matrices of object data set,

  • taining labels of object data set ,

下载上述4个文件后,解压并按照如下方式组织文件夹结构:

为了创建 KITTI 点云数据,首先需要加载原始的点云数据并生成相关的包含目标标签和标注框的数据标注文件,同时还需要为 KITTI 数据集生成每个单独的训练目标的点云数据,并将其存储在 gt_database 的 .bin 格式的文件中,此外,需要为训练数据或者验证数据生成 .pkl 格式的包含数据信息的文件。随后,通过运行下面的命令来创建 KITTI 数据:

该过程的产出物为.pkl文件,生成时间较长

执行上述命令后,生成的文件目录如下:

3.1.3 数据打包

上面两条命令分别对应转换训练数据集和验证数据集(.pkl-->lmdb),打包完成之后,data目录下的文件结构应该如下所示:

train_lmdb 和 val_lmdb 就是打包之后的训练数据集和验证数据集,也是网络最终读取的数据集,

3.1.4 config 配置

在进行模型训练和验证之前,需要对configs文件中的部分参数进行配置,一般情况下,我们需要配置以下参数:

  • device_ids、batch_size_per_gpu:根据实际硬件配置进行device_ids和每个gpu的batchsize的配置;

  • ckpt_dir:浮点、calib、量化训练的权重路径配置,权重下载链接在config文件夹下的README中;

  • base_data_dir:为kitti3d数据集目录,./tmp_data/kitti3d/;

  • root_path:为kitti3d数据集目录,./tmp_data/kitti3d/;

  • db_info_path:为生成的 kitti3d_dbinfos_train.pkl 路径

  • data_path:为打包的lmdb路径

3.2 浮点模型训练

在configs/detection/pointpillars/pointpillars_kitti_car.py下配置参数,需要将相关硬件配置和数据集路径配置修改后使用以下命令训练浮点模型:

3.3 浮点模型精度验证

通过指定训好的float_checkpoint_path,使用以下命令验证已经训练好的模型精度:

4 模型量化和编译

模型上板前需要将模型编译为.hbm文件, 可以使用compile的工具用来将量化模型编译成可以上板运行的hbm文件,因此首先需要将浮点模型量化,地平线对pointpillars模型的量化采用horizon_plugin框架,通过Calibration+QAT量化训练和转换最终获得定点模型。

4.1 Calibration

为加速QAT训练收敛和获得最优量化精度,建议在QAT之前做calibration,其过程为通过batchsize个样本初始化量化参数,为QAT的量化训练提供一个更好的初始化参数,和浮点训练的方式一样,将checkpoint_path指定为训好的浮点权重路径。通过运行下面的脚本就可以开启模型的Calibration:

4.2 Calibration 模型精度验证

calibration完成以后,可以使用以下命令验证经过calib后模型的精度:

验证完成后,会在终端输出calib模型在验证集上的检测精度。

4.3 量化模型训练

Calibration完成后,就可以加载calib权重开启模型的量化训练。 量化训练其实是在浮点训练基础上的finetue,具体配置信息在config的qat_trainer中定义。量化训练的时候,初始学习率设置为浮点训练的十分之一,训练的epoch次数也大大减少。和浮点训练的方式一样,将checkpoint_path指定为训好的calibration权重路径。
通过运行下面的脚本就可以开启模型的qat训练:

4.4 量化模型精度验证

量化模型的精度验证,只需要运行以下命令:

qat模型的精度验证对象为插入伪量化节点后的模型(float32);quantize模型的精度验证对象为定点模型(int8),验证的精度是最终的int8模型的真正精度,这两个精度应该是十分接近的。

4.5 仿真上板精度验证

除了上述模型验证之外,我们还提供和上板完全一致的精度验证方法,可以通过下面的方式完成:

4.6 量化模型编译

在训练完成之后,可以使用compile的工具用来将量化模型编译成可以上板运行的hbm文件,同时该工具也能预估在BPU上的运行性能,可以采用以下脚本:
opt为优化等级,取值范围为0~3,数字越大优化等级越高,运行时间越长;
compile_perf脚本将生成.html文件和.hbm文件(compile文件目录下),.html文件为BPU上的运行性能,.hbm文件为上板实测文件。

5 其他工具

5.1 结果可视化

如果你希望可以看到训练出来的模型对于单帧雷达点云的检测效果,我们的tools文件夹下面同样提供了点云预测及可视化的脚本,你只需要运行以下脚本即可:

由于开发机配置不同,plt.show可能不会正常显像,可以通过plt.savefig在保存的路径中查看

6 板端部署

6.1 上板性能实测

使用hrt_model_exec perf工具将生成的.hbm文件上板做BPU性能实测,hrt_model_exec perf参数如下:

点云模型的板端验证请务必使用真实点云输入

6.2 AIBenchmark示例

OE开发包中提供了pointpillars的AI Benchmark示例,位于:ddk/samples/ai_benchmark/j5/qat/script/detection/pointpillars_kitti_car,具体使用可以参考开发者社区J5算法工具链产品手册-AIBenchmark评测示例

可在板端使用以下命令执行做模型评测:
如果要进行精度评测,请参考开发者社区J5算法工具链产品手册-AIBenchmark示例精度评测进行数据的准备和模型的推理。
算法工具链
征程5官方教程
+3
评论5
0/1000
  • wangqin
    Lv.1

    配置里

    db_sampler

    {

    info_path="./tmp_data/kitti3d/kitti3d_dbinfos_train.pkl

    }

    这个文件怎么生成,制作数据集的时候只生成lmdb,但并没有生成kitti3d_dbinfos_train.pkl,

    2023-04-13
    0
    5
    • 颜值即正义回复wangqin:
      pkl是python3 tools/create_data.py 脚本生成的
      2023-04-13
      0
    • wangqin回复颜值即正义:
      好的,找到了,请问create_data.py有支持nuscenes,我现在拿到的版本只有kitti的
      2023-04-14
      0
    • 颜值即正义回复wangqin:
      nuscenes不需要create_data,另外我们即将发布centerpoint模型是基于nuscenes的。

      2023-04-25
      0
    • 御坂美琴回复颜值即正义:

      你好,我并为找到 hat/models/task_modules/pointpillars,这个文件夹,请问应该如何获得

      2023-05-12
      0
    • 御坂美琴回复颜值即正义:

      也未找到这个horizon_plugin_pytorch/nn/quantized/functional_impl/_voxelization文件夹

      2023-05-12
      0
  • 御坂美琴
    Lv.1

    你好,我并为找到 hat/models/task_modules/pointpillars,这个文件夹,请问应该如何获得

    2023-05-12
    0
    2
    • 颜值即正义回复御坂美琴:
      HAT是python包,可以:ls /usr/local/lib/python3.6/site-packages/hat/models/task_modules/pointpillars/
      根据docker版本路径会有些微不同
      2023-05-15
      0
    • 颜值即正义回复御坂美琴:
      horizon_plugin_pytorch/nn/quantized/functional_impl/_voxelization文件夹的位置在usr/local/lib64/python3.6(python3.8)/site-packages/horizon_plugin_pytorch目录下
      2023-05-15
      0
  • chengang
    Lv.1

    有一个疑问想请教下,参考算法有pointpillars和centerpoint两种点云检测算法,检测头不一样,一个是anchor-based,一个是anchor-free。板端部署应用,多类别检测的话,使用哪一种检测头更方便些,时间开销不知道你们有没有测试过,谢谢。

    2023-08-04
    0
    2
    • 颜值即正义回复chengang:

      您好,pointpillars是单类别3D检测,centerpoint是多类别3D检测,如果您要做多类别检测,建议参考centerpoint

      2023-08-04
      0
    • chengang回复颜值即正义:

      谢谢。

      2023-08-07
      0
  • 夏新飞1
    Lv.1

    您好,请问可以导出onnx吗?如何导出呢?

    2023-05-31
    0
    1
    • 遥看瀑布挂前川回复夏新飞1:
      您好,可以在config文件中添加onnx_cfg参数组 来导出:
      导出 float onnx,config添加:

      使用以下命令:

      python3 tools/export_onnx.py --config /workspace/pointpillars_config_path.py

      2023-05-31
      0
  • PolarS
    Lv.1

    ??

    2023-03-07
    0
    0