1. 问题描述
智驾算法模型训练过程中,可能存在如下情况:使用Data1完成一阶段浮点模型model_stage1_float训练后,更换训练数据为Data2,固定model_stage1_float权重,用model_stage1_float模型浮点输出,训练二阶段模型model_stage2_float,最后拼到一起成 model_all_float 用于量化部署。

在进行量化时,按需使用对应的Data用于不同阶段模型的校准。如果model_stage1仅进行calib,model_stage2很容易想到如下两套量化方案:

对于上述两种方案遇到的问题,都可以通过对model_stage2_float进行finetune来解决,下面进行详细描述。
2. 多阶段模型量化方案
如果上述“方案2”的模型精度与延迟均满足预期,则不需要使用下面的方案。
当model_stage1仅需要calib时,推荐在model_stage2进行calib前,先使用model_stage1 calib后的输出,对model_stage2进行浮点finetune,保证model_stage1_calib+model_stage2_float指标与可视化符合预期。然后,再对finetune后的 model_stage2_float进行calib。这样可以让model_stage1的伪量化误差被model_stage2浮点finetune“消化”,让最终部署的多阶段模型量化损失最小。
强烈建议在latency达标的情况下,将model_stage1输出尽可能设置高精度类型,例如linear/conv输出建议配置为int16,这里有两点需要注意:
model_stage1输出直接作为model_stage2输入时,需要保证model_stage1输出dtype与model_stage2输入dtype一致。例如model_stage1是linear输出,model_stage2第一个算子是conv,即使model_stage1 linear输出支持int32/fp32更高精度类型,由于model_stage2 conv输入最高仅支持int16类型,所以model_stage1 linear输出也只能设置为int16。
model_stage1输出直接作为model_stage2输入时,需要保证model_stage1输出scale与model_stage2输入scale一致。具体做法是:读取model_stage1输出scale,转换得到threshold,然后通过ModuleNameTemplate配置model_stage2对应输入quant的threshold。
关于这两点的代码示例详见下一节。

当model_stage1需要calib+qat才能达标时,则推荐在model_stage2进行calib前,先使用model_stage1 qat后的输出,对model_stage2进行浮点finetune,保证model_stage1_qat+model_stage2_float指标与可视化符合预期。后续做法与上小节一致。

注意
多阶段模型量化部署,一定要做好代码模块化管理。
每个阶段的模型,分别prepare。
在进行model_stage2_float finetune 和 model_stage2 calib时,都应该冻结model_stage1_calib/qat模型,此时,一定要确保冻结住(相同输入时,每次推理结果不变),例如对model_stage1_calib进行冻结,示例如下。
3. 全流程代码示例
3.1 非hat用户
非hat用户可参考如下示例(代码可直接运行):
Stage1: CNN Backbone,末尾为 Conv2d(无 BN/ReLU)
Stage2: CNN Head,开头为 Conv2d
关键点:
Stage1 输出 dtype 必须与 Stage2 输入 dtype 一致(均为 qint16)
Stage1 输出 scale 必须与 Stage2 输入 scale 一致(通过 threshold 传递)
Stage2 应先用 Stage1 calib 输出做 float finetune,再进行自身校准
如下图,查看stage1.hbm输出scale/dtype 和stage2.hbm输入scale/dtype,可以发现是匹配的。

3.2 hat用户
hat用户可参考如下示例(代码可直接运行):
