MIT-TinyML学习笔记【4】Quantization1

1 Numeric Data Types

1.1 Integer

image.png

1.2 Fixed-Point Number

定点数
image.png

1.3 Floating-Point Number

  • Larger Range
    image.png

浮点数Family
深度学习引发的数值表示的革新
image.png
权衡要表示的range和小数位的精度

  • 单精度FP32、半精度FP16…
  • BF16 (Google) 为了追求表示更大的范围 在训练时小数没那么重要,所以增加了Exponent
  • TF32(Nvidia)FP32的Exponent bits + FP16的Fraction bits

计算一个FP16的例子
image.png
计算一个BF16的例子
image.png


2 K-Means-based Weight Quantization

image.png
it does not hurt the accuracy!(for inference

[[Reference_Deep Compression]]
image.png

  • 对原始权重进行聚类,得到4个聚类中心,index分别设置为0、1、2、3
  • 用2bit就可以表示index,所以原本需要32bit存储的每个weight数据变成2bit存储
  • 聚类结果仍用32bit存储
  • 最终节约3.2倍的storage
  • 假设参数量M远大于量化比特数量N,原本存储需要32Mbit,K-means量化后需要NMbit,减少了32/N倍的storage

note: specialized data path is required to support such technique

2.1 Fine-tuning Quantized Weights

image.png

  1. 按照原始weights求梯度,然后根据聚类后的group将梯度求和
  2. -0.03+0.12+0.02-0.07=0.04
  3. 用求得的梯度和(一个group)来更新centroids聚类中心

2.2 Accuracy vs. Compression rate

image.png

Question:我们应该先剪枝还是先量化?
Answer:先剪枝,减少参数量,然后再进行量化
剪枝后、fine-tuning后的参数分布如下图
image.png

量化后
image.png

量化后+重训练后
image.png

slightly shifted, left or right

直接这样看几乎没看出啥区别,但是在ppt里两张来回翻翻还是能看出权重的略微移动

2.3 How Many Bits do We Need?

image.png

2.4 Summary

计算图如下
image.png

  • 在执行推理时,利用查找表将权重压缩
  • K-Means量化只节约了模型的存储开销
  • 所有的计算和内存访问依然是浮点数
    image.png
    Linear Quantization不仅用Integer来存储,也用Interger来计算

3 Huffman Coding

在对权重进行量化后,根据权重分布的直方图可以很直观的发现它不是一个均匀分布,有些权重出现的概率大,有些权重出现的概率小,所以不需要把所有权重都按上面说4bit或2bit来表示,而是把出现概率大的用更少的bit表示,md韩松博士是学过信息论的哈哈哈
image.png


To further reduce the storage required

4 Deep Compression Pipeline

image.png
实验结果
image.png

Can we make compact models to begin with?
SqueezeNet
image.png
image.png
压缩后的SqueezeNet的模型尺寸,比AlexNet小510倍

5 Linear Quantization

不需要定制化的硬件,可以在CPU/GPU上跑起来

[[Reference_Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference]]

image.png

  • zero point:2bit有符号整数
  • scale:32bit浮点数
  • 跟K-means最大的区别是量化后的值是线性的
  • (K-means量化后的四个值-1, 0 ,1.5, 2)

量化与反量化,课件里直接从反量化切入,实际上先把实数激活值量化成整数,与权重矩阵相乘得到整数结果 Y i n t / q Y Y_{int} / q_{Y} Yint/qY后,再进行反量化

从q到r的映射 = 从量化的权重到真实权重的映射

  • Scale是一个量化参数
  • Zero point是另一个量化参数,使得r中的0能够被准确的表示(因为剪枝后的权重中存在很多的零,我们希望q经过映射能把零给准确的表达出来)
    image.png

下图表示了量化后的权重到真实权重的映射,根据 r m i n , r m a x r_{min}, r_{max} rmin,rmax 可以知道量化后的 q 需要多少bit来表达和存储
根据量化后的bit,可以表达的数据范围为 − 2 N − 1 , 2 N − 1 − 1 -2^{N-1},2^{N-1}-1 2N1,2N11
image.png

5.1 如何计算量化参数scale(非对称量化):

image.png
计算scale的例子:
image.png
首先找到真实权重的最大值和最小值 ->得到分子
然后确定用多少bit来表示量化后的权重,这里采用2bt,得到分母为3
计算得到S为1.07

5.2 如何计算量化参数Z(非对称量化):

得到S后,用 r m i n = S ( q m i n − Z ) r_{min}=S(q_{min}-Z) rmin=S(qminZ) r m a x = S ( q m a x − Z ) r_{max}=S(q_{max}-Z) rmax=S(qmaxZ)就可以算出Z,将计算结果求整

image.png
计算Z的例子
image.png

5.3 非对称量化Non-symmetric

假设没有bias的情况,浮点数(Y, W, X)通过量化后的整数 -> 反量化得到

  • W:权重,可以提前计算qw, Zw ,Sw,常量
  • X:输入激活值input activation,dynamic

如何计算qY
image.png
哪些是常量?
image.png
integer的乘法,32bit加法来防止溢出

  • q W , Z W q_{W},Z_{W} qW,ZW都是可以提前计算的,因为W权重在推理时候是已知的看作常数
  • 经验上, S W S X S Y \frac{S_{W}S_{X}}{S_{Y}} SYSWSX 永远保持在 (0,1) 的范围内,所以可以用定点数计算代替
    image.png
    2的-n次方可以用移位实现,硬件中替代除法的友好方法

image.png
权重的分布通常是正态分布,所以可以认为权重的Zero Point为0(意味着量化后的0映射到浮点数中也是0,也就是说认为权重大概是对称分布的
从而在计算时消除这项(Zero Point = 0 也就是对称量化,因为权重的分布特性,所以在量化权重时常用对称量化!)

5.4 对称量化Symmetric

image.png

在这种情况下, r m i n = − ∣ r ∣ m a x , Z = 0 r_{min}=-|r|_{max}, Z=0 rmin=rmax,Z=0 可以算出S
这种方法在Pytorch和ONNX中使用
image.png

但是,只采用一边的范围来计算( q m i n q_{min} qmin)此时量化后的正数和负数不平均,如图中3+ 4-

相反,采用 q m a x q_{max} qmax来计算S是TensorFlow等框架中采用的方法
image.png

5.5 对称量化vs非对称量化

两者的主要区别是量化值区间是否约束了量化前后的零点对应

image.png

  • 非对称量化使用整个范围,可以处理好原始数据分布不均匀的情况

  • 部署更加困难,且计算zero point需要额外的逻辑资源

  • 对称量化会忽略掉一半的范围

  • 由于Activation Tensor在经过ReLU后没有负数,所以对称量化会浪费1bit有效位(3bit表示8个量化值,但实际上只有0和整数,即4个量化值去映射不存在的负数,只有4个量化值有效,那其实2bit就能表示,所以浪费了1bit有效位)

  • 部署比较简单

对称量化的zero point = 0 所以消除了2项,减少了计算量

image.png


小白看到这里有点懵,在网上找找相关资料

6 参考博客

6.1 参考一

一起实践神经网络量化系列教程
image.png

  • 对称量化的实数0也对应整数的0,而非对称量化的实数0不一定对应着0,而是Zero Point Z
  • 对称量化实数的范围是对称的 [ − α , α ] [-\alpha, \alpha] [α,α] ,而非对称量化的范围不对称 [ − β , α ] [-\beta,\alpha] [β,α]
  • 对称量化整数的范围是对称的 [ − 127 , 127 ] [-127,127] [127,127],而非对称量化的不对称 [ − 128 , 127 ] [-128,127] [128,127]

简单概括非对称量化: f ( X ) = S ⋅ X + Z f(X)=S\cdot X+Z f(X)=SX+Z ,其中Z为Zero Point,这个数字就表示实数0映射到整数是多少,而对称量化就是 f ( X ) = S ⋅ X f(X)=S\cdot X f(X)=SX

需要注意的一点是,不论是非对称还是对称量化,是基于线性量化(也可以称作均匀量化)的一种。线性量化将FP32映射到INT8数据类型,每个间隔是相等的,而不相等的就称为非线性量化。非线性量化因为对部署并不是很友好,虽然能够更好地捕捉到权重分布的密集点


以下根据oldpan大佬的博客,试图对应上课件,来理解对称量化和非对称量化

课件中: r m a x = S ( q m a x − Z ) r_{max}=S(q_{max}-Z) rmax=S(qmaxZ),这里是反量化的公式 (整数值减去zero point再乘上scale得到实数值),所以在计算S的时候分子分母是反的!即博客中的 s = 1 / S s=1/S s=1/S

  • 对称量化
    int8对称量化的表示范围 [ − 2 b − 1 + 1 , 2 b − 1 − 1 ] [-2^{b-1}+1,2^{b-1}-1] [2b1+1,2b11](对应课件的 q m i n , q m a x q_{min},q_{max} qmin,qmax),其中 b=8 bit,因此量化后的输入x可以表示为
    x q = c l i p [ r o u n d ( x ⋅ s , − 127 , 127 ) ] x_{q}=clip[round(x\cdot s,-127,127)] xq=clip[round(xs,127,127)]
    s = 2 b − 1 − 1 α = q m a x r m a x s=\frac{2^{b-1}-1}{\alpha}=\frac{q_{max}}{r_{max}} s=α2b11=rmaxqmax
    课件中计算对称量化的S用的是 r m i n / q m i n r_{min}/q_{min} rmin/qmin 我的理解,对称的时候用最大值相除或者用最小值相除都可以(课件中也提到过不同的框架会分别采用 r m i n , r m a x r_{min} , r_{max} rmin,rmax
    其中,截断函数clip:
    c l i p ( x , l , u ) = l , x < l x , l < = x < = u u , x > u clip(x,l,u)={ \begin{aligned} &l, &x<l \\ &x, &l<=x<=u \\ &u, &x>u \end{aligned} } clip(x,l,u)=l,x,u,x<ll<=x<=ux>u
    整理为通用公式表达有:
    x q = q u a n t i z e ( x , b , s ) = c l i p [ r o u n d ( x ⋅ s , − − 2 b − 1 + 1 , 2 b − 1 − 1 ) ] x_{q}=quantize(x,b,s)=clip[round(x\cdot s,--2^{b-1}+1,2^{b-1}-1)] xq=quantize(x,b,s)=clip[round(xs,2b1+1,2b11)]

  • 非对称量化
    s = 2 b − 1 α − β = q m a x − q m i n r m a x − r m i n s=\frac{2^{b}-1}{\alpha-\beta}=\frac{q_{max}-q_{min}}{r_{max}-r_{min}} s=αβ2b1=rmaxrminqmaxqmin
    注意: 2 b − 1 − 1 − ( − 2 b − 1 ) = 2 b − 1 2^{b-1}-1-(-2^{b-1})=2^{b}-1 2b11(2b1)=2b1
    其中, z = − r o u n d ( β ⋅ s − 2 b − 1 ) = − r o u n d ( r m i n × s − q m i n ) z=-round(\beta\cdot s-2^{b-1}) =-round(r_{min}\times s -q_{min}) z=round(βs2b1)=round(rmin×sqmin)
    注意:量化与反量化的 Z 相差一个负号,且 s = 1/S(again!课件中给出的是反量化公式)

    整理为通用公式表达有:
    x q = q u a n t i z e ( x , b , s , z ) = c l i p [ r o u n d ( x ⋅ s + z , − − 2 b − 1 , 2 b − 1 − 1 ) ] x_{q}=quantize(x,b,s,z)=clip[round(x\cdot s + z,--2^{b-1},2^{b-1}-1)] xq=quantize(x,b,s,z)=clip[round(xs+z,2b1,2b11)]

  • 量化的方式

  • pre-tensor

    • 同一块输入,比如某个卷积前的输入tensor,采用一个scale,该层的所有输入共享一个scale值
  • pre-channel

    • 一般用于权重,比如一个卷积权重的维度是 [ 64 , 3 , 3 , 3 ] [64,3,3,3] [64,3,3,3](输入通道数为3,kernel size = 3 x 3,输出通道数64),就会产生64个scale值
  • 分析一下为什么是这样

    • 卷积操作量化,卷积操作可以拆分成im2col+矩阵乘法
    • 偏置bias一般可以去掉,对精度影响也不大,暂时不考虑
      image.png
    • 上图输入X的维度为 [ m , p ] [m,p] [m,p]而W的维度为 [ p , n ] [p,n] [p,n],因此i的范围为 [ 0 , m ) [0,m) [0,m),k的范围为 [ 0 , p ) [0,p) [0,p)。W和Y同理。这里的输入和权重都是FP32精度,也就是实数。而对应的INT8精度的输入和权重,q下标就代表quantize也就是量化:
      X q = ( x q , i k ) ∈ Z m × p W q = ( w q , k j ) ∈ Z p × n \begin{aligned} X_ {q} =(x_{q,ik}) \in Z^{m\times p} \\ W_{q} = (w_{q,kj}) \in Z^{p\times n} \end{aligned} Xq=(xq,ik)Zm×pWq=(wq,kj)Zp×n
      把矩阵拆分成细粒度计算,即行和列每个元素相乘然后求和
      y i j = ∑ k = 1 p x i k ⋅ w k j ≈ ∑ k = 1 p d e q u a n t i z e ( x q , i k , s q , i k ) ⋅ d e q u a n t i z e ( w q , k j , s w , k j ) = ∑ k = 1 p 1 s x , i k x q , i k ⋅ 1 s w , k j w q , k j y_ {ij}=\sum_{k=1}^{p} x_{ik} \cdot w_ {kj} \approx \sum _ {k=1}^ {p} dequantize( x_ {q,ik} , s_ {q,ik} ) \cdot dequantize( w_ {q,kj} , s_ {w,kj} ) = \sum_{k=1}^ {p} \frac {1}{s_ {x,ik}} x_ {q,ik} \cdot \frac {1}{s_{w,kj}} w_{q,kj} yij=k=1pxikwkjk=1pdequantize(xq,ik,sq,ik)dequantize(wq,kj,sw,kj)=k=1psx,ik1xq,iksw,kj1wq,kj
      进一步,两个浮点型的运算可以被近似为INT8反量化后的运算,进一步等于量化后的运算:
      = ∑ k = 1 p 1 s x , i k x q , i k ⋅ 1 s w , k j w q , k j = \sum_{k=1}^ {p} \frac {1}{s_ {x,ik}} x_ {q,ik} \cdot \frac {1}{s_{w,kj}} w_{q,kj} =k=1psx,ik1xq,iksw,kj1wq,kj
      可以看到上式子每个输入元素都有自己的scale值,而我们必须把x和w的scale值提到最前面才能让x和w实现INT8类型的矩阵运算
      = 1 s x , i ⋅ s w , j ∑ k = 1 p x q , i k ⋅ w q , k j = \frac {1}{s_{x,i}\cdot s_{w,j}} \sum_{k=1}^ {p} x_ {q,ik} \cdot w_{q,kj} =sx,isw,j1k=1pxq,ikwq,kj
      为了把S提出来,k必须被干掉
      image.png
      image.png

卷积操作可以拆分成im2col+矩阵乘法,下图左边的kernel矩阵,每一行代表一个输出通道的kernel集合(这里因为输入图像是三通道的,因此kernel有三个,不同颜色代表一个kernel):
image.png
这就是pre-channel或者详细点就是per-output-channel也就是卷积输出通道,我们对每一个卷积权重的输出通道那一维进行量化,然后共享一个scale,这也就呼应了上述的公式!

6.2 参考二

对称量化vs非对称量化
这里的Wx应该一样高?like WX
image.png

7 考虑bias如何进行线性量化

对权重使用对称量化,Zero point = 0;(权重的分布特点)
为了把权重、激活、bias三项的Scale合并,令 S b = S W S X S_{b}=S_{W}S_{X} Sb=SWSX
且对bias使用对称量化,Zero point = 0;(bias的分布特点)
image.png

q b i a s = q b − Z X q w q_{bias}=q_{b}- Z_{X}q_{w} qbias=qbZXqw
image.png

7.1 对于FC Layer

image.png
只有整数的乘法、32bit的加法

7.2 对于Conv Layer

  1. 量化后的激活值和权重进行矩阵乘法(Nbit乘法
  2. 与32bit的 q b i a s q_{bias} qbias相加(这里加法都用int32是为了防止溢出
  3. 转Nbit int后,与scale相乘
  4. 加上Nbit的 Zero point Y

如何计算Y的量化参数Z和S?用数据集的图 计算统计值 called: collaboration)
image.png

7.3 线性量化性能

image.png

8 Summary

  • K-means量化,存储整数权重+浮点数码本、进行浮点数计算
  • 线性量化,存储整数权重、进行整数计算
  • 课程是按照量化的"aggressive"程度来梳理的,一开始的K-means计算还是浮点数计算,然后线性量化直接变成Integer计算,下一节课介绍更aggressive的量化方法
    image.png
    image.png

9 Reference

image.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值