Posts 量化
Post
Cancel

量化

量化根据是否需要重训练,分为:

  • 感知量化训练,优点:模型准确率更好,适用于对模型压缩率和准确率要求较高的场景。

  • 训练后量化,优点:简单易用,适用于追求高易用性和缺乏训练资源的场景。

训练后量化

Post-training Quantization, PAT,或者离线量化

在模型训练结束后进行的量化,对训练后模型中的权重由浮点数(如float32)量化到低比特整数(如int8/int4),并通过少量校准数据基于推理过程对数据(activation)进行校准量化,从而加速模型推理速度。

通常,训练后的模型权重已经确定,因此可根据权重的数值离线计算得到权重的量化参数。

而通常数据是在线输入的,无法准确获取数据的数值范围,通常需要一个较小的有代表性的数据集来模拟在线数据的分布,利用数据集执行前向推理,得到对应的中间结果,并根据这些浮点结果离线计算出数据的量化参数。

量化根据对象的不同,分为:

  • 权重(weight)量化
  • 数据(activation)量化

权重量化

是指根据权重的数值分布情况,将权重处理到低比特。

训练后量化场景通过离线量化的方式,直接从用户推理模型中读取权重数据,然后调用量化算法对权重进行量化,并把量化后的数据回写到模型中。

推理时,在内存初始化阶段,对网络模型中的权重进行反量化操作变成float进行正常的推理。

数据量化

是指根据数据的数值分布情况,将输入数据(activation)处理到低比特。每一层的数据分布是未知且巨大的,只能在前向过程中确定,因此数据量化是基于推理或者训练过程的。

在训练后量化场景中,通过在线量化的方式,通过修改用户推理模型,在待量化层位置插入旁路量化节点,采集待量化层的输入数据,然后校准得到数据量化因子scale, offset。在推理时一般使用少量数据集,代表所有数据集的分布。

校准

在训练后量化场景中,做前向推理获取数据量化因子的过程。

量化算法

权重量化

  • ARQ算法(Adaptive Range Quantization)
  • NUQ算法(Non Uniform Quantization)

数据量化

  • IFMR算法(Input Feature Map Reconstruction)
  • HFMG算法(Histogram Feature Map Glutton)

ARQ算法

对权重直接量化的方法。有2种方式:channel_wisenon-channel_wise

  • channel_wise:所有filter一起分析数据分布,进行量化,公用一个量化因子。

  • non channel_wise:每个filter独立做数据分析,进行量化,有独立的量化因子。

NUQ算法

是对权重进行非等间距量化的一种方法。

均匀量化将权重数据从32bit量化到8bit,NUQ在此基础上挑选部分量化台阶。

IFMR算法

在某个数据分布下,通过搜索的方式确定最佳量化方式。

  • 1。将浮点数截断到[clip_min, clip_max]范围。
  • 2。将浮点数据量化到int范围。

HFMG算法

通过直方图的方式来记录激活数据的数据分布,通过搜索的方式确定最佳量化截断位置。

  • 1。根据输入数据创建直方图。
  • 2。若有多个batch的数据,则对每个batch的数据创建一个直方图,然后进行直方图合并。
  • 3。基于创建的直方图,根据搜索的方式确定数据的截断点。

量化感知训练

Quantization Aware Training, QAT,或者在线量化

MindSpore的感知量化训练是一种伪量化的过程,它在模型中需要记录量化参数的地方插入伪量化节点,其作用有二:

  • 统计流经算子节点的数据的最大最小值,找到输入、权重等待量化数据的分布;
  • 模拟量化模型在量化到低比特时引入的精度损失(来自rounding和clamping操作),将该损失作用到网络模型中,传递给损失函数,让优化器在训练过程中对该损失值进行优化,从而提高模型对量化效应的适应能力,获得更高的量化模型精度。

一般对于权重的量化使用对称量化,对于激活的量化使用非对称量化。原因是对于权重而言,一般是对称的,如[-6.0, 6.0],采用对称量化有更少的计算量。对于激活而言,其值分布在一侧,比如ReLU输出就是[0.0, +∞),如果采用对称量化,则会比较浪费。

对称量化

原始float数据与量化后的INT8数据之间的转换: \(scale = \frac{2 \times max(\vert x_{min} \vert, x_{max})}{Q_{max}-Q_{min}}\)

\[offset = 0\] \[int = round( \frac{float}{scale})\] \[float = scale \times int\]

非对称量化

原始float数据与量化后的INT8数据之间的转换: \(scale = \frac{x_{max}-x_{min}}{Q_{max}-Q_{min}}\)

\[offset = Q_{min} - round(\frac{x_{min}}{scale})\] \[float = scale \times (uint8 + offset)\]

\(uint8 = round(\frac{float}{scale}) - offset\) MindSpore中的实现参见:

  • mindspore/python/mindspore/compression/quant/quant_utils.py
  • mindspore/ccsrc/plugin/device/gpu/kernel/cuda_impl/cuda_ops/fake_quant_perlayer_impl.cu
  • mindspore/mindspore/ccsrc/plugin/device/gpu/kernel/cuda_impl/cuda_ops/fake_quant_perchannel_impl.cu
  • mindspore/python/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer.py
  • mindspore/python/mindspore/ops/_op_impl/_custom_op/fake_quant_perchannel.py
  • mindspore/ccsrc/plugin/device/gpu/kernel/cuda_impl/cuda_ops/minmax_update_impl.cu
  • mindspore/python/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py

通道稀疏

张量分解

模型部署优化

主要为算子融合,是指通过数学等价,将模型中的多个算子运算,融合成单算子运算,以减少实际前向过程中的运算量。

  • Conv+Bn融合,融合后的Bn层会被删除。
  • Bn+Mul融合,融合后的Mul层会被删除。
  • Bn+Add融合,融合后的Add层会被删除。

INT4部署时遇到的问题

部分Conv用INT4量化后,性能比INT8劣化

INT8量化时,Dequant(INT32->Fp16)和Quant(Fp16->INT8)可以融合成Requant算子。

但是INT4量化时,先做mad(INT32),然后Dequant(INT32->Fp16)和Quant(Fp16->INT4),由于硬件没有INT32->INT4的指令,所以无法将Dequant和Quant融合成Requant算子,导致INT4相比INT8,vector计算量增大很多,所以部分Conv性能反而是负收益。

This post is licensed under CC BY 4.0 by the author.