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

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 的配置文件,定义了模型结构、数据集加载,和整套训练流程,所需参数的说明在算子定义中会给出。配置文件主要内容包括:

# GPU卡等基础参数配置
batch_size_per_gpu = 28
# PointPillars 配置
norm_cfg = None

# 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

def _voxelization(
    points: Tensor,
    voxel_size: Tensor,
    pc_range: Tensor,
    max_voxels: int,
    max_points_per_voxel: int,
    use_max: bool,
) -> Tuple[Tensor, Tensor, Tensor]:
    "Convert points(N, >=3) to voxels."
    ndim = 3 #point xyz
    grid_size = (pc_range[3:] - pc_range[:3]) / voxel_size  # (x, y, z)
    voxel_map_shape = voxel_map_shape[::-1]  # (z, y, x)

    voxels = torch.zeros(...)    #(max_voxels, max_points_per_voxel, points.shape[-1])
    coors = torch.full(
        (max_voxels, 3),
        -1,
        dtype=torch.int32,
    )   #(max_voxels, 3)
    num_points_per_voxel = torch.zeros(...) #(max_voxels,)

    voxel_num = torch.zeros(1, dtype=torch.int64)
    voxel_num = torch.ops.horizon.voxelization(
        points.cpu(),
        voxel_size.cpu(),
        pc_range.cpu(),
        voxels.cpu(),
        coors.cpu(),
        num_points_per_voxel.cpu(),
        max_points_per_voxel,
        max_voxels,
        ndim,
    )

    if use_max:
        # for deploy, use max_voxels
        out_num = max_voxels
    else:
        out_num = voxel_num

    coors = coors[:out_num].to(points.device)
    voxels = voxels[:out_num].to(points.device)
    num_points_per_voxel = num_points_per_voxel[:out_num].to(points.device)
    return (voxels, coors, num_points_per_voxel)

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

class PillarFeatureNet(nn.Module):
    def __int__(
    ...
    ):
    ...
    def forward(
        self,
        features: torch.Tensor,
        coors: torch.Tensor,
        num_voxels: torch.Tensor = None,
        horizon_preprocess: bool = True,
    ):
        if horizon_preprocess:
            # used horizon preprocess, skip pre_process here.
            features = self._extract_feature(features) #PFNLayer
        else:
            # default preprocess
            assert num_voxels is not None, "`num_voxels` can not be None."
            features = self._extend_dim(features, num_voxels, coors)
            features = self._extract_feature(features) #PFNLayer
        return features


class PFNLayer(nn.Module):
    def __init__(
    ...
    )
    def forward(self, inputs: torch.Tensor):
        ...
        print('input:',inputs[0].size)
        x = self.linear(inputs)    #对应改动2
        x = self.norm(x)
        x = self.relu(x)
        x_max = self.max_pool(x)  # 对应改动3 (1, C, P, 1) 
        x_max = x_max.permute(0, 3, 2, 1)  # (1, 1, P, C)
        return x_max

PointPillarScatter-
该层实现伪图像转换的最后一个步骤。为了获得伪图片特征,将 P 转化为(W, H),由于预先设定pillar最大值以及去除了一些空pillar,因此P<H*W,最终可以通过映射获得形如(C, H, W) 的伪图像。

对应代码: hat/models/task_modules/lidar/pillar_encoder.py

class PointPillarScatter(nn.Module):
    ...
    def forward(
        ...
        ):
         #input_shape=(coors_range[3:] - coors_range[:3]) / voxel_size 
         #input_shape (432, 496, 1)
         self.nx = input_shape[0]  
         self.ny = input_shape[1]
         if self.use_horizon_pillar_scatter: #对应改动4
             P, C = voxel_features.size(2), voxel_features.size(3)
             voxel_features = voxel_features.reshape(P, C)
             out_shape = (batch_size, self.nchannels, self.ny, self.nx)
             #(P, C)-->(batch,C,H,W)
             batch_canvas = point_pillars_scatter( 
                 voxel_features, coords, out_shape
             )
         else:
             ...
         return batch_canvas

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

def _point_pillars_scatter(
    voxel_features: Tensor, coords: Tensor, output_shape: List[int]
) -> Tensor:
    ...
    canvas = torch.zeros(
        batch_size * hight * width,
        channel_dim,
        dtype=voxel_features.dtype,
        device=voxel_features.device,
    )
    index = (
        coords[:, 0] * (hight * width) + coords[:, -2] * width + coords[:, -1]
    )
    canvas[index] = voxel_features
    return canvas.reshape(batch_size, hight, width, channel_dim).permute(
        0, 3, 1, 2
    )

