使用Onnxruntime对onnx模型量化介绍
Onnxruntime不支持量化感知训练(QAT),只支持训练后量化(PTQ)
量化前处理
- 符号形状推理:最适合Transformer模型。
- 模型优化: 使用ONNXRuntime本地库重写计算图,包括合并计算节点、消除冗余以提高运行效率。
- ONNX 形状推理
这些步骤的目的是提高量化质量。 当张量的形状已知时,onnxruntime量化工具效果最佳。符号形状推理和 ONNX 形状推理都有助于找出张量的形状。符号形状推理最适用于基于变换器的模型,而 ONNX 形状推理则适用于其他模型。
模型优化可进行某些运算融合,使量化工具的工作变得更容易。 例如,在优化过程中,可以将卷积算子和批量归一化算子融合为一个算子,从而可以非常高效地进行量化。需要注意的是,ONNXRuntime 存在一个已知问题,即模型优化无法输出超过 2GB 的模型大小。 因此,对于大型模型,必须跳过优化。
预处理 API 位于Python模块onnxruntime.quantization.shape_inference
,函数quant_pre_process()
模型优化也可以在量化过程中进行。不过,由于历史原因,虽然默认情况下是这样,但并不推荐这样做。量化过程中的模型优化会给调试量化造成的精度损失带来困难。因此,最好在预处理期间而不是量化期间执行模型优化。
静态/动态量化
① 动态量化
用于动态量化的Python API 位于模块 onnxruntime.quantization.quantize
中,函数 quantize_dynamic()
。
② 静态量化
用于静态量化的Python API位于onnxruntime.quantization.quantize
模块,函数 quantize_static()
,Onnxruntime的静态量化工具支持三种校准方法: MinMax
、Entropy
和 Percentile
。 详情请参阅 calibrate.py
。
调试
量化数据类型选择
量化值为 8 位宽,可以是有符号(int8)或无符号(uint8)。 我们可以分别选择激活和权重的有符号性,因此数据格式可以是(激活:uint8,权重:uint8)、(激活:uint8,权重:int8)等。 我们用 U8U8 来表示(激活值:uint8,权重:uint8),用 U8S8 来表示(激活值:uint8,权重:int8),同样用 S8U8 和 S8S8 来表示其余两种格式。
ONNX CPU 运行时量化可运行 U8U8、U8S8 和 S8S8。 带有 QDQ 的 S8S8 是默认设置,兼顾了性能和精度。 它应该是首选。 只有在精度大幅下降的情况下,才可以尝试 U8U8。 请注意,使用 QOperator 的 S8S8 在 x86-64 CPU 上运行速度较慢,一般情况下应避免使用。 ONNX Runtime 在 GPU 上的量化仅支持 S8S8。