如何让点云3D检测模型在征程5上部署性能更佳?以 PointPillars 模型为例的优化探索
2023/12/20

地平线征程5
地平线“征程5”是专为高阶智能驾驶打造的智能芯片,搭载地平线第三代架构BPU--贝叶斯(Bayes),算力可达128TOPS,是率先实现前装量产的国产百TOPS级大算力智能芯片。基于征程5开发的高等级自动驾驶方案可实现ADAS功能、高速导航智能驾驶、城区导航智能驾驶和智慧泊车的全场景覆盖。针对自动驾驶实际工况,Bayes结合突破性的AI加速计算技术,通过灵活配置的访存计算,极大的优化内存占用及访存,将并行计算发挥到极致! |
简介
在自动驾驶应用中,除了在2D图像中检测目标之外,还必须在3D空间中检测某些目标的类别,如汽车、行人、自行车等。3D点云可以提供一种精确、高空间维度、高分辨率的数据,可以弥补对3D空间的距离信息,使得系统能够更准确地理解周围环境的立体结构,更精确地检测和跟踪物体;并且点云的采集在各种环境条件下都具有良好的适应性,不受光照、天气和光线等因素的限制,相比之下,光学传感器(如摄像头)在恶劣天气或低光照条件下可能性能下降,而点云的采集能够在这些情况下保持相对稳定的性能,可以为车辆提供了关键的环境感知和障碍物检测能力,为自动驾驶车辆的感知和决策提供了关键数据,是一个不可或缺的组成部分,是实现安全、智能自动驾驶的关键技术之一。
随着深度学习架构的进步逐渐出现了许多基于3D点云的目标检测器。Pointpillars 提出了一种改进版本的点云表征方法Pillar,可以将点云转换成伪图像,进而通过2D卷积实现基于3D点云的目标检测,是一个能够平衡检测速度和检测精度的检测模型,是最常用于点云推理的模型之一,目前地平线的参考算法已帮助多家用户完成点云模型的部署落地。本文即对如何在地平线征程5芯片上高效部署基于3D点云的PointPillars 检测模型进行介绍。
部署优化
在部署优化之前,首先明确一下 PointPillars 模型的基本结构,然后进一步讨论优化方向和优化思路。
PointPillars 的最大贡献是在 VoxelNet 中 Voxel 的基础上提出了一种改进版本的点云表征方法 Pillar ,可以将点云转换成伪图像,进而通过2D卷积实现目标检测。PointPillars 整个网络结构分为三个部分:
• Pillar Feature Net:将输入的点云转换为稀疏的Pseudo image;
• Backbone:处理Pseudo image得到高层的特征;
• Detection Head:检测和回归3D框。

量化精度优化
在前面有提到,点云数据具有不均匀的特征,这种分布特点的数据使用PTQ量化方式很大可能会有量化精度问题,因此在 PointPillars 的量化过程中,我们使用 Calibration+QAT 的量化方式来保证点云模型的量化精度。需要提到的是地平线的calibration对于大部分模型就可以达到预期的量化精度,少量模型在较小的QAT训练代价下可以达到量化精度。由于 PointPillars 中所有算子的量化在征程5平台上是完全支持的,得到初版的量化精度是非常简单的。
QAT量化方式是根据数据的分布选取量化系数,将fp32的数据截断到int8范围,由于点云数据分布不均匀,其表现在部分数据(点云坐标)的数值范围较大,部分(点到中心的距离)数值范围较小,这种情况对量化是很不友好的,因此在量化训练中,精度掉接近于 7 个点;为了使得数据分布处于均匀范围内,一般都会做归一化处理(归一化对浮点的精度也是有利的),因此,为了提升量化精度,我们增加了对点云特征的归一化处理。
Pythondef normalize(self, features, norm_dims, norm_range): # 做归一化 start = norm_range[norm_dims] end = norm_range[norm_dims + len(norm_range) // 2] features[:, :, norm_dims] = features[:, :, norm_dims] - start features[:, :, norm_dims] = features[:, :, norm_dims] / (end - start) return features
经归一化处理后,量化精度损失在 1% 以内。
部署性能优化
在 PointPillars 三个部分结构中:
• Backbone 和 DetectionHead 中的算子均为普通的 Conv2d、ConvTranspose2d、BarchNorm2d、ReLU 等常规操作,且并非PointPillars部署的性能瓶颈。
• 而从输入点云数据至 PillarFeatureNet 生成 Pseudo Image Feature 的这一过程中(见下图),涉及到高密度点云数据 Pillar 化 (Voxelization)、点云数据维度扩充增强(VoxelAugment)、点云特征提取(PFNLayer)、特征数据重排布(PillarScatter)等操作,逻辑运算量大且数据存取操作较多,在整个部署耗时中占了很大的比重,是点云模型部署着重优化的内容。
从输入点云数据到生成 Pseudo Image Feature 的整体流程如下:

