ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

盘点一下后训练量化的基本操作

2022-03-21 12:59:31  阅读:240  来源: 互联网

标签:bin max 数值 盘点 搜索 量化 基本操作 255


(本文首发于公众号,没事来逛逛)

这篇文章简单聊聊后训练量化的一些常规操作。

一些基础知识

在此之前,还是需要先了解一下后训练量化 (下面简称 PTQ,Post-training Quantization) 是啥?具体细节这里就不展开了,不熟悉的读者欢迎看回我之前的文章 (神经网络量化入门–后训练量化。简单来说,后训练量化就是在不重新训练网络 (即不更新 weight) 的前提下,获取网络的量化参数。

说到量化参数,就不得不祭出量化的基本公式了 (假设用非对称量化,8bit):
r = S ( q − z ) (1) r=S(q-z) \tag{1} r=S(q−z)(1)

q = c l i p ( r o u n d ( r S + Z ) , 0 , 255 ) (2) q=clip(round(\frac{r}{S}+Z),0,255) \tag{2} q=clip(round(Sr​+Z),0,255)(2)

这里面的 r r r 和 q q q 分别表示量化前的浮点数和量化后的定点数。而 S S S 和 Z Z Z 就是两个重要的量化参数 scale (步长) 和 zero point (零点)。除此之外,还有两个非常重要的量化参数: r m i n r_{min} rmin​、 r m a x r_{max} rmax​,分别表示浮点数 r r r 的数值范围。

S S S、 Z Z Z、 r m i n r_{min} rmin​、 r m a x r_{max} rmax​ 构成了网络量化里面四个最重要的量化参数,几乎所有后训练量化算法,都是为了找到这几个东西。这里面, S S S、 Z Z Z 和 r m i n r_{min} rmin​、 r m a x r_{max} rmax​ 之间又是可以相互转换的:
S = r m a x − r m i n q m a x − q m i n (3) S = \frac{r_{max}-r_{min}}{q_{max}-q_{min}} \tag{3} S=qmax​−qmin​rmax​−rmin​​(3)

Z = c l i p ( r o u n d ( q m a x − r m a x S ) , 0 , 255 ) (4) Z = clip(round(q_{max} - \frac{r_{max}}{S}), 0, 255) \tag{4} Z=clip(round(qmax​−Srmax​​),0,255)(4)

公式里面的 q m a x q_{max} qmax​、 q m i n q_{min} qmin​ 表示定点数 q q q 的数值范围,在量化策略确定之后,数值一般就确定下来了。比如说,我这里采用 8bit 的非对称量化,那么量化后的数值范围一般就是 0~255,即 q m a x = 255 q_{max}=255 qmax​=255, q m i n = 0 q_{min}=0 qmin​=0。

公式 (3) 大家都能理解,但公式 (4) 写法比较多,容易搞晕。我简单画了张图,不明白的同学再琢磨琢磨。

对于一个常规的神经网络来说,只要我们知道了每一层权重 (weight、bias) 和每一层特征 (feature map) 的 S S S 和 Z Z Z (或者 r m i n r_{min} rmin​、 r m a x r_{max} rmax​,反正可以相互转换),理论上我们就可以用定点的方式跑网络了,从而获得内存访问和计算效率上的提升。为什么这里要说常规呢?因为有一些激活函数在定点的情况下难以运行,这类函数通常还是只能以浮点的形式计算,在一些只能跑定点运算的芯片上令人头疼不已。

后训练量化

了解完这些基础后,现在回到正题:如何找到合适的量化参数呢?

对于权重而言,在模型训练完成后数值就基本确定了,而对于 feature map 来说,却没法事先得知,因此会用一批矫正数据集 (通常就是训练集的一小部分) 跑一遍网络,以此来统计每一层 feature map 的数值范围。

navie的想法

有了权重和特征的数值范围后,一种很直接的方法就是根据数值范围的大小来确定 r m i n r_{min} rmin​、 r m a x r_{max} rmax​。我之前的文章()就简单采用了这种方法。但这种方法容易受到噪声的影响,比如,有些 weight 或者 feature 中可能存在某些离群点,它的数值较大,但对结果影响又很小,如果把这些数值也统计到 minmax 里面,就容易造成浪费。

举个栗子,如果某个 weight 里面的数值是 [-0.1, 0.2, 0.3, 255.1],那我们统计出来的 minmax 就是 -0.1 和 255.1,如此一来,0.2、0.3 这样的数值就会被映射到同一个定点数,信息损失相当严重,而它们对结果影响可能远大于 255.1。因此,在这种情况下,我们宁愿把 255.1 损失掉,也希望尽可能把 0.2、0.3 保持下来。

一些简单的改进

那该如何改进呢?

1. 直方图截断

既然离群点影响很大,那最容易想到的解法就是排除这些离群点的干扰。我们可以把 weight 或者 feature map 的数值范围统计出一个直方图,根据直方图舍弃前后 m% 的数值,直接用剩下的数值来确定 minmax。

2. 滑动平均

除此之外,还有一种对 feature map 比较有效的统计方法。 这也是 Google 论文提到的一种技巧 1 ^1 1。我们把矫正数据集分为几个 batch,逐次输入到网络中统计数值。每次更新数值范围时,按照 r m a x t = r m a x t ∗ ( 1 − α ) + r m a x t − 1 ∗ α r_{max}^t=r_{max}^t*(1-\alpha)+r_{max}^{t-1}*\alpha rmaxt​=rmaxt​∗(1−α)+rmaxt−1​∗α 来更新,其中, r m a x t − 1 r_{max}^{t-1} rmaxt−1​ 是上一次统计到的最大值。通过控制 α \alpha α 的数值,可以控制新数据对历史统计数据的影响,让最终统计到的数值能大致涵盖大部分数值,但又不会被一些离群点主导。

3. 均值和方差

一个不成文的约定:我们通常会假设 weight 和 feature 的数值呈正态分布。在此假设下,我们可以统计出测试数据中 weight 或者 feature 的均值 μ \mu μ 和方差 σ \sigma σ,然后,根据正态分布的性质,在区间 ( μ − 3 σ , μ + 3 σ ) (\mu-3\sigma, \mu+3\sigma) (μ−3σ,μ+3σ) 之间的数值占了 99+%,因此,可以令 r m i n = μ − 3 σ r_{min}=\mu-3\sigma rmin​=μ−3σ、 r m a x = μ + 3 σ r_{max}=\mu+3\sigma rmax​=μ+3σ,这样就基本涵盖了大部分数值,也避免了一些离群点的影响。

当然,如果实际的数值分布不是正态的,比如,是个双峰分布,那可能就 gg 了。

加点数学的味道

以上这些方法都比较 tricky (直方图要舍弃多少才合适?滑动平均的 α \alpha α 怎么设置?正态分布一定要取 3 σ 3\sigma 3σ?万一离群点很重要怎么办?),效果好坏全靠灵巧的双手。下面介绍几种更加 mathematic 的方法,看起来理论更加完备一些 (虽然对于神经网络来说, 有时候仍然很玄学)。

虽然扯到数学,但其实也没什么高大上的,无非就是找一些方法,可以让这些 tricky 的事情更加自动化一些。

这其中最关键的,就是找到一种度量信息损失的方法,可以告诉我们,当前取到的 minmax 值合不合适,是不是精度最高的。这些度量方法中,最常用的如欧式距离 (L2距离)、L1距离、KL散度、余弦距离等。

1. 搜索minmax

确定好度量方法后,我们就可以自动化地搜索最合适的数值范围了。最简单的思路就是在原本的 minmax 区间内,逐步搜索一个更小的数值范围,然后计算这个范围内的信息做了量化后有多少信息损失,损失越小,证明这个数值范围越合适。

江湖中人用的较多的 TensorRT 量化算法就是基于 KL 散度来搜索 minmax 的。TRT 采用的是 8bit 对称量化,即正数区间量化到 [0, 127],负数区间量化到 [-128, 0)。量化的大致过程如下:

  1. 首先根据矫正数据集确定数值范围 [ r m i n r_{min} rmin​, r m a x r_{max} rmax​];
  2. 把这个范围区间划分为 2048 份 (相当于离散化成 2048 个 bin 的直方图,具体多少 bin 可以调整);
  3. 以最前面的 128 个 bin 作为基准,逐次向后搜索,每次扩增一个 bin 的长度,得到一个新的数值范围。然后把这个数值范围重新划分为一个 128 个 bin 的直方图 Q Q Q (这一步相当于舍弃了部分数值信息,并做了量化);
  4. 那要如何评价当前这个数值范围是否合适呢?这个时候 KL 散度就能派上用场了。我们把剩下那些没有搜索到的数值压缩到当前搜索到的 bin 上,得到一个信息基本没有损失的直方图 P P P,如果我们之前搜索到的 Q Q Q 跟 P P P 相比信息损失最小 (即 KL 散度最小),那这个 Q Q Q 对应的数值范围就是最好的数值范围。不巧的是,KL 散度需要两个直方图的 bin 是一样的 (L1 距离等也有这个要求),而 Q Q Q 之前已经被量化到 128 个 bin 了。为了解决这个问题,需要把 Q Q Q 再反量化到跟 P P P 的 bin 数相同,这样就可以计算信息损失了。
  5. 重复步骤 3、4,记录每次搜索的 KL 散度大小,直到搜索完整个范围。KL 散度最小的搜索范围,就是理论上信息损失最小的 minmax。

其中的一些关键操作如量化、反量化等,限于篇幅这里就不展开讲了。

有人可能会问:按照这样搜索,那是不是最后一次把整个数值范围都包含进去的时候 KL 散度最小呢?毕竟搜索到最后一步我们没有舍弃任何数值。有这种疑惑是因为没有考虑到量化的影响。由于大部分情况下,数值分布都近似于正太分布 (即大部分数值会集中在一个区间内),而随着搜索范围增大,离群点会越来越多,但中间那些真正有用的、比较集中的数值就只能用更少的 bin 来表达 (要知道总共只有 128 个 bin 可以承载信息)。因此,绝大部分情况下,舍弃离群点 (outlier) 获得的收益往往是更大的。

以上就是 TRT 量化的大致过程,基本套路就是:从一个小的搜索范围逐渐扩大出去,每次搜索都量化一遍信息 (比如划分成固定 bin 数的直方图),然后用一种度量方式 (KL 散度、L1 距离等) 来衡量完整信息和量化信息之间的差异,差异最小的区间就是我们需要的 minmax。

2. 搜索S和Z

除了 minmax,我们也可以搜索合适的 S S S 和 Z Z Z。这里的套路和前面是类似的,也是根据量化前后的信息损失来找出最优解。

假设量化前的浮点 weight 或 feature map 为向量 r r r,那么量化后为:
q = c l i p ( r o u n d ( r S + Z ) , 0 , 255 ) (5) q=clip(round(\frac{r}{S}+Z),0,255) \tag{5} q=clip(round(Sr​+Z),0,255)(5)
再进行反量化后得到:
KaTeX parse error: No such environment: align at position 8: \begin{̲a̲l̲i̲g̲n̲}̲ \hat r&=S*(q-Z…
接下来就可以度量量化的信息损失了,在论文 EasyQuant 2 ^2 2 中使用了余弦相似性,因此这里我们也以余弦相似性为例。

假设矫正数据集总共有 N N N 个样本,那么平均相似性为:
1 N ∑ i N c o s ( r i , r i ^ ) = 1 N ∑ i N r i r i ^ ∣ ∣ r i ∣ ∣ ∣ ∣ r i ^ ∣ ∣ (7) \frac{1}{N}\sum_{i}^Ncos(r_i,\hat{r_i})=\frac{1}{N}\sum_i^N\frac{r_i \hat{r_i}} {||r_i||||\hat{r_i}||} \tag{7} N1​i∑N​cos(ri​,ri​^​)=N1​i∑N​∣∣ri​∣∣∣∣ri​^​∣∣ri​ri​^​​(7)
而我们要求解的,就是使得这个相似性最大的 S S S 和 Z Z Z (余弦相似性越大,信息损失越小):
max ⁡ S , Z 1 N ∑ i N r i r i ^ ∣ ∣ r i ∣ ∣ ∣ ∣ r i ^ ∣ ∣ (8) \underset{S, Z} {\operatorname {max}} \frac{1}{N}\sum_i^N\frac{r_i \hat{r_i}} {||r_i||||\hat{r_i}||} \tag{8} S,Zmax​N1​i∑N​∣∣ri​∣∣∣∣ri​^​∣∣ri​ri​^​​(8)
搜索 S S S 和 Z Z Z 的方法有很多,比如可以参考前面 TRT 的思路,先设定 S S S 和 Z Z Z 的范围,然后我们用两个循环分别对 S S S 和 Z Z Z 进行搜索遍历,计算每一步搜索的相似性分数,分数最大的就是我们需要的 S S S 和 Z Z Z。这种方法就是通常所说的 Grid Search

不过,由于我们已经有了 S S S 和 Z Z Z 的解析式了,所以完全可以梯度下降法,甚至直接对 (8) 式求解析解的方法,获得最优解。不过暂时没见过有文章这样处理,估计是因为解析式里面 round 这个函数不好求导吧。

当然,在网络结构比较复杂的情况下,单独针对每一层求解量化参数,并不一定能获得整个网络的最优精度,因此在 EasyQuant 2 ^2 2 论文中有很多 trick 来更好地求解量化精度,这个有机会后面再细讲。

总结

水了这么多,总算可以结尾了。这篇文章主要介绍了后训练量化的一些常用操作,包括如何用直方图简单地截取 minmax,以及 TensorRT 量化算法的套路等等。事实上,这些后训练量化的方法也完全可以用到量化感知训练中,后者无非是多了对权重的更新学习而已。

讲完基本操作,后面就是进阶版本了,可能会介绍一些更加前沿的后训练量化的论文。感兴趣的老铁点个赞和在看可好。

参考

  1. Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference
  2. EasyQuant: Post-training Quantization via Scale Optimization

欢迎关注我的公众号:大白话AI,立志用大白话讲懂AI。

标签:bin,max,数值,盘点,搜索,量化,基本操作,255
来源: https://blog.csdn.net/u012954083/article/details/123632603

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有