量化分类及基本概念
模型量化方法本质上是函数映射。量化建立了高精度的浮点数值和量化后低精度的定点数值之间的数据映射。分为线性量化和非线性量化
【线性量化】
线性量化是目前最常用的量化方法,尤其是在工业界应用比较成熟的8比特量化方案采用的都是线性量化。
浮点->定点的公式如下:
定点->浮点的公式如下:
其中:
- R 表示输入的浮点数据,
- Q 表示量化之后的定点数据,
- Z 表示偏移量,或零点/最小值对应的量化数值,
- S 表示缩放系数。
S的求解方式如下:
其中:
- Rmax、Rmin 分别表示输入浮点数据中的最大值和最小值,
- Qmax、Qmin 分别表示量化后最大定点值和最小定点值。
线性量化又分为对称量化,和非对称量化
【非线性量化】
“非线性”映射函数 多种多样,通常需要根据不同场景的权值输入分布特点,研究使用何种映射方式。
- 实现1:非线性函数
- 实现2:聚类,每类线性量化
PyTorch量化
PyTorch对量化的支持目前有如下三种方式:
- Post Training Dynamic Quantization,模型训练完毕后的动态量化;
- Post Training Static Quantization,模型训练完毕后的静态量化;
- QAT(Quantization Aware Training),模型训练中开启量化。
【训练后量化】
训练后量化过程:
- 准备数据集。
- 以训练好的高精度模型为基准,使用校正数据集对其量化。
- 统计权重和激活值的数值范围,确定量化参数。
- 使用量化参数对模型进行量化。
【训练感知量化】
量化过程不可避免的会带来模型精度的损失,为了能够尽量保持原模型的精度,通常会对量化后的模型做fine tuning,或者进行重新训练。这种方式称作“训练感知量化”。
如果模型量化的精度能够满足使用要求,则会忽略掉finetuning和重训过程,这种简单直接的量化方式称作“训练后量化”。
训练感知量化能够获得更高的量化后模型精度,但是量化过程较为繁琐;训练后量化过程简单快速,但是模型精度损失会较大。尤其是规模较小的模型,有时可能会导致无法使用。
训练感知量化过程:
- 训练一个高比特的浮点模型。
- 确定模型网络中需要量化的部分,并相应位置插入伪量化的Ops。
- 在模拟量化过程(伪量化)的模式下迭代训练。
- 存储量化参数,降低精度,生成量化推理模型。
- 使用量化模型执行推理。
在训练过程中引入量化操作会面临一个问题,量化后的数值是离散的,在反向传播时无法进行求导。怎么办?
答:
因此引入了伪量化模块。数值是量化数值,但是类型还是浮点型。在实际的工程中会使用一种近似方程,定义如下公式。称为直通滤波器STE
如下图所示,在前向传播时会对输入权值做量化,但是在反向传播时梯度值会直接通过STE。
TensorRT量化
TensorRT的量化工具也比较成熟了。支持PTQ和QAT量化
【PTQ量化】
流程:具体使用就是,我们导出ONNX模型,转换为TensorRT的过程中可以使用trt提供的Calibration方法去校准,这个使用起来比较简单。可以直接使用trt官方提供的trtexec命令去实现,也可以使用trt提供的python或者C++的API接口去量化,比较容易。
TensorRT实现int8量化
- 对权重直接使用了最大值量化
- 对偏移直接忽略
- 对激活值采用饱和量化【解释见:注释1】
注释1:什么是非饱和量化?什么是饱和量化?选择合适的阈值T
为什么非饱和?因为激活值通常分布不均匀,
【×】直接使用非饱和量化会使得量化后的值都挤在一个很小的范围从而浪费了INT8范围内的其他空间,也就是说没有充分利用INT8(-128~+127)的值域;
【√】而进行饱和量化后,使得映射后的-128~+127范围内分布相对均匀,这相当于去掉了一些不重要的因素,保留了主要成分。
如何寻找这个阈值T就成了INT量化的关键,怎么找呢?
不同模型的激活值分布差异很大,这就需要进行动态的量化。
于是,NVIDIA就选择了KL散度也即相对熵来对量化前后的激活值分布进行评价,来找出使得量化后INT8分布相对于原来的FP32分布,信息损失最小的那个阈值。
INT8量化校准过程
- 先在一个校准数据集上跑一遍原FP32的模型;
- 然后,对每一层都收集激活值的直方图(默认2048个bin),并生成在不同阈值下的饱和量化分布;
- 最后,找出使得KL散度最小的那个阈值T,即为所求。
【TensorRT训练中量化】
训练中量化(QAT)是TensorRT8新出的一个“新特性”,这个特性其实是指TensorRT有直接加载QAT模型的能力。QAT模型这里是指包含QDQ操作的量化模型。实际上QAT过程和TensorRT没有太大关系,trt只是一个推理框架,实际的训练中量化操作一般都是在训练框架中去做,比如我们熟悉的Pytorch。(当然也不排除之后一些优化框架也会有训练功能,因此同样可以在优化框架中做)
TensorRT-8可以显式地load包含有QAT量化信息的ONNX模型,实现一系列优化后,可以生成INT8的engine。