目录
- 1. 精度调优推荐流程
- 2. Calibration阶段的精度调优建议
- 3. QAT量化训练阶段的精度调优建议
- 4. 定点精度的调优建议
- 5. 分析工具使用指南
1. 精度调优推荐流程

2. Calibration阶段的精度调优建议
Calibration即可满足精度要求,可以免去费时的量化训练过程,另一方面通过Calibration初始化量
化参数之后也可以加速模型的量化训练收敛。
calibration/float精度比<80%为经验值,仅供参考(部分模型calibration/float精度比<80%时也可以通过QAT训练达到预期精度)。
2.1 Calibration 精度损失 < 20%
2.2 Calibration 精度损失 ≥ 20%
建议优先排查浮点模型精度是否正常(是否正常收敛、过拟合、加载权重是否正确等等);
当使用默认配置,Calibration损失较大或尝试了上一节的调参建议后仍存在大幅损失时,建议参考后文第五章使用分析工具来定位量化异常层。
3. QAT量化训练阶段的精度调优建议
量化参数初始化
建议默认使用Calibration,可以使得QAT训练获得更好的精度、收敛得更快。
Transform(数据增强)
建议默认 QAT 时保持跟浮点一致,也可以适当减弱,比如分类的颜色转换可以去掉,RandomResizeCrop 的比例范围可以适当缩小等。
Optimizer
默认情况 QAT 时保持跟浮点一致,也可以尝试 SGD,如果浮点训练采用的是 OneCycle 等会影响 LR 设置的优化器,建议不要与浮点保持一致,使用 SGD 替换。
异常情况处理:
出现NAN:
检查浮点模型精度是否正常;
检查数据和 label 中有无 nan,inf;
调低学习率,或者使用 warmup 策略;
使用 torch.nn.utils.clip_grad_norm_ 进行梯度截断。
loss异常
检查是否正确加载Calibration参数
若按照以上建议调试仍然不能有效提升量化精度,建议参考后文第五章使用分析工具来定位量化异常层。
4. 定点精度的调优建议
2. 排查是否是加载ckpt之后又做了错误修改导致模型输出异常;
3. 若为Calibration直接转定点,且Calibration精度损失很小,定点精度损失较大,请先确认Calibration阶段的操作是否有误(通常是由于伪量化节点状态设置不正确,导致Calibration阶段测试的是浮点精度,建议参考QAT方案Calibration使用说明 第六章第3个常见问题,正确使用set_fake_quantize设置模型状态);
4. 若为Calibration直接转定点,定点精度损失不算太大,可继续进行qat,并尝试不同epoch的qat模型以找到最佳定点精度。
5. 若以上策略均无明显收益,则建议参考后文第五章使用分析工具来定位量化异常层。
5. 分析工具使用指南
请在使用分析工具之前调用set_fake_quantize接口将calibration模型设置为VALIDATION的状态,避免因为伪量化节点未生效导致分析结果异常;
对于初次使用的用户,推荐使用集成接口来一次性完成相似度、统计量、共享 op 、fuse pattern和量化配置的检查,使用方式如下:
对于debug工具生成的结果,建议依次关注如下几个方面:
5.1 共享op
5.1.1 可能导致的问题
共享op可能会导致模型部分结构 fuse 失败
共享op可能会导致多个op共用相同的量化参数,导致出现精度问题
5.1.2 分析方式
注:基于浮点模型做检查(calibration和qat模型由于已完成fuse,无法进行原始模型结构相关的检查)



5.1.3 优化建议
单独定义每个op/block(除DeQuantStub节点之外),避免一次定义多次调用。
若存在共享conv对精度有增益等特殊设计场景,可通过复制两份op并加载同一份参数以避免出现异常fuse的情况。
5.2 未正确fuse
5.2.1 可能导致的问题
模型量化精度损失明显(如果每个算子都独立进行计算,则都会被单独计算量化参数)
模型部署延时变长(算子融合可以减少部署模型中的op数量,加快模型计算)
5.2.2 分析方式
注:基于浮点模型做检查(calibration和qat模型由于已完成fuse,无法进行原始模型结构相关的检查)
观察任意的相似度分析或者非原始浮点模型的统计量结果,如果发现存在有零散的bn、relu和floatfunctional.add则代表有可能存在未被正常fuse的现象。

再结合check_unfused_operations的检查结果,查看该算子的融合建议:

本文基于J5 OE1.1.68版本测试,集成接口model_profiler(mode=FvsQ)profiler.html中的fuse检查结果可能存在部分漏检,后续新版本将修复。
5.2.3 优化建议
如果使用的是fx模式,则在prepare过程中会自动完成算子融合,一般仅在异常op共享或wrap时会出现未fuse的情况,请按照前文建议取消共享并合理调整wrap范围以使得可被fuse的结构均被fuse。
5.3 数据分辨率不足
由于calibration和qat的默认qconfig均为int8配置,数据表示范围有限,因此使用默认配置可能会导致部分层出现明显的精度损失。
5.3.1 分析方式
5.3.1.1 模型输入

此外还有一些特殊场景输入节点有明确的物理含义(如gridsample的grid输入),其输入数值确实需要为一系列整型数:

则建议首先判断其数值范围是int8还是int16(上图明显超过了int8可表示范围),配置对应的qonfig,然后手动设置该输入节点的scale(scale=max/128.0或scale=max/32768.0)。
5.3.1.2 模型输出
2. 观察统计量结果文件最后一列,若开启了高精度则输出类型为float32;

3.观察qconfig检查结果文件,若开启了高精度则输出类型为float32;

4.可观察相似度结果中DeQuantStub节点是否含scale,若无scale则代表已开启了高精度输出,若有则代表未开启。

AttributeError: 'NoneType' object has no attribute 'numel'。
5.3.1.3 模型中间层
与模型输入的分析方式相同,通过观察相似度(qscale和数值范围是否匹配)和统计量(最大最小值是否超过int8数值范围)的结果,判断是否是为某个节点数值分辨率不足导致的量化损失。
5.3.2 优化建议
5.3.2.1 模型输入
模型输入一般有两种:原始数据(图像,雷达等)和模型的辅助输入(如 transformer 的位置编码);这些数据都需要量化之后才能作为量化网络的输入,由于量化工具采用对称均匀量化的方式,建议通过以下手段来改进:
2. 查看量化配置是否合理,比如图像输入建议采用固定量化 scale=1/128.0(若归一化未处理至[-1,1],则设置scale=max/128.0,max为输入数据集绝对值的最大值);但固定 scale 不一定适合所有数据,需要具体分析;
3. 如果数据分辨率要求比较高且无法调整,建议使用 int16 的量化。
以图像输入为例,由于原始图像(不管是 RGB 还是 YUV)输入范围是 [0, 255],不适合对称量化,而做关于 0 对称的归一化之后,输入范围变为 [-1, 1],可以直接使用固定 scale=1/128.0 进行量化。
5.3.2.2 模型输出
模型输出很多时候有物理含义,可能要求比较高的分辨率,不适合 int8 量化,建议:
2. 如果 BPU 性能等原因需要量化输出,建议使用 int16 量化,或者通过调整输出物理含义的方式降低输出数据分辨率。
5.3.2.3 模型中间层
从实现角度看算子有两种:1. 单粒度算子,如 conv2d;2. 通过多个小算子实现的复杂算子,如 layernorm;这里主要关注算子整体的输出,忽略复杂算子内部的小算子输出。
如果算子输出的数值范围较大,建议如下:
2. 使用 int16 量化;
3. 如果遇到 conv-[bn]-[add]-relu 这样的 pattern,可以尝试在 QAT 阶段指定使用 relu6(不一定有效)。
如果存在某层的 weight 的数值范围较大,可以:
1.尝试调整 weight-decay;建议在 4e-5 附近做适当调整,不要过大或过小。weight decay 过小导致 weight 方差过大;过大则可能导致连锁反应,比如网络层输出的 weight 方差过大。
5.4 单算子损失异常
5.4.1 分析方式
这类问题的表现为单算子损失较大,量化后或转定点后相似度明显降低。例如下图中的cat节点就存在明显异常,观察其输入输出统计量,发现两个输入的数值范围不同:


若观察相似度和统计量结果均未获取到有效信息,此时则建议使用分步量化工具(排查QAT阶段的量化异常层)以及单算子转换精度调试工具(排查定点精度损失异常层)。
5.4.2 优化建议
易出现量化误差损失较大的算子有以下几类:
a. 需要通过各种手段限制输入范围,让多输入的数值范围相近;
b. 使用 int16 量化;
a. 评估下是否可以少使用/不使用此算子或替换成其他不会导致值域增大的激活算子;
b. 限制输入范围在较为平缓的区间;
c. 使用 int16 量化;
d. 如果 QAT 精度正常但 quantized 精度不足,建议寻求地平线技术支持。
b. 如果 QAT 精度正常但 quantized 精度不足,可尝试手动调整查表参数,如 layernorm 和 softmax 均支持手调的参数;