SequentialBottleNeck-
该模型的backbone用是SequentialBottleNeck,使用多个 Conv2D + BN + ReLU 的结构将特征进行融合处理,通过多个卷积和反卷积的组合,最后在dim=1维做concat。RPN结构见下图:

对应代码:hat/models/necks/sequential_bottleneck.py

class SequentialBottleNeck(nn.Module):
    def __init__(
        self,
        ...
    ):
    ...
        for i, layer_num in enumerate(self._layer_nums):
            block, num_out_filters = make_layer(
            ...
            )
            blocks.append(block)
            if i - self._upsample_start_idx >= 0:
                ...
                    deblock = self._make_deblock(
                        num_out_filters, i, stride, True, use_tconv
                    )
                ...
                deblocks.append(deblock)
        self.blocks = nn.ModuleList(blocks)
        self.deblocks = nn.ModuleList(deblocks)
        ...
    
    def forward(self, x: torch.Tensor):
        ...
        for i in range(len(self.blocks)):
            x = self.blocks[i](x)
            if i - self._upsample_start_idx >= 0:
                ups.append(self.deblocks[i - self._upsample_start_idx](x))
        if len(ups) > 0:
            ...
            x = self.cat.cat(ups, dim=1)
        return x

Detection Head-
pointpillars模型 head 层的输出为box_preds, cls_preds, dir_preds。对应代码路径为:-
hat/models/task_modules/pointpillars/head.py

class PointPillarHead(nn.Module):
    def __init__(
        self,
        ...
    ):
    ...
    self.conv_box = nn.Conv2d(in_channels, num_box, 1) #bbox head layer
    self.conv_cls = nn.Conv2d(in_channels, num_cls, 1)#cls head layer
    self.conv_dir = nn.Conv2d(in_channels, num_dir, 1)#direction head layer
    ...
    def forward(self, x):
        box_preds = self.conv_box(x)
        cls_preds = self.conv_cls(x)
        if self.use_direction_classifier:
            dir_preds=self.conv_dir(x)
        ...
        return box_preds, cls_preds, dir_preds

PointPillars Loss-

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

class PointPillarsLoss(nn.Module):
    def __init__(
        self,
        ...
    ):
    def forward(
    ...
    ):
        ...
        cls_loss_reduced, cls_pos_loss, cls_neg_loss = self.get_cls_loss(cls_preds, box_cls_labels)
        loc_loss_reduced, dir_loss_reduced = self.get_box_reg_loss(... )
        loss = loc_loss_reduced + cls_loss_reduced + dir_loss_reduced
        loss_dict = {
            "loss": loss,
            "cls_pos_loss": cls_pos_loss.detach().cpu(),
            "cls_neg_loss": cls_neg_loss.detach().cpu(),
            "dir_loss_reduced": dir_loss_reduced.detach().cpu(),
            "cls_loss_reduced": cls_loss_reduced.detach().cpu().mean(),
            "loc_loss_reduced": loc_loss_reduced.detach().cpu().mean(),
        }

        return loss_dict

前/后处理-

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下,其结构为:-

