专栏算法工具链QAT快速上手(eager mode)

QAT快速上手(eager mode)

芯链情报局2023-11-07
237
0

目录

  • 1. 必要步骤速览
  • 2. 各步骤详解
    • 2.1 浮点模型准备
    • 2.2 数据校准
    • 2.3 量化训练
    • 2.4 定点转换
    • 2.5 模型编译
  • 3. 常见问题


Pytorch官方提供了两种量化模式:Eager Mode Quantization 和 FX Graph Mode Quantization,这两种模式的区别如下(来源:PyTorch官方文档):
avatar
对于新手而言,还是优先推荐 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。
  1. LR 更新策略也可以尝试把 StepLR 替换为 CosLR。
  2. 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
  1. 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;
算法工具链
征程3征程5杂谈
评论0
0/1000