量化准确性调试

本文提供了一些高层次的策略来提升量化的准确性。如果量化后的模型相较于原模型存在误差,我们可以将其误差分为以下几类:

  1. 数据不敏感错误 - 由于模型量化的内在误差导致大量输入数据出现较大误差

  2. 数据敏感错误 - 由异常输入数据引起,输入数据中的小部分存在较大误差

  3. 实现错误 - 量化内核与参考实现不符

数据不敏感错误

通用提示

  1. 对于PTQ(训练后量化),确保用于校准的数据能够代表你的数据集。例如,在分类问题中,建议每个类别都有多个样本,并且总的样本数量至少为100。使用更多的数据进行校准除了会增加校准时间外没有其他负面影响。

  2. 如果你的模型包含 Conv-BN 或 Linear-BN 结构,建议将它们融合。在 FX 图形模式量化中,此操作会自动完成。而在 Eager 模式量化中,你可以手动使用 torch.ao.quantization.fuse_modules API 来进行。

  3. 提高有问题的操作的数据类型精度。通常,fp32的准确度最高,其次是fp16,然后是动态量化int8,最后是静态量化int8。

    1. 注意:这是以牺牲性能来换取准确性的。

    2. 注意:不同后端中,每个操作和数据类型的内核可用性可能会有所不同。

    3. 注意:数据类型转换会增加额外的性能成本。例如,fp32_op -> 量化 -> int8_op -> 去量化 -> fp32_op -> 量化 -> int8_op -> 去量化 的性能会低于 fp32_op -> fp32_op -> 量化 -> int8_op -> int8_op -> 去量化,因为前者需要更多的数据类型转换。

  4. 如果你在使用通道量化训练 (PTQ),考虑使用量化感知训练 (QAT) 来恢复部分由于量化的精度损失。

Int8 量化技巧

  1. 如果你使用的是逐张量权重量化,考虑改为逐通道权重量化。

  2. 如果你在fbgemm上进行推理,确保将reduce_range参数设置为False(如果您的CPU是Cooperlake或更新版本),否则设置为True

  3. 检查输入激活分布在不同样本间的差异。如果差异较大,该层可能更适合动态量化而非静态量化。

数据敏感错误

如果你使用的是静态量化,而一部分输入数据导致了较高的量化误差,你可以尝试:

  1. 调整你的校准数据集,使其更好地代表你的推理数据集。

  2. 手动检查(使用Numeric Suite)哪些层的量化误差较高。对于这些层,可以考虑保持它们为浮点数,或者调整观察器设置以选择更合适的比例和偏移值。

实施错误

如果你在使用自定义后端的 PyTorch 量化时,可能会发现操作(例如 dequant -> op_fp32 -> quant)的参考实现与目标硬件上该操作的量化实现(如 op_int8)之间存在差异。这可能意味着以下两种情况之一:

  1. 这些差异(通常很小)是因为目标内核在目标硬件上的表现与 fp32/cpu 不同而产生的,比如使用整数数据类型进行累加操作。如果内核不能保证与参考实现完全一致,则这种差异是正常现象。
  2. 目标硬件的内核存在精度问题。在这种情况下,请联系内核开发人员。

数值调试工具(原型)

警告

数值调试工具尚处早期原型阶段,可能随时发生变化。