Bev Sparse 多任务模型训练
这篇教程主要是告诉大家如何利用HAT在数据集 nuscenes 上从头开始训练一个 BevSparseMultiTask 模型, 包括浮点、量化和定点模型。
该模型是一个bev多任务感知模型,包含感知三大任务的检测头:sparse动态检测头,sparse静态元素检测头和通用障碍物检测头。
训练流程
如果你只是想简单的把 BevSparseMultiTask 的模型训练起来,那么可以首先阅读一下这一章的内容。
和其他任务一样,对于所有的训练,评测任务,HAT统一采用 tools + config 的形式来完成。
在准备好原始数据集之后,可以通过下面的流程,方便地完成整个训练的流程。
数据集准备
这里以nuscense数据集为例,可以从 https://www.nuscenes.org/nuscenes 下载数据集, 对于Occupancy预测任务,还需要下载OCC的GT,可以从 https://github.com/CVPR2023-3D-Occupancy-Prediction/CVPR2023-3D-Occupancy-Prediction 下载数据集。 这里建议将下载好的数据集,解压到nuscense数据集文件夹中的 occ3d/gts 下。 同时,为了提升训练的速度,我们对原始的jpg格式的数据集做了一个打包,将其转换成lmdb格式的数据集。
上面这条命令会在 ./tmp_data/nuscenes/occ3d 下面生成 nuscenes_infos_train.pkl 和 nuscenes_infos_val.pkl 两个文件, 接下来执行下面命令进行打包:
上面这两条命令分别对应着转换训练数据集和验证数据集,打包完成之后,tmp_data目录下的文件结构应该如下所示:
train_lmdb 和 val_lmdb 就是打包之后的训练数据集和验证数据集,也是网络最终读取的数据集,meta中为评测脚本需要的初始化信息,具体信息是从nuscenes原始数据集中拷贝得来。
模型训练
数据集准备好之后,就可以开始训练浮点型的 BevSparseMultiTask 网络了。在网络训练开始之前,你可以使用以下命令先测试一下网络的计算量和参数数量:
如果你只是单纯的想启动这样的训练任务,只需要运行下面的命令就可以:
由于HAT算法包使用了一种巧妙的注册机制,使得每一个训练任务都可以按照这种train.py加上config配置文件的形式启动。 train.py是统一的训练脚本,与任务无关,我们需要训练什么样的任务、使用什么样的数据集以及训练相关的超参数设置都在指定的config配置文件里面。 config文件里面提供了模型构建、数据读取等关键的dict。
导出定点模型
完成量化训练后,便可以开始导出定点模型。可以通过下面命令来导出:
模型验证
模型训练完成之后,我们还可以验证训练出来的模型性能。由于我们提供了float, calibration, qat两阶段的训练过程,相应的我们可以验证这三个阶段训练出来的模型性能,只需要相应的运行以下三条命令即可:
同时,我们还提供了quantization模型的性能测试,只需要运行以下命令,但需要注意是必须要先导出hbir:
这个显示出来的精度才是最终的量化模型的真正精度,当然这个精度和qat验证阶段的精度应该是保持十分接近的。
模型推理和结果可视化
如果你希望可以看到训练出来的模型的可视化效果,我们的tools文件夹下面同样提供了可视化脚本,你只需要运行以下脚本即可:
定点模型检查和编译
在HAT中集成的量化训练工具链主要是为了地平线的计算平台准备的,因此,对于量化模型的检查和编译是必须的。 我们在HAT中提供了模型检查的接口,可以在定义好量化模型之后,先检查能否在 BPU 上正常运行:
在训练完成之后,可以使用 compile_perf_hbir 的工具用来将量化模型编译成可以上板运行的 hbm 文件,同时该工具也能预估在BPU上的运行性能,可以采用以下脚本:
训练细节
在这个说明中,我们对模型训练需要注意的一些事项进行说明,主要为 config 的一些相关设置。
模型构建
BevSparseMultiTask 模型包含动态,静态,通用障碍物三个任务头。其中动态任务选用的是 SparseBEVOEHead 。
静态任务选用的是 SparseMapPerceptionDecoder 。
通用障碍物任务选用的head是 FlashOccHead 。
三个任务的head和backbone一起构成了这个Bev多任务感知模型,model 在config中的定义为:
其中, model 下面的 type 表示定义的模型名称,剩余的变量表示模型的其他组成部分。这样定义模型的好处在于我们可以很方便的替换我们想要的结构。
训练脚本在启动之后,会调用 build_model 接口,将这样一个dict类型的model变成类型为 torch.nn.Module 类型的model。
数据增强
跟 model 的定义一样,数据增强的流程是通过在config配置文件中定义 data_loader 和 val_data_loader 这两个dict来实现的,分别对应着训练集和验证集的处理流程。
Nuscenes 数据集同时包含动态静态和通用障碍物的标注,我们可以在一个数据集上同时训练三个任务。
具体代码实现中,NuscenesBevDataset可以提供动态和occ的标注,NuscenesSparseMapDataset 继承了它, 可以同时提供动态,静态和occ的标注。
动态检测头用到了时序信息,所以 data_loader 采用了 DistStreamBatchSampler,确保数据按时序返回。
训练策略
为了训练一个精度高的模型,好的训练策略是必不可少的。对于每一个训练任务而言,相应的训练策略同样都定义在其中的config文件中,从 float_trainer 这个变量就可以看出来。
float_trainer 从大局上定义了我们的训练方式,包括使用多卡分布式训练(distributed_data_parallel_trainer),模型训练的epoch次数,以及优化器的选择。
同时 callbacks 中体现了模型在训练过程中使用到的小策略以及您想实现的操作,包括指数移动平均训练(ExponentialMovingAverage), 学习率的变换方式(CosineAnnealingLrUpdater),
在训练过程中验证模型的指标(Validation),以及保存(Checkpoint)模型的操作。当然,如果你有自己希望模型在训练过程中实现的操作,也可以按照这种dict的方式添加。
float_trainer 负责将整个训练的逻辑给串联起来。
如果需要复现精度,config中的训练策略最好不要修改。否则可能会有意外的训练情况出现。
通过上面的介绍,你应该对config文件的功能有了一个比较清楚的认识。然后通过前面提到的训练脚本,就可以训练一个高精度的纯浮点的检测模型。 当然训练一个好的检测模型不是我们最终的目的,它只是做为一个pretrain为我们后面训练定点模型服务的。
量化模型训练
当我们有了纯浮点模型之后,就可以开始量化模型了。和浮点训练类似,我们可以用下面的命令,对模型进行校准(calibration), 得到伪量化模型。
可以看到,我们的配置文件没有改变,只改变了 stage 的类型。此时我们使用的训练策略来自于config文件中的 calibration_trainer 。
当我们训练量化模型的时候,需要设置model_convert_pipeline,它首先载入模型浮点权重,然后用 Float2Calibration 将模型从浮点模型,转化成校准模型。
其中 calibration_qconfig_setter 定义了模型的量化配置。目前的配置是:
量化配置的解释
这里的量化配置略微有点复杂,我们将会逐步细致的解释。
首先,calibration_qconfig_setter 的第一个参数 reference_qconfig 定义了一个基础的量化配置,使用的observer是 observer_v2.HistogramObserver.
这是基于直方图统计的校准工具, 它会全局统计模型每一层输入输出 feature 的直方图统计量,然后决定每一层的量化步长 scale.
calibration_qconfig_setter 的第二个参数是 templates 对应的 q_template, 从上到下用了很多template 定义量化配置。
最顶部是 ModuleNameTemplate({"": qint8}) , 定义了全局的量化配置是 qint8 的,
然后两行 MatmulDtypeTemplate 和 ConvDtypeTemplate 的配置分别定义了Matmul算子输入和Conv算子输入的类型为 qint8.
接着,许多行使用 ModuleNameTemplate 为模型中的很多op特别设置了量化类型和固定scale,这是基于对模型结构和统计量的观察得出的配置。
用户也可以像这里类似地修改模型每一层的量化配置。
注意到 q_template 中还有一行 *sensitivity_templates , 这是通过敏感度分析的结果配置的高精度模板。
尽管基于经验,我们已经手动配置了一些高精度算子,量化模型还是很难恢复浮点模型的精度,为了分析模型量化的问题,我们建议用户对模型进行敏感度分析。 要运行模型敏感度分析工具,可以跑一下命令:
这个命令对应config中的以下配置:
敏感度分析的主要原理是:给定数据,工具分别运行浮点模型和量化模型,找到输出相差最大的样本,称之为 bad case.
然后对于量化模型,工具遍历模型每个算子,进行单算子量化,按量化后浮点模型输出比较的误差进行排序,得到模型量化敏感的算子列表。
sensitivity_templates 正是读取了这个敏感度排序列表,将敏感度排序在前列的算子配置成高精度,从而提高模型的量化精度。
本模型经过校准后,模型量化精度已经达到了浮点训练的 99% 以上,我们无需再进行额外的量化感知训练就可以达到精度目标。
关于模型量化的更多信息,请阅读 工具介绍 - QAT精度调优工具 章节的内容。
