自动驾驶技术落地的重要方向正变为多任务感知模型,然而,行业一直面临着挑战,那便是怎样把检测、建图、占用预测等多个任务高效布置在车规级芯片上。地平线征程6平台上面的SparseBevFusionMultitaskOE模型,凭借优化多任务共享架构以及量化策略,在28毫秒内达成了三大核心感知任务,给多任务模型的嵌入式部署提供了能复用的参考路径。
SparseBevFusionMultitaskOE模型的关键想法是,借助稀疏关键点投射回去到相机空间里来开展特征采样,这样的设计致使动态检测、静态要素检测以及占用格预测这三个任务,能够共同启用图像编码器的骨干网络(Backbone)与颈部网络(Neck)。共享结构极大程度地削减了重复计算量,三个任务头,也就是Detection Head、Online Mapping Head、Occupancy Head,它们各自负责相应的任务输出。在征程6之上,该模型分别参照了Sparse4D、MapTR以及FlashOcc这三个主流单任务模型的优化经验,达成了多任务的有效融合。
选用用于模型训练的是NuScenes开源数据集,该数据集当中同时涵盖了动态目标、静态地图元素以及占用格,这三种任务的标注信息。在具体实现的过程中,采用NuscenesSparseMapDataset格式的数据集,它能够对三个任务同时开展监督训练。因为动态检测头需要借助时序信息,所以数据加载器特意采用了DistStreamBatchSampler,以此确保数据能够按照时序顺序返回。在此种设计之下,模型于训练阶段能够学习到连续帧之间的运动规律,这为动态目标检测的时序特征提取奠定了基础。
模型于配置文件(configs/bev/bev_sparse_det_maptr_flashocc_henet_tinym_nuscenes.py)里,以字典形式对各个任务头的结构予以定义。开发者能够借由enable_xx_head参数,灵活地挑选需要合入的任务组合,在构建OrderedDict之后,将其传入task_heads字段。这样的注册机制,极大程度地提升了模型的可扩展性,准许依据不同的部署需求,迅速调整任务组合。代码之中,另外预留了lidar_feature接口,目的在于兼容未来有可能出现的多模态融合方案,当不存在使用激光雷达网络的情况时,此参数会自动被设置成None。
在那个量化部署的阶段之时,模型采用的是HistogramObserver校准方式,此方式在OE 3.7.0以及后续版本当中,已经被证实精度是要比MSEObserver更为优越的。校准所用到的数据直接采用训练集,校准的步数设定为50步,并且没有去进行量化感知训练(QAT)这一操作。量化配置借助q_template得以实现,它分为全局配置、ModuleNameTemplate和SensitivityTemplate这三级。对于有着固定物理范围的算子,像坐标变换层这样的,预先配置了固定尺度,也就是fix-scale;对于敏感度比较高的算子,是依据调试结果按照比例配置int16精度。这种分层量化策略在确保精度的情况下,有效地控制了量化损失。
det_head = dict(
type="SparseBEVOEHead",
enable_dn=True,
level_index=[2],
cls_threshold_to_reg=0.05,
instance_bank=dict(
type="MemoryBankOE",
...
)
模型依据征程6芯片的硬件特点,展开了针对性的部署优化。最终于征程6M平台里,整个多任务模型端到端的延迟被控制在28毫秒之内。在优化进程中,团队借鉴了单任务模型于征程6上的部署经验,对已知的敏感算子层作了提前配置。针对量化后出现的精度掉点状况,开发人员参照地平线给出的精度调优工具指南,经逐层剖析定位了问题算子,且针对性地配置了更高精度或者手动调整了量化参数。
task_heads = OrderedDict()
if enable_det_head:
task_heads["det"] = det_head
if enable_om_head:
task_heads["om"] = om_head
if enable_occ_head:
task_heads["occ"] = occ_head
model = dict(
type="SparseBevFusionMultitaskOE",
compiler_model=False,
对SparseBevFusionMultitaskOE模型展开部署实践,证实了多任务模型于车规级芯片上具备可行性,相较于单任务模型的单独部署,多任务方案借由共享特征提取网络,大幅削减了总体计算开销,当前,模型里的稀疏动态目标检测部分一直处于持续优化状态,后续版本会进一步提高检测精度,这种把成熟单任务模型予以多任务融合的部署思路,给其他复杂感知模型在征程6上的落地供给了可复用的方法论。
def forward_single_head(
self, head, feature_maps, data, lidar_feature, compiler_model
):
if isinstance(head, (SparseBEVOEHead, FlashOccHead)):
return head(
feature_maps=feature_maps,
metas=data,
lidar_feature=lidar_feature,
compiler_model=compiler_model,
)
时至今日,于自动驾驶感知模型渐趋复杂的情形下,当芯片进行部署时,针对多任务模型而言,你觉得其最大的技术难点究竟是算力分配,还是精度平衡,又或是多任务彼此间的特征冲突呢?欢迎于评论区分享你的看法。
calibration_data_loader = copy.deepcopy(data_loader)
calibration_data_loader["dataset"]["transforms"] = val_data_loader["dataset"][
"transforms"
]
calibration_batch_processor = copy.deepcopy(val_batch_processor)
calibration_step = 50
calibration_qconfig_setter = QconfigSetter(
reference_qconfig=get_qconfig( # 1. 主要用于获取 observer
# observer=(observer_v2.MSEObserver)
observer=(observer_v2.HistogramObserver)

相关标签: # SparseBevFusionMultitaskOE # 地平线征程6 # 模型部署 # 多任务感知 # 量化部署