1. 量化的基本概念
A. 问题设置和符号表示
假设网络有L层,其每层的参数表示为:{W1,W2,…,WL}\left\{W_{1}, W_{2}, \ldots, W_{L}\right\}{W1,W2,…,WL},用θ\thetaθ表示所有参数的集合,以监督学习问题为例,其目标函数为:
L(θ)=1N∑i=1Nl(xi,yi;θ)(1)\mathcal{L}(\theta)=\frac{1}{N} \sum_{i=1}^{N} l\left(x_{i}, y_{i} ; \theta\right) (1) L(θ)=N1i=1∑Nl(xi,yi;θ)(1)
假设θ\thetaθ是训练好的浮点精度的参数,那么,量化要实现的是:将参数θ\thetaθ以及中间激活值的精度降低到低精度,同时对模型的泛化能力/精度影响最小。
量化最重要的一步是量化函数的定义,即将权重值和激活值映射为有限数值的函数。
根据量化函数的不同,可以将量化分为:对称量化、非对称量化;均匀量化、非均匀量化。
B. 均匀量化与非均匀量化
量化函数为:
Q(r)=Int(r/S)−Z(2)Q(r)=\operatorname{Int}(r / S)-Z (2) Q(r)=Int(r/S)−Z(2)
Q是量化算子,r是实值输入(激活或权重),S是实值缩放因子 (论文中常见的说法是steps),Z是整数零点。 此外,Int函数通过四舍五入操作(例如四舍五入和截断)将一个实值映射为一个整数值。实质上,这个函数是一个从实值r到一些整数值的映射。这种量化方法也被称为均匀量化,因为产生的量化值(论文中常见的说法是 levels)是均匀间隔的。
经过量化函数之后,还有一个步骤称为 去量化 (dequantization),从量化值Q®中恢复实值r:
r~=S(Q(r)+Z)(3)\tilde{r}=S(Q(r)+Z) (3) r~=S(Q(r)+Z)(3)
请注意,由于四舍五入操作,恢复的实值r~\tilde{r}r~将不完全匹配 r。
还有一些非均匀量化方法,其量化值不一定是均匀间隔的。这种量化与上述的均匀量化相对应。
**非均匀量化:**量化steps以及量化levels允许非均匀的间隔。其定义如下:
Q(r)=Xi,ifr∈[Δi,Δi+1)(4)Q(r)=X_{i}, \text { if } r \in\left[\Delta_{i}, \Delta_{i+1}\right) (4) Q(r)=Xi,ifr∈[Δi,Δi+1)(4)
具体来说,当一个实数r的值落在量化步骤Δi\Delta_{i}Δi和Δi+1\Delta_{i+1}Δi+1之间时,量化器Q将其投射到相应的量化级别XiX_{i}Xi。请注意,XiX_{i}Xi和Δi\Delta_{i}Δi的间隔都不是均匀的。非均匀量化可能会在固定的位宽下达到更高的精度,因为人们可以通过更多地关注重要的值区域或找到合适的动态范围来更好地捕捉分布。例如,许多非均匀量化方法是为权重和激活的钟形分布而设计的。
一个常用的非均匀量化方法是使用对数分布进行量化,即量化steps和量化levels以指数形式增加而不是线性增加。另一个常见的非均匀量化是binary code-based,其中一个实数向量r∈Rnr \in R^nr∈Rn被量化为m个二进制向量相加的方式,即:r≈∑i=1mαibi\mathbf{r} \approx \sum_{i=1}^{m} \alpha_{i} \mathbf{b}_{i}r≈∑i=1mαibi,这里的 αi\alpha_{i}αi是尺缩因子,是一个实数值,bi\mathbf{b}_{i}bi 是二值向量,bi∈(−1,+1)\mathbf{b}_{i} \in (-1,+1)bi∈(−1,+1)。
为了进一步改进量化器,还可以非均匀量化看为一个优化问题。如公式5所示,通过最小化原始张量和量化后张量之间的误差来自动调节量化器Q中的量化steps/levels。
minQ∥Q(r)−r∥2(5)\min _{Q}\|Q(r)-r\|^{2} (5) Qmin∥Q(r)−r∥2(5)
当然,量化函数中的steps/levels 也可以作为可学习的参数与网络参数一起被训练,这种称为可学习量化函数。
除了上述的基于某些规则或者基于梯度优化自动学习的非均匀量化方法之外,也可以利用kmeans聚类获得量化steps/levels。
均匀量化和非均匀量化的总结:
非均匀量化使我们能够更好地捕捉信号信息,通过分配比特和将参数范围非均匀地离散化。然而,非均匀量化方案通常很难在一般的计算硬件上有效部署,例如GPU和CPU。均匀量化是目前常用的方法,因为它的简单性和对硬件的高效映射。
C. 对称量化与非对称量化
均匀量化的一个重要因素是公式(2)中比例因子S的选择。这个比例因子实质上是将一个给定的实值范围r划分为若干个分区:S=β−α2b−1S=\frac{\beta-\alpha}{2^{b}-1}S=2b−1β−α,其中[α,β]表示剪裁范围,这是一个有界的范围,我们用它来剪裁实值,而b是量化位宽。因此,为了定义缩放因子S,首先应该确定裁剪范围[α,β]。选择裁剪范围的过程通常被称为校准。而根据选择裁剪范围的方法不同,又可以将量化分为对称量化和非对称量化。
一个直接的选择是使用信号的最小/最大值作为裁剪范围,即α=rmin\alpha=r_{min}α=rmin,β=rmax\beta=r_{max}β=rmax。这种方法是一种不对称的量化方案,因为裁剪范围不一定相对于原点对称,即 −α≠β-\alpha\neq\beta−α=β。也可以通过选择−α=β-\alpha = \beta−α=β的对称剪裁范围来使用对称量化方案。一个流行的选择是根据信号的最小/最大值来选择:−α=β=max(∣rmin∣,∣rmax∣)-\alpha = \beta = max(|r_{min}|,|r_{max}|)−α=β=max(∣rmin∣,∣rmax∣)。
与对称量化相比,非对称量化通常会导致更严格的裁剪范围。当目标权重或激活值不平衡时,这一点尤其重要,例如,ReLU之后的激活总是有非负值。然而,使用对称量化,通过用Z=0替换零点,简化了公式(2)中的量化函数。
Q(r)=Int(r/S)(6)Q(r)=\operatorname{Int}(r / S) (6) Q(r)=Int(r/S)(6)
比例因子S的计算也有两种方式:“full range”和“restricted range”。
“full range”: S=2max(∣r∣)2n−1S = \frac{2 \max (|r|)}{2^{n}-1}S=2n−12max(∣r∣) , 对于使用INT8来说,其使用的范围是:[-128,127];
“restricted range”: S=max(∣r∣)2n−1−1S = \frac{\max (|r|)}{2^{n-1}-1}S=2n−1−1max(∣r∣) , 对于使用INT8来说,其使用的范围是:[-127,127];
“full range”的方法更准确。对称量化在实践中被广泛采用,用于量化权重,因为将零点清零可以导致推理过程中计算成本的降低,同时也使实现更加直接。
使用信号的最小/最大值进行对称和非对称量化是一种流行的方法。然而,这种方法很容易受到激活中离群数据的影响。这些数据会不必要地增加范围,从而降低量化的分辨率。解决这个问题的一个方法是使用百分位数而不是信号的最小/最大值。也就是说,不使用最大/最小值,而使用第i个最大/最小值作为β/α。
除了上述方法之外,通过最小化真实值和量化值之间的KL损失来选择β和α也是一种重要的方法。
对称量化与非对称量化的总结:
对称量化使用一个对称的范围来划分剪裁。这样做的好处是更容易实现,因为它导致了公式2中的Z=0。然而,对于范围可能偏斜且不对称的情况,它是次优的。对于这种情况,非对称量化是首选。
D. 静态量化与动态量化
根据何时确定裁剪的范围,可以将量化分为静态量化和动态量化。
在动态量化中,这个范围是在运行时为每个激活图动态计算的。这种方法需要实时计算信号统计(最小、最大、百分位数等),这可能有非常高的开销。然而,动态量化通常会带来更高的精确度,因为信号范围是为每个输入精确计算的。
另一种量化方法是静态量化,在推理过程中,剪裁范围是预先计算的,而且是静态的。这种方法不增加任何计算开销,但与动态量化相比,它通常会导致较低的精度。
动态量化与静态量化的总结:动态量化动态地计算每个激活的裁剪范围,往往能达到最高的精度。然而,动态计算一个信号的范围是非常昂贵的,因此,常使用的一般是静态量化,即所有输入的削波裁剪是确定的。
E. 量化粒度
量化方法的一个区别在于如何计算权重的剪切范围[α, β]的颗粒度,一般可以有下述分类:
a)逐层量化:剪裁范围是通过考虑一个层的卷积滤波器中的所有权重来确定的,对一层中所有卷积滤波器使用相同的剪切范围[α, β],虽然这种方法实现起来非常简单,但它往往会导致次优的准确性,因为每个卷积滤波器的范围可以有很大的变化。例如,一个参数范围相对较窄的卷积核可能会因为同一层中另一个参数范围较宽的核而失去其量化分辨率。
b)分组量化: 在一个层内对多个不同的通道进行分组,以计算裁剪范围。虽然会更加精确,然而,这种方法不可避免地增加计算不同比例系数的额外成本。
c)逐通道量化:为每个卷积滤波器使用一个固定值,与其他滤波器无关。每个滤波器都被分配了一个专用的比例系数。这确保了更好的量化分辨率,往往能带来更高的精度。
量化粒度的总结: 通道量化是目前用于量化卷积核的标准方法。它使实践者能够以可忽略不计的开销为每个单独的内核调整削波范围。
F. 量化后的微调方法
根据在量化之后是否需要重新训练模型可以将量化的方法分为:量化感知训练(QAT)和训练后量化(PTQ)。
量化感知训练(QAT): 给定一个训练好的模型,量化可能会给训练好的模型参数带来扰动,这可能会使模型偏离它在用浮点精度训练时收敛的点。可以通过用量化的参数重新训练网络模型来解决这个问题,这样模型就可以收敛到一个有更好损失的点。一种常用的方法称为量化感知训练(QAT),其通常在前向和反向传递过程中以浮点数进行,但在每次梯度更新后,模型参数会被量化。反向传播中的一个很关键的地方在于如何处理不可微分的量化算子,这个算子的梯度几乎在任何地方都是零,一般使用直通估计器(STE)来近似这个算子的梯度。
QAT的总结:尽管STE是粗略的近似,但QAT已经被证明是有效的。然而,QAT的主要缺点是计算成本太高。因为其需要重新训练网络模型,这种训练可能需要花费几百个epoch,对于低比特的量化,更是如此。当前,高效的量化部署很重要,很多时候重新训练整个量化模型被认为是过于耗时和没必要的。
训练后量化(PTQ): 训练后量化(PTQ),它执行量化后没有任何微调,计算开销非常低。与需要足够数量的训练数据进行再训练的QAT不同,PTQ有一个额外的优势,即它可以在数据有限或无标签的情况下应用。然而,与QAT相比,这往往是以较低的精度为代价的,特别是对于低精度量化。
PTQ的总结:在PTQ中,所有的权重和激活值量化参数的确定都不需要对NN模型进行任何重新训练。因此,PTQ是一种非常快速的量化NN模型的方法。然而,与QAT相比,这往往是以较低的精度为代价的。
G. 随机量化
前面所述的量化都是确定性的量化方案,有一些工作探索了随机量化。一种直觉是,与确定的量化相比,随机量化可能会让NN探索更多。主流观点认为:小的权重更新可能不会导致任何权重变化,因为舍入操作可能总是返回相同的权重。然而,启用随机四舍五入可能为NN提供一个逃脱的机会,从而更新其参数。具体来说:随机量化将浮点数值向上或向下映射的概率与权重更新的幅度相关。具体如下式:
Int(x)={⌊x⌋withprobability⌈x⌉−x⌈x⌉withprobabilityx−⌊x⌋(7)\operatorname{Int}(x)=\left\{\begin{array}{ll} \lfloor x\rfloor & \text { with probability }\lceil x\rceil-x \\ \lceil x\rceil & \text { with probability } x-\lfloor x\rfloor \end{array}\right. (7) Int(x)={⌊x⌋⌈x⌉withprobability⌈x⌉−xwithprobabilityx−⌊x⌋(7)
2. 量化的高级概念:低于8bit的量化
A. 模拟量化(假量化)与纯整数量化
在模拟量化中,量化后的模型参数以低精度存储,但操作(如矩阵乘法和卷积)是以浮点运算进行的。因此,量化后的参数需要在浮点运算之前进行反量化。因此,人们不能完全受益于模拟量化的快速有效的低精度逻辑。然而,在纯整数量化中,所有的操作都是使用低精度的整数运算,这允许用高效的整数算术进行整个推理,而不需要对任何参数或激活值进行浮点反量化。
一般来说,用浮点运算进行全精度推理可能有助于提高最终的量化精度,但这是以不能从低精度逻辑中获益为代价的。在延迟、功耗和面积效率方面,低精度逻辑比全精度逻辑有多种好处。如下图所示:
模拟量化与纯整数量化的总结:一般来说,与模拟量化相比,纯整数量化更可取。这是因为纯整数量化使用较低的精度的算术逻辑,而模拟量化则使用浮点逻辑来进行运算。然而,这并不意味着模拟量化永远没有用。事实上,模拟量化方法对那些受带宽限制而不是受计算限制的问题是有益的,比如在推荐系统中,对于这些任务,瓶颈是内存占用和从内存加载参数的成本。因此,对于这些情况,进行模拟量化是可以接受的。
B. 混合精度量化
当我们使用较低精度的量化时,硬件性能会提高。然而,将一个模型均匀量化为超低精度会导致精度显著下降。 可以通过混合精度量化来解决这个问题。如下图所示,每层都以不同的比特精度进行量化。这种方法的一个挑战是,选择这种不同bit位设置的搜索空间是层数的指数级。为每一层选择这种混合精度基本上是一个搜索问题。
既然可以将混合精度的设置等价为一个搜索问题,那么NAS中的一些策略自然也可以应用在这里。
当前,设置混合精度的方法有基于强化学习(RL)的方法来自动确定量化策略, 或者将混合精度配置搜索问题表述为神经结构搜索(NAS)问题,并使用可微分NAS(DNAS)方法来有效地探索搜索空间。
但是这些基于搜索的方法的一个缺点就是:往往需要大量的计算资源,其性能通常对超参数甚至初始化都很敏感。
另一类混合精度方法使用周期性函数正则化来训练混合精度模型,在学习各自的位宽时,自动区分不同的层和它们在精度方面的不同重要性。
与这些基于探索和正则化的方法不同,HAWQ引入了一种自动的方法,根据模型的二阶敏感性找到混合精度设置。理论上表明,二阶算子的轨迹(即Hessian矩阵)可以用来衡量一个层对量化的敏感性。自然,敏感性越高的层应当使用更大的比特宽度。这种方法被证明比基于RL的混合精度方法快100倍以上。最近,在HAWQv3中,引入了一个纯整数的、硬件感知的量化方法,提出了一个快速的整数线性编程方法,为给定的特定应用约束(例如,模型大小或延迟)找到最佳位精度。
混合精度量化的总结:
混合精度量化已被证明是对不同NN模型进行低精度量化的一种有效的、具有硬件效率的方法。在这种方法中,NN的各层被分组为对量化敏感/不敏感。对不同的层使用不同的量化比特宽度。
C. 硬件感知的量化
量化的目标之一是改善推理延迟。然而,并不是所有的硬件在某一层/操作被量化后都能提供同样的速度。事实上,量化的好处与硬件有关,许多因素,如片上存储器、带宽和缓存层次影响量化的速度。
考虑这一事实对于通过硬件感知量化实现最佳效益非常重要。
最近一项工作,直接在硬件中部署量化操作,并测量不同量化位精度的每一层的实际部署延迟。
D. 蒸馏辅助量化
这种量化方法就是结合模型压缩中常用的模型蒸馏法,通过引入一个教师模型辅助量化的训练过程。其本质与模型压缩中的蒸馏是一样的。
E. 极致量化----二值量化
量化的极端情况:只使用1bit量化,这种量化目前还算火热,量化之后的速度具有非常大的提升,但是精度的下降也很厉害。二值量化也几乎可以独立为一个很重要的研究方向。目前不打算研究该量化,这部分就先略过。
F. 矢量量化
在信息论中,特别是在数字信号处理领域,量化作为一种压缩工具被广泛研究。然而,机器学习的量化方法的主要区别在于,从根本上说,我们感兴趣的不是以与原始信号相比最小的变化/错误来压缩该信号。相反,我们的目标是找到一个降低精度的表示,使损失尽可能小。因此,如果量化后的权重/激活与非量化后的权重/激活相差甚远,也是完全可以接受的。
因此,DSP中的经典量化方法有很多有趣的想法也可以被应用于NN量化,特别是矢量量化。
比如,使用聚类方法。已经有研究表明,使用k-means聚类法是足以将模型大小减少8倍,而不会出现明显的精度下降。
参考文献如下,想要获得更多详细的信息还是请阅读原论文,感谢原论文作者做出的贡献。
@article{gholamisurvey, title={A Survey of Quantization Methods
for Efficient Neural Network Inference}, author={Gholami, Amir and
Kim, Sehoon and Dong, Zhen and Yao, Zhewei and Mahoney, Michael W and
Keutzer, Kurt}, journal={arXiv preprint arXiv:2103.13630},
year={} }