目录
- 1. 必要步骤速览
- 2. 各步骤详解
- 2.1 浮点模型准备
- 2.2 数据校准
- 2.3 量化训练
- 2.4 定点转换
- 2.5 模型编译
- 3. 常见问题
对于新手而言,还是优先推荐 FX mode(QAT快速上手(fx mode)),虽然 FX mode 也有一些限制,需要模型满足 “symbolically traceable” 的要求,但整体而言其自动化程度会高很多,无需用户手写算子融合、手动替换不支持的算子,若碰到无法解决的问题,再回退到 Eager mode。
1. 必要步骤速览
整个QAT方案从浮点到部署模型就包括五个步骤:浮点模型准备、数据校准、量化训练(可选)、定点转换、模型编译。必要的步骤和示例代码如下所示,每个步骤的详细说明和注意事项可参考后文讲解。完整的示例推荐参考OE开发包中/ddk/samples/aitoolchain/horizonmodeltrainsample/pluginbasic目录下的eagermode.py脚本。
强烈建议在量化训练前(甚至是浮点模型设计阶段)先跳过训练过程完整走完prepare->convert->check步骤,确保模型可被硬件支持。
2. 各步骤详解
2.1 浮点模型准备
a. 请使用足够的数据量将浮点模型正常训练至收敛后再进行量化训练。
b. 强烈建议对输入数据进行归一化处理,有利于浮点收敛的同时也可使得模型对量化更友好。
c. 建议您在浮点模型设计阶段对照算子支持列表,避免使用不支持的算子导致后续prepare qat或者编译报错。
d. 更多关于如何搭建量化友好模型的说明可参考用户手册 4.2.4.1浮点模型的要求
若选择eager mode,那在浮点模型准备阶段需要完成下面几个必要步骤(可参考Pytorch官方文档):
- 在模型输入前插入 QuantStub节点,在模型输出后插入 DequantStub节点。有如下注意事项:
多个输入仅在 scale 相同时可以共享 QuantStub,否则请为每个输入定义单独的 QuantStub
建议使用horizon\plugin_pytorch.quantization.QuantStub 默认动态统计输入scale,若是可提前计算出scale的场景建议手动设置scale(例如bev模型的homo矩阵),对应的公版接口torch.quantization.QuantStub不支持手动设置。
- 参考算子约束列表完成算子替换。做这一步的原因是eager mode对算子的支持有一定限制,对部分算子的量化会有一些特殊处理。(例如需要用torch.nn.ReLU\替换torch.nn.functional.relu,add/cat/matmul等需要替换为horizon.nn.quantized.FloatFunctional,具体可参考如下示例)。
- 算子融合:算子融合可显著提高模型量化精度及部署性能,因此这是不可或缺的步骤,目前可支持conv/ConvTranspose2d/linear、bn、relu/relu6、add之间的融合(具体可参考:PythonPath/horizonpluginpytorch/quantizationfusemodules.py),支持使用算子下标或算子名称来写融合函数,具体可参考如下示例。
2.2 数据校准
对于部分模型,仅通过 Calibration 便可使精度达到要求,不必进行比较耗时的量化感知训练。即使模型经过量化校准后无法满足精度要求,此过程也可降低后续量化感知训练的难度,缩短训练时间,提升最终的训练精度。数据校准的具体配置方式及调参建议可参考QAT方案Calibration使用说明 。
2.3 量化训练
量化训练一些推荐的超参配置如下表所示:
超参
推荐配置
高级配置(如果推荐配置无效请尝试)
LR
从0.001开始,搭配StepLR做2次scale=0.1的lr decay
1. 调整lr在0.0001->0.001之间,配合1-2的lr decay。
- LR 更新策略也可以尝试把 StepLR 替换为 CosLR。
- QAT使用AMP,适当调小lr,过大导致nan。
Epoch
浮点epoch的10%
1. 根据loss和metric的收敛情况,考虑是否需要适当延长epoch。
Weight decay
与浮点一致
1. 建议在4e-5附近做适当调整。weight decay过小导致weight方差过大,过大导致输出较大的任务输出层weight方差过大。
optimizer
与浮点一致
1. 如果浮点训练采用的是 OneCycle 等会影响 LR 设置的优化器,建议不要与浮点保持一致,使用 SGD 替换。
transforms(数据增强)
与浮点一致
1. QAT阶段可以适当减弱,比如分类的颜色转换可以去掉,RandomResizeCrop的比例范围可以适当缩小
averaging\_constant(qconfig\_params)
1. 使用calibration后推荐减弱激活更新:
1. calibration的精度和浮点差距较大时:activation averaging\_constant不要设置成0.0
- weight averagingconstant一般不需要设置成0.0,实际情况可以在(0,1.0]之间调整
- 在QAT之前要求模型设置的是train()的状态,CALIBRATION和VALIDATION则要求模型是eval()状态,这主要是为了使bn、dropout等处于正确的状态(训练的时候bn会更新,评测的时候bn不更新)。
- CALIBRATION时会disable\_fake\_quant,并设置fake\_quant状态为train(),即不进行伪量化操作,仅观测算子输入输出统计量,更新scale;QAT时会观测统计量并进行伪量化操作;VALIDATION时不会观测统计量,仅进行伪量化操作。
- 数据校准之前模型设置为train()的状态,且未使用set\_fake\_quantize,等于是在跑QAT训练;
- 数据校准之前模型设置为eval()的状态,且未使用set\_fake\_quantize,会导致scale一直处于初始状态,全为1;
- 数据校准之前模型设置为eval()的状态,且正确使用了set\_fake\_quantize,但是在这之后又设置了一遍model.eval(),这将导致fake\_quant未处于训练状态,scale一直处于初始状态,全为1;

