专栏算法工具链地平线3D目标检测 bev_sparse 参考算法-V2.0

地平线3D目标检测 bev_sparse 参考算法-V2.0

芯链情报局2024-12-25
1461
3

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

简介

在自动驾驶视觉感知系统中,为了获得环绕车辆范围的感知结果,通常需要融合多摄像头的感知结果。目前更加主流的感知架构则是选择在特征层面进行多摄像头融合。其中比较有代表性的路线就是这两年很火的BEV方法,继Tesla Open AI Day公布其BEV感知算法之后,相关研究层出不穷,感知效果取得了显著提升,BEV也几乎成为了多传感器特征融合的代名词。但是,随着大家对BEV研究和部署的深入,BEV范式也逐渐暴露出来了一些缺陷:

  • 感知范围、感知精度、计算效率难平衡:从图像空间到BEV空间的转换,是稠密特征到稠密特征的重新排列组合,计算量比较大,与图像尺寸以及BEV 特征图尺寸成正相关。在大家常用的nuScenes 数据中,感知范围通常是长宽 [-50m, +50m] 的方形区域,然而在实际场景中,我们通常需要达到单向100m,甚至200m的感知距离。 若要保持BEV Grid 的分辨率不变,则需要大大增加BEV 特征图的尺寸,从而使得端上计算负担和带宽负担都过重;若保持BEV特征图的尺寸不变,则需要使用更粗的BEV Grid,感知精度就会下降。因此,在车端有限的算力条件下,BEV 方案通常难以实现远距离感知和高分辨率特征的平衡;

  • 无法直接完成图像域的2D感知任务:BEV 空间可以看作是压缩了高度信息的3D空间,这使得BEV范式的方法难以直接完成2D相关的任务,如标志牌和红绿灯检测等,感知系统中仍然要保留图像域的感知模型;

实际上,我们感兴趣的目标(如动态目标和车道线)在空间中的分布通常很稀疏,BEV范式中有大量的计算都被浪费了。因此,我们希望实现一个高性能高效率的长时序纯稀疏融合感知算法,一方面能加速2D->3D 的转换效率,另外一方面在图像空间直接捕获目标跨摄像头的关联关系更加容易,因为在2D->BEV的环节不可避免存在大量信息丢失,地平线提出了Sparse4D及其进化版本Sparse4D v2,从Query构建方式、特征采样方式、特征融合方式、时序融合方式等多个方面提升了模型的效果。

性能精度指标

模型信息

定点精度

J6E性能

模型

数据集

Input shape

backbone

num_anchor

NDS

mAP

FPS

Latency

SparseBevOE

Nuscenes

6x3x256x704

HENET

384

0.5424/0.53

0.4040

62

13.28ms

 

公版模型介绍

Sparse4D 采用了Encoder-Decoder 结构。其中Encoder包括image backbone和neck,用于对多视角图像进行特征提取,得到多视角多尺度特征图。同时会cache 历史帧的图像特征,用于在decoder 中提取时序特征;Decoder为多层级联形式,输入时序多尺度图像特征图和初始化instance,输出精细化后的instance,每层decoder包含self-attentiondeformable aggregationrefine module三个主要部分。

学习2D检测领域DETR改进的经验,我们也重新引入了Anchor的使用,并将待感知的目标定义为instance,每个instance主要由两个部分构成:

  1. Instance feature :目标的高维特征,在decoder 中不断由来自于图像特征的采样特征所更新;

  2. 3D Anchor :目标结构化的状态信息,比如3D检测中的目标3D框(x, y, z, w, l, h, yaw, vx, vy);公版通过kmeans 算法来对anchor 的中心点分布进行初始化;同时,在网络中会基于一个MLP网络来对anchor的结构化状态进行高维空间映射得到 Anchor Embed ? ,并与instance feature 相融合。

基于以上定义,通过初始化一系列instance,经过每一层decoder都会对instance 进行调整,包括instance feature的更新,和anchor的refine。基于每个instance 最终预测的bounding box。

地平线部署说明

公版sparse4d在J6上部署的改动点为:

  • resnet50替换为henet。

  • num_anchor和num_temp_instances降低。num_abchor 900num_anchor和num_temp_instances降低。num_abchor 900-->384;num_temp_instances 600384;num_temp_instances 600-->128。

  • 去除instance的update

  • get和cache对当前帧的anchor、feature 和temp帧做融合(cat)

  • 一阶段生成的featuremap只使用FPN的第二层(stride=16),非公版的使用4层。

  • DeformableFeatureAggregation中kps_generator直接使用offset(linear)生成,非公版的基于anchor生成。

  • RefinementModule对速度没有做refine计算,公版使用了。

下面将部署优化对应的改动点以及量化配置依次说明。

性能优化

改动点1:

backbone换为henet

 

改动点2

一阶段生成的featuremap只使用FPN的1层(公版使用4层),通过实验验证level_index=2(stride=16)时精度和性能平衡的更好。

 

