模型量化相关知识汇总

量化&反量化

量化操作可以将浮点数转换为低比特位数据表示,比如int8和 uint8.

Q(x_fp32, scale, zero_point) = round(x_fp32/scale) + zero_point,

量化后的数据可以经过反量化操作来获取浮点数

x_fp32 = (Q - zero_point)* scale 

pytorch中 quantize_per_tensor的解释

pytorch可以使用quantize_per_tensor函数来对一个浮点tensor做8bit量化.

    ts_quant = torch.quantize_per_tensor(ts, scale = 0.1, zero_point = 10, dtype = torch.quint8)
    print(f'fp32 ts:{ts}, quant ts:{ts_quant}, int_repr:{ts_quant.int_repr()}')
    # 截断后的浮点数.
    naive_quant = np.array([24.5, 1.0, 2.0]) / 0.1 + 10
    print(f'naive_quant:{naive_quant}')

打印结果:

fp32 ts:tensor([100.,   1.,   2.]), quant ts:tensor([24.5000,  1.0000,  2.0000], size=(3,), dtype=torch.quint8,
       quantization_scheme=torch.per_tensor_affine, scale=0.1, zero_point=10), int_repr:tensor([255,  20,  30], dtype=torch.uint8)
naive_quant:[255.  20.  30.]

有几点值得说明

  • ts_quant直接打印出来的值并不是quint8数据,依然是个浮点,它表示的是映射到8bit后被截断剩下有效的浮点范围. scale=0.1的前提下,uint8只能表示出[0, 25.5]范围的浮点数,加上zero_point=10, 那么输入的浮点必须要在[0, 24.5]范围内才能被表示,超出部分会被截断,所以打印出来的是24.5, 1, 2.
  • 浮点表示的[24.5, 1.0, 2.0]可以通过int_repr方法打印出定点表示.
  • int_repr等效与naive_quant的实现

量化流程分:
后量化(ptq), 量化参数基于calib数据获取
QAT:量化参数来自训练数据。
从量化作用位置上来分:
只量化权重
动态量化(权重静态量化,激活动态量化)
静态量化(权重和激活静态量化)

对于输入r,Q(r) = round(r/S + Z), 其中S,Z分别是quant scale和bias。
通过公式r^ = (Q(r) -Z)* S反量化操作可以获取浮点数r^,量化误差:quant_error = r - r^
量化的目的就是找到一个合适的S,对于torch来说,可以通过 MinMaxObserver, MovingAverageMinMaxObserver, HistogramObserver
这些方法来统计quant scale和bias。

  • 非对称量化(Affine or asymmetric quantization)
    affine策略对沿激活值偏向一边时更合适(比如范围在[-0.5,1]之间),它直接统计了最大最小值,不适合做weight的量化。对应方法:torch.per_tensor_affine
  • 对称量化
    不需要计算zero point, 对于skew分布的输入量化效果会很差。weight更适合使用per-channel 对称量化。对应函数:torch.per_tensor_symmetric
    一般来说,对于weight使用对称 MinMax量化会更好,对于激活使用affine-per-tensor + MovingAverageMinMax 会更好。
    示例代码:
Affine or asymmetric quantization 
def get_symmetric_range(x):
  beta = torch.max(x.max(), x.min().abs())
  return -beta.item(), beta.item()

def get_affine_range(x):
  return x.min().item(), x.max().item()

torch 可选的量化策略有:

per_channel_affine: qscheme = ...
per_tensor_symmetric: qscheme = ...
per_channel_symmetric: qscheme = ...
per_channel_affine_float_qparams: qscheme = ...

qconfig与obser的关系:

torch.quantization.QConfig
    activation
        MovingAverageMinMaxObserver
            qscheme:torch.per_tensor_affine or torch.per_tensor_symmetric
            min_val
            max_val
            caculate_qparams()
    weight
        MovingAveragePerChannelMinMaxObserver
            ...

PTQ静态量化步骤

pre-trained model -> fuse modules -> insert stubs & observers -> calib -> quantization -> ptq model
注意,quantstub&dequantstub只是一个占位符, 在calib时会被替换成observer。

参考代码:https://pytorch.org/blog/quantization-in-practice/#post-training-static-quantization-ptq

参考链接:

https://blog.csdn.net/qq_34218078/article/details/127521819
https://pytorch.org/blog/quantization-in-practice/#post-training-static-quantization-ptq

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值