接下来,我们展开对各个部分的优化方法。
前处理优化
前处理包括 Voxelization 操作和特征的扩维操作-VoxelAugment。我们将分析公版的实现在J5上部署的困难点,然后基于困难点介绍优化方式以及地平线对点云前处理的部署优化。
Voxelization:体素化,是把三维空间中的点云数据转换到体素(voxel,即三维空间中的网格)。 PointPillars中的 Pillars 可以看作是特殊( z 轴没有空间限制)的 voxel,为了与社区名称和代码实现名称相统一,我们下文统一称为 Voxelization、voxel。 |
Voxelization部署分析
假设用 (x, y, z, r) 表示点云数据中的一个点,其中(x, y, z) 为坐标,r 为点云的反射强度。
PointPillars 中的 Pillar 化(一种特殊的 Voxelization 操作,是把 z 轴看作一个整体,把三维空间离散化为 x-y 平面中均匀间隔的网格)流程如下:

从上图可以看出,在 Voxelization 过程中,需要依次、逐个对密集点云中的每个点进行判断,并将其划分入对应的 voxel 中,且每个 voxel 都需要存储点云中对应区域的信息。随着点云密度的增加,处理的体素数量也相应增多,导致需要更多的计算和内存资源,其计算复杂度可能导致较长的部署时间。
VoxelAugment部署分析
继 voxelization 中把每个点云 point 划分到各个 pillar 中之后,公版 PointPillars 中对点云 point 做了特征增强,即前文提到的把每个 4 维点云 point 数据 (x, y, z, r) 根据点到中心的距离扩充到了 9 维 (x, y, z, r, xc, yc, zc, xp, yp) 。然而,这样的处理方式,无论是对量化精度还是部署性能方面,都存在一些不足:
• 量化精度方面:前文已提到,这里不再赘述;
• 部署性能方面: 在从 4 维扩充到 9 维时,对中心点距离的求解,增加了计算量和相应的耗时。而在我们的实验中发现,增加的后 5 维数据,实际对模型的浮点精度影响很小。
针对以上两个问题,下面介绍地平线的优化方法。
VoxelAugment优化
根据实验,原9维的方案会导致耗时增加,精度收益不大,因此在我们的改进方法中,点云 point 仅使用前4维 (x, y, z, r) ,并结合前文对量化精度的优化,做了归一化处理:
Python
# 伪代码,仅展示处理流程
def _extend_dim(self, features, num_voxels, coors):
# 直接取 (x, y, z, r) 四维
features[:, :, :3] = features[:, :, :3] - self.pc_range[:3]
# 对 x, y, z 做归一化
features = normalize(feature, norm_dims=[0,1,2], norm_range=self.pc_range)
return features
在优化后,该部分耗时减少了 4ms,精度上影响较小。
Voxelization优化
对于点云的 voxelization 耗时问题,地平线提供了多种部署方式(包括编译器、ARM、DSP)。在 PointPillars 模型中,该部分被编译进模型中,为编译器优化实现。在使用上,plugin提供了外部接口,通过调用该算子就可以实现编译器的加速。
使用方法:
Pythonfrom horizon_plugin_pytorch.nn.quantized.functional_impl import ( _voxelization as horizon_voxelization,)voxels, coors, num_points_per_voxel = horizon_voxelization( points, voxel_size=self.voxel_size.to(device), pc_range=self.pc_range.to(device), max_points_per_voxel=self.max_points_in_voxel, max_voxels=max_voxels, use_max=is_deploy,)
ARM和DSP的实现见AIBenchmark
前处理集成和部署
为了便于量化和部署,我们在 horizon_plugin_pytorch 和编译器中实现了 point_pillars_preprocess 算子集成了Voxelization 和 VoxelAugment操作。horizon_plugin_pytorch 中 point_pillars_preprocess 算子的调用方式为:
Python
from horizon_plugin_pytorch.nn.functional import point_pillars_preprocess
voxel_features, coords = point_pillars_preprocess(
points_lst,
self.pc_range.to(device),
self.voxel_size.to(device),
self.max_voxels_num,
self.max_points_in_voxel,
is_deploy,
norm_range=self.norm_range.to(device),
norm_dims=self.norm_dims.to(device),
)
在 AIBenchmark 中对点云前处理也提供了ARM和DSP实现的方式。DSP具有强大的并行计算能力,能够同时处理多个数据,且具有快速读写内存的特点,利用 DSP 可以有效加速 Voxelization 过程,提高实时性能。例如,在 8.3 万点云数据量时,经 DSP 优化后,前处理耗时由 17.11 ms 降低至 6.28 ms,性能提升一倍。具体数据可见实验结果章节。
特征提取层PFNLayer
PointPillars 的 PFNLayer 做用是将每个包含D维特征的点(由前文可知,公版PointPillars 中 D=9,地平线参考模型中 D=4)用一个 Linear + BatchNorm1d + ReLU + max 的组合来进行特征提取,生成(C,P,N) 的张量。
而地平线征程5最早针对的是以CNN为基础的图像处理,在编译器内部4d-Tensor是最高效的支持方式。如果不是4d-Tensor的话,编译器内部会主动转成4d(某些维度为1)来做,会多了很多无效的计算。我们可以使用常规的4维算子替换原来任意维度的设置,避免不必要的冗余计算。常见的替换方式如下,中间配合任意维度的reshape,permute来完成等价替换。因此,我们将公版中的 Linear + BatchNorm1d + ReLU + max 分别做了如下替换:
N dims | 4dims |
nn.Linear | nn.Conv2d |
nn.BacthNorm1d | nn.BacthNorm2d |
torch.max | nn.MaxPool2d |
关键代码
Python
# 原来的方式
class PFNLayer(nn.Module):
def __init__():
self.linear = nn.Linear(in_channels, self.units, bias=False)
self.norm = nn.BatchNorm1d(self.units, **self.bn_kwargs)
def forward(self, inputs: torch.Tensor):
x = self.linear(inputs)
x = (
self.norm(x.permute(0, 2, 1).contiguous())
.permute(0, 2, 1)
.contiguous()
)
x = F.relu(x)
x_max = torch.max(x, dim=1, keepdim=True)[0]
return x_max
# 更改后, 4d 算子的使用方式
class PFNLayer(nn.Module):
def __init__():
self.linear = nn.Conv2d(in_channels, self.units, kernel_size=1, bias=False)
self.norm = nn.BatchNorm2d(self.units, **bn_kwargs)
self.relu = nn.ReLU(inplace=True)
self.max_pool = nn.MaxPool2d(kernel_size=pool_size, stride=pool_size)
def forward(self, inputs: torch.Tensor):
x = self.linear(inputs)
x = self.norm(x)
x = self.relu(x)
x_max = self.max_pool(x)
x_max = x_max.permute(0, 3, 2, 1).contiguous() # (1, 1, P, C)
return x_max
伪图像化
PillarScatter 是实现伪图像转换的最后一个步骤,该部分将(1, 1, P, C) 的特征映射获得形如(C, H, W) 的伪图像。为了便于量化训练和上板推理优化,我们在 horizon_plugin_pytorch 和编译器中均实现了 point_pillars_scatter 算子。该算子由编译器内部完成,用户不需要感知。
horizon_plugin_pytorch 中 point_pillars_scatter 算子的调用方式为:
Python
from horizon_plugin_pytorch.nn.functional import point_pillars_scatter
pseudo_image_feature = point_pillars_scatter(voxel_features, coords, out_shape)
优化总结
相比于公版 PointPillars ,我们主要做了如下更改:
• voxelization:为了便于量化和推理优化,horizon-plugin-pytorch 和编译器做了优化实现,并且为了进一步提升推理性能,我们也提供了 DSP实现,可以有效地加速点云处理;
• point encoder(VoxelAugment):仅使用4维(公版9维),并做归一化处理,在浮点精度与公版相比几乎不掉点的前提下,提高了量化精度,并减少推理耗时 4ms;
• PFNLayer:使用 Conv2d + BatchNorm2d + ReLU + MaxPool2d,替换原有的 Linear + BatchNorm1d + ReLU + torch.max,优化推理性能;
• PillarScatter:horizon_plugin_pytorch 和编译器中内部集成实现,便于模型量化和推理优化。
实验结果
1. PointPillars 在征程5平台性能数据
数据集 | Kitti3D |
点云量 | 15W |
点云范围 | [0, -39.68, -3, 69.12, 39.68, 1] |
Voxel size | [0.16, 0.16, 4.0] |
最大点数 | 100 |
最大pillars数 | 12000 |
FPS | 116 |
latency | 32.8ms(infer)+ 2.6ms(后处理) |
量化精度(浮/定) | 77.32/76.76 |
latency数据中infer耗时为点云前处理和模型部分的总耗时。
2. DSP优化点云前处理在征程5平台性能数据
地平线 Albenchmark 中提供了点云前处理的DSP实现,可以有效地加速点云处理。本实验选取多组点云数据输入,通过对比前处理运行时长(latency)判断DSP的加速效果。
模型 | 有效数据 | 原始方案 | DSP优化 |
PointPillars | 83165 | 17.11 | 6.28 |
9896 | 5.65 | 4.46 | |
68535 | 14.79 | 6.06 | |
71445 | 15.49 | 6.00 |
有效数据:为在点云配置范围内的点云数,即参加实际运算的点云。
从实验数据可以看出,DSP的并行计算的加速效果在点云处理上发挥显著,特别是在计算量大的情况下优化效率更高。
3. 点云模型优化通用建议
• 使用已封装的算子和BPU支持的算子(见附录算子支持列表)。推荐使用地平线实现的 point_pillars_scatter、point_pillars_preprocess 算子,该算子由编译器针对硬件特点做了优化,因此建议在模型搭建阶段使用已经封装好的算子。
• 板端部署时(原始方案),padding数据设置为-100。板端做数据处理时建议将padding数据配置为-100,遇到[-100,-100,-100,-100]数据时会跳出循环,减少padding数据的遍历。
• 对于点云数据,pillars_num较大,将大数据放到W维度提升计算效率。基于地平线硬件对齐规则,未对齐的数据会被padding导致算力浪费,为了避免此情况,建议将大数据放到W维度。
• 若前处理存在性能瓶颈,尝试DSP方案。在工程部署中若发生性能瓶颈,可以考虑将点云处理放置DSP处理,合理利用和分配资源。
• 对输入数据做归一化,更有利于量化。点云分布不均匀,在量化上大多数需要使用QAT量化,更好的数据分布对量化也会更友好。
总结
本文通过对 PointPillars 在地平线征程5上量化部署的优化,使得模型在该平台上用低于1%的量化精度损失,得到latency为32.8ms的部署性能,特别是点云的前处理,提供了多种部署方式以及优化数据。同时,通过 PointPillars 的部署经验,可以推广到所有的点云模型部署,最后给出点云模型在征程5上高效部署的优化建议。
附录

算法包获取

使用文档

算子支持列表
.
分享文章
欢迎订阅地平线相关资讯,您可以随时取消订阅。
感谢您的订阅, 我们会第一时间推送地平线最新活动与资讯到您邮箱