/usr/local/lib/python3.10/dist-packages/hat/models/task_modules/sparsebevoe/head.py

改动点3:

  • DeformableFeatureAggregation中kps_generator直接使用offset(linear)生成,非公版的基于anchor生成。(公版的方式会导致延迟增加)。

/usr/local/lib/python3.10/dist-packages/hat/models/task_modules/sparsebevoe/det3d_blocks.pySparseBEVOEKeyPointsGenerator

改动点4:

RefinementModule的velocity没有refine。经过实验公版的vx的refine对精度影响较小,基于性能考虑去除该操作。

改动点5:

InstanceBankOE模块:

  • num_anchor数量降低(900num_anchor数量降低(900-->384),num_temp_instances数量降低(600384),num_temp_instances数量降低(600-->128)

  • update:取消原instance_bank的update

精度优化

浮点精度

改动点1

get中对当前帧的anchor和instance_feature融合temp_anchor 和temp_feature(num_temp=128)

改动点2 

  • cache时,仍使用topk(k=128)获取当前帧高得分的instance作为下一帧的输入

  • 新增融合上一帧的cache(memory_cache),最后返回num_memory个instance作为当前帧最终的Cache。cache=memory_cache+cache

cache_instance部分v1、v2均不量化!

量化精度

为量化精度保证,我们将以下的算子配置为int16或int32输出:

  • temp_interaction、interaction操作中对输出的instance_featuremap使用固定scale的int16量化

/usr/local/lib/python3.10/dist-packages/hat/models/task_modules/sparsebevoe/head.py

注:fix_Scale不同的数据集数据范围不同,需要根据私有数据集的数据范围固定,scale计算方式为:输入最大值的绝对值(比最大值稍大保证可覆盖)除以int16 或int8最大值

  • 获取instance的anchor时,对anchor的量化以及结合时序anchor的cat算子使用int16保障精度:

/usr/local/lib/python3.10/dist-packages/hat/models/task_modules/sparsebevoe/memory_bank.py


  • KeyPointsGenerator:key_points的生成中对offset、keypoints_add做int16量化。

/usr/local/lib/python3.10/dist-packages/hat/models/task_modules/sparsebevoe/det3d_blocks.py

  • RefinementModule:对中间的add层和输出层做int16和int32的输出(注意cache不能int32输出,还需输入给下一帧)

/usr/local/lib/python3.10/dist-packages/hat/models/task_modules/sparsebevoe/det3d_blocks.py

  • DeformableFeatureAggregation:对point做固定scale和int16量化。

/usr/local/lib/python3.10/dist-packages/hat/models/task_modules/sparsebevoe/blocks.py

注:fix_Scale不同的数据集数据范围不同,需要根据私有数据集的数据范围固定,scale计算方式为:输入最大值的绝对值(比最大值稍大保证可覆盖)除以int16 或int8最大值

总结与建议

部署建议:

  • 可以使用单层feature来做特征提取,根据精度和性能表现选择某层stride特征。

  • 根据实际情况配置anchor数,对anchor个数做合理裁剪,在精度影响较小的前提下提升性能。

  • 适当减轻模型,例如降低self_attn和cross_attn 输入维度,减少embedding_dim、num_points、decoder layer、num_head数量,选择对浮点精度影响较小的性能最优的配置组合。

  • 对points相关的计算(anchor_projection、project_points、key_points计算)建议开启int16和手动固定scale的方式。

  • 使用精度debug工具、敏感度分析工具来降低量化损失。

  • 若追求更高的性能,可以使用地平线征程6的高效backbone-henet。训练策略上对backbone单独配置较大的学习率

本文通过对SparseBevOE在地平线征程6上量化部署的优化,使得模型在该计算方案上得到latency为13ms的部署性能,同时,通过SparseBevOE的部署经验,可以推广到其他模型部署优化,例如包含使用稀疏BEV的模型部署。

附录

  1. 论文:https://arxiv.org/abs/2311.11722

  2. 公版代码:https://link.zhihu.com/?target=https%3A//github.com/linxuewu/Sparse4D

  3. 课程:https://www.shenlanxueyuan.com/open/course/210

  4. 知乎专栏:https://zhuanlan.zhihu.com/p/637096473

 

算法工具链
征程6官方教程
+1
评论3
0/1000
  • arco
    Lv.1

    666

    2024-12-26
    0
    0
  • 狂暴刷
    Lv.1

    有几个问题请教一下,

    1、为啥要取消instance_bank里面的update

    2、为啥要在instance_bank外增加一个memory_bank

    3、为啥sample code里面num_single_frame_decoder设置为0?这样的话没有单帧decoder不会影响性能吗?

    2025-06-04
    0
    0
  • 刃木
    Lv.1

    henet的输出channel和fpn的输入 channel对不上,按照原生的henet的话是不是fpn的输入维度需要改为 [64, 64, 128, 192, 384]

    2026-02-11
    0
    0