└── horizon_model_train_sample
    ├── scripts    
        ├── configs            #配置文件
        `── tools              #工具及运行脚本

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

拉取docker环境

docker pull openexplorer/ai_toolchain_ubuntu_20_j5_gpu: {version}
#启动容器,具体参数可根据实际需求配置
#-v 用于将本地的路径挂载到 docker 路径下
nvidia-docker run -it --shm-size="15g" -v `pwd`:/open_explorer openexplorer/ai_toolchain_ubuntu_20_j5_gpu: {version}

如需本地离线安装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个文件后,解压并按照如下方式组织文件夹结构:

├── tmp_data
│   ├── kitti3d
│   │   ├── testing
│   │   │   ├── calib
│   │   │   ├── image_2
│   │   │   ├── velodyne
│   │   ├── training
│   │   │   ├── calib
│   │   │   ├── image_2
│   │   │   ├── label_2
│   │   │   ├── velodyne

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

mkdir ./tmp_data/kitti3d/ImageSets
# 从社区下载数据集划分文件
wget -c  https://raw.githubusercontent.com/traveller59/second.pytorch/master/second/data/ImageSets/test.txt --no-check-certificate --content-disposition -O ./tmp_data/kitti3d/ImageSets/test.txt
wget -c  https://raw.githubusercontent.com/traveller59/second.pytorch/master/second/data/ImageSets/train.txt --no-check-certificate --content-disposition -O ./tmp_data/kitti3d/ImageSets/train.txt
wget -c  https://raw.githubusercontent.com/traveller59/second.pytorch/master/second/data/ImageSets/val.txt --no-check-certificate --content-disposition -O ./tmp_data/kitti3d/ImageSets/val.txt
wget -c  https://raw.githubusercontent.com/traveller59/second.pytorch/master/second/data/ImageSets/trainval.txt --no-check-certificate --content-disposition -O ./tmp_data/kitti3d/ImageSets/trainval.txt
#将原始数据转化为所需的format
python3 tools/create_data.py --dataset "kitti3d" --root-dir "./tmp_data/kitti3d"

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

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

├── tmp_data
│   ├──── kitti3d
│   │   ├── ImageSets
│   │   │   ├── test.txt
│   │   │   ├── train.txt
│   │   │   ├── trainval.txt
│   │   │   ├── val.txt
│   │   ├── testing
│   │   │   ├── calib
│   │   │   ├── image_2
│   │   │   ├── velodyne
│   │   │   ├── velodyne_reduced        # 新生成的 velodyne_reduced
│   │   ├── training
│   │   │   ├── calib
│   │   │   ├── image_2
│   │   │   ├── label_2
│   │   │   ├── velodyne
│   │   │   ├── velodyne_reduced        # 新生成的 velodyne_reduced
│   │   ├── kitti3d_gt_database           # 新生成的 kitti_gt_database
│   │   │   ├── xxxxx.bin
│   │   ├── kitti3d_infos_train.pkl       # 新生成的 kitti_infos_train.pkl
│   │   ├── kitti3d_infos_val.pkl         # 新生成的 kitti_infos_val.pkl
│   │   ├── kitti3d_dbinfos_train.pkl     # 新生成的 kitti_dbinfos_train.pkl
│   │   ├── kitti3d_infos_test.pkl        # 新生成的 kitti_infos_test.pkl
│   │   ├── kitti3d_infos_trainval.pkl    # 新生成的 kitti_infos_trainval.pkl

3.1.3 数据打包

#pack train_Set
python3 tools/datasets/kitti3d_packer.py --src-data-dir ./tmp_data/kitti3d/ --target-data-dir ./tmp_data/kitti3d --split-name train --pack-type lmdb
#pack test_Set
python3 tools/datasets/kitti3d_packer.py --src-data-dir ./tmp_data/kitti3d/ --target-data-dir ./tmp_data/kitti3d --split-name val --pack-type lmdb

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

├── tmp_data
│   ├──── kitti3d
│   │   ├── train_lmdb       # 新生成的 lmdb
│   │   ├── val_lmdb
│   │   ├── ImageSets
│   │   │   ├── test.txt
│   │   │   ├── train.txt
│   │   │   ├── trainval.txt
│   │   │   ├── val.txt
│   │   ├── testing
│   │   │   ├── calib
│   │   │   ├── image_2
│   │   │   ├── velodyne
│   │   │   ├── velodyne_reduced
│   │   ├── training
│   │   │   ├── calib
│   │   │   ├── image_2
│   │   │   ├── label_2
│   │   │   ├── velodyne
│   │   │   ├── velodyne_reduced
│   │   ├── kitti3d_gt_database
│   │   │   ├── xxxxx.bin
│   │   ├── kitti3d_infos_train.pkl
│   │   ├── kitti3d_infos_val.pkl
│   │   ├── kitti3d_dbinfos_train.pkl
│   │   ├── kitti3d_infos_test.pkl
│   │   ├── kitti3d_infos_trainval.pkl

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路径
  • infer_cfg:指定模型输入,在infer.py脚本使用时需配置;

3.2 浮点模型训练-

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

python3 tools/train.py --stage float --config configs/detection/pointpillars/pointpillars_kitti_car.py

3.3 浮点模型精度验证-

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

python3 tools/predict.py --stage float --config configs/detection/pointpillars/pointpillars_kitti_car.py

4 模型量化和编译-


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

4.1 Calibration-

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

python3 tools/train.py --stage calibration --config configs/detection/pointpillars/pointpillars_kitti_car.py

4.2 Calibration 模型精度验证-

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

python3 tools/predict.py --config configs/detection/pointpillars/pointpillars_kitti_car.py --stage calibration

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

4.3 量化模型训练-

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

python3 tools/train.py --stage qat --config configs/detection/pointpillars/pointpillars_kitti_car.py

4.4 量化模型精度验证-

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

#qat模型精度验证
python3 tools/predict.py --stage qat--config configs/detection/pointpillars/pointpillars_kitti_car.py
#quantize模型精度验证
python3 tools/predict.py --stage int_infer --config configs/detection/pointpillars/pointpillars_kitti_car.py

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

4.5 仿真上板精度验证-

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

python3 tools/align_bpu_validation.py --config configs/detection/pointpillars/pointpillars_kitti_car.py

4.6 量化模型编译-

在训练完成之后,可以使用compile的工具用来将量化模型编译成可以上板运行的hbm文件,同时该工具也能预估在BPU上的运行性能,可以采用以下脚本:

python3 tools/compile_perf.py --config configs/detection/pointpillars/pointpillars_kitti_car.py --out-dir ./ --opt 3

opt为优化等级,取值范围为0~3,数字越大优化等级越高,运行时间越长;-
compile_perf脚本将生成.html文件和.hbm文件(compile文件目录下),.html文件为BPU上的运行性能,.hbm文件为上板实测文件。

5 其他工具-


5.1 结果可视化-

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

python3 tools/infer.py --config configs/detection/pointpillars/pointpillars_kitti_car.py --save-path ./

需在config文件中配置infer_cfg字段。

可视化结果将会在save-path路径下输出。

6 板端部署-


6.1 上板性能实测-

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

hrt_model_exec perf --model_file {model}.hbm \
                    --input_file {lidar_data}.bin \
                    --thread_num 8 \
                    --core_id 0 \
                    --frame_count 2000 \
                    --profile_path '.'

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

6.2 AIBenchmark示例-

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

可在板端使用以下命令执行做模型评测:

#性能数据
sh fps.sh
#单帧延迟数据
sh latency.sh

如果要进行精度评测,请参考开发者社区J5算法工具链产品手册-AIBenchmark示例精度评测进行数据的准备和模型的推理。

相关链接:-

地平线pointpillars参考算法FAQ-

你好,J5的OE包提供了PointPillars训练示例,请问J3的OE包有提供PointPillars训练示例吗?如何在J3上部署PointPillars模型?

您好,请问J3是否支持PointPillar算法,在官方链接里有相关的说明: https://developer.horizon.cc/api/v1/fileData/horizon\_xj3\_open\_explorer\_cn\_doc/hat/source/examples/pointpillars.html;但是在释放的OE包里,并没有找到完整例程,在v2.6.2b 版本里有找到相关的config, 但是其中deploy_model里隐去了preprocess和backbone,导致最后在C++部署的例程里无法进行方便地部署,请确认J3是否支持?在哪个版本下支持? 可否提供链接?谢谢。

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

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

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

配置里

db_sampler

{

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

}

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

??

pkl是python3 tools/create_data.py 脚本生成的

python3 tools/create_data.py --dataset "kitti3d" --root-dir "./tmp_data/kitti3d"

HAT是python包,可以:ls /usr/local/lib/python3.6/site-packages/hat/models/task_modules/pointpillars/-
根据docker版本路径会有些微不同

horizon_plugin_pytorch/nn/quantized/functional_impl/_voxelization文件夹的位置在usr/local/lib64/python3.6(python3.8)/site-packages/horizon_plugin_pytorch目录下

您好,可以在config文件中添加onnx_cfg参数组 来导出:-
导出 float onnx,config添加:

onnx_cfg = dict( model=deploy_model, stage="float", inputs=deploy_inputs, model_convert_pipeline=dict( type="ModelConvertPipeline", converters=[ dict( type="LoadCheckpoint", checkpoint_path=os.path.join( ckpt_dir, "float-checkpoint-best.pth.tar"                ),            ),        ],    ),)

使用以下命令:

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

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

好的,找到了,请问create_data.py有支持nuscenes,我现在拿到的版本只有kitti的

nuscenes不需要create_data,另外我们即将发布centerpoint模型是基于nuscenes的。-

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

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

谢谢。