IncrementalNetwork-Quantization: INQ渐进量化方法详解
作者‖ Cocoon
编辑‖ 3D视觉开发者社区
3D开发者社区链接:https://mp.weixin.qq.com/s/GWyYcV6wVjxFnDOcU5ZMHg
概述
论文链接: https://arxiv.org/pdf/1702.03044v2.pdf
代码链接: https://github.com/Zhouaojun/IncrementalNetwork-Quantization
谷歌学术被引量: 797
该方法发表于ICLR 2017,由英特尔中国提出,目的是希望能够无损地用低位宽的权重表达神经网络,是量化领域中的经典论文之一。具体地,文章提出了一种渐进量化方式,其主要包含三个相互依赖的操作:权重划分、分组量化与重训练。即,首先通过某种分组规则将权重分为两个互不相干的组,然后对其中一组进行量化,而后将其冻结,再对另外一组以渐进迭代的方式进行重训练,目的是补偿第一组的量化损失。其中,渐进迭代的终止条件是所有的权值都被量化完毕。
下文将对权值量化的方式、渐进量化的策略以及整体的算法步骤进行介绍,并在实验部分贴出INQ相比起其他SOTA的对比效果及部分消融实验结果。
渐进量化
变长编码的权重量化(variable-length encoding scheme)
命名:
假设预训练的全精度的模型为{Wl:1≤l≤L}\{W_l: 1 \leq l \leq L\}{Wl:1≤l≤L},其中WlW_lWl表示第lll层的权重,LLL表示在模型中要学习参数的层数。为了对接下来的表达进行简化,我们只考虑对卷积层和全连接层进行量化。举个例子,就像AlexNetAlexNetAlexNet、VGG−16VGG-16VGG−16、GoogleNetGoogleNetGoogleNet以及ResNetsResNetsResNets之类的网络而言,对应于其中的卷积层,WlW_lWl可以是4D的tensor,对应于其中的全连接层,WlW_lWl可以是2D的矩阵。
设低比特版本的权重为Wl^\hat{W_l}Wl^,且其中的每一个元素只能从以下的集合中选取:
Pl={±2n1,⋯,±2n2,0}\mathbf{P}_{l}=\left\{\pm 2^{n_{1}}, \cdots, \pm 2^{n_{2}}, 0\right\} Pl={±2n1,⋯,±2n2,0}
其中n1n1n1和n2n2n2是两个整数,且n2≤n1n2 \leq n1n2≤n1。
也就是说,量化后的权重数值范围由n2n2n2和n1n1n1决定,在一定范围以外的数值会被直接怼成0。
任务描述:
给定一个预训练的全精度模型,INQ的目的是在尽可能不损失精度的前提下,将该32位的浮点型权重变换到2的整数幂或0上。
此外,还希望能够探索在网络无损量化限定下能支持的最极端的小位宽是多少。
怎么做?
在INQ中,期待的位宽bbb需要我们预先确定好,然后我们只要确定好超参n1n1n1就可以了,因为n2n2n2可以根据位宽bbb以及超参n1n1n1推断而得。
n1n1n1的计算方式为一个经验上有点复杂又实践证明有用的公式:
n1=floor (log2(4s/3))n_{1}=\text { floor }\left(\log _{2}(4 s / 3)\right) n1= floor (log2(4s/3))
其中,sss的计算方式为:
s=max(abs(Wl))s=\max \left(\operatorname{abs}\left(\mathbf{W}_{l}\right)\right) s=max(abs(Wl))
再其中,absabsabs为逐元素的操作。
当n1n1n1获得后,n2n2n2可以自然而然的通过n2=n1+1−2b−12n2 = n1+1-\frac{2^{b-1}}{2}n2=n1+1−22b−1而得,举个例子,当b=3b=3b=3,n1=−1n1=-1n1=−1时,n2=−2n2=-2n2=−2。
当侯选池PlP_lPl确定后,我们进一步地通过下式将WlW_lWl中的每一个元素变换成低比特的量化
值:
W^l(i,j)={βsgn(Wl(i,j))if (α+β)/2≤abs(Wl(i,j))<3β/20otherwise \widehat{\mathbf{W}}_{l}(i, j)= \begin{cases}\beta \operatorname{sgn}\left(\mathbf{W}_{l}(i, j)\right) & \text { if }(\alpha+\beta) / 2 \leq \operatorname{abs}\left(\mathbf{W}_{l}(i, j)\right)<3 \beta / 2 \\ 0 & \text { otherwise }\end{cases} Wl(i,j)={βsgn(Wl(i,j))0 if (α+β)/2≤abs(Wl(i,j))<3β/2 otherwise
其中,α\alphaα和β\betaβ是在侯选池PlP_lPl中相邻的两个元素,进而迫使量化后的权重都能够是侯选池中的元素。这里有一个小细节,即在公式(2)中的系数4/34/34/3的设定与公式(4)是强呼应的。
假设我们希望模型量化位数bbb是5,由于0不能够用2的整数次幂来表达,因此我们额外给出一个比特来表示0值,剩下的4个比特则用来表达最多16个2的整数次幂数。换句话说,候选的量化值的个数最多只有2b−1+12^{b-1}+12b−1+1个,这也对应点了该小节的“变长(variable-length )”的题。
显然,上述的量化方式是线性的,另一种可以选择的替代方案是“对数”的,尽管这种替代方案很可能也是有效的,但是在实现上以及计算开销上都有着更大的困难。
渐进量化策略
假设:
尽管我们可以直接使用上述的量化方式直接对全精度的模型进行量化,但是不可避免的,会遭遇很大的精度损失。
在当时已有的量化工作中,比如说HashedNet(Chen 等, 2015),BinaryConnect(Courbariaux等,2015)等,其实大家都会面临着掉点的问题,在大型的数据面前,掉点问题会显得更加突出。然而,发现已有的量化工作有一个共性,就是在量化的过程中都采用了全局的策略,即所有的权重参数同时地转换为低比特位的量化参数。而INQ认为,这种全局策略是导致精度损失的原因之一。此外,当量化比特位越低时,精度损失的越厉害。
INQ受当时的某些剪枝工作的启发,即在剪枝中,移除某些不那么重要的神经网络中的层所带来的精度损失往往可以通过后续的训练弥补回来,因此,INQ做出了这样的推测:改变网络权重的重要性是获得无损量化的关键。
策略:
在上述假设的基础上,INQ提出了三个互相依赖的操作:权重划分、逐组的量化、重训练。
权重划分将全精度的CNN中的每一层的权重划分为两个互不相关的组,这两个组主要起着互补的作用。在第一组的权重主要用于构成全精度网络的低比特版本,因此其中的权重直接使用公式(4)进行量化,而第二组的权重,则用于补偿模型精度的损失,因此他们需要被重训练。
一旦第一次量化和重训练的操作结束后,这三个操作将在第二组权重中以一种迭代的方式进行,迭代结束的条件是所有的权重都被量化完毕,这个过程就是所谓的渐进的网络量化和精度逐步提升的过程。这个过程的好处就是,低比特量化的精度损失可以被渐进策略很好的弥补。
INQ迭代的过程如Fig 2所示:
在Fig 2中,第一行表示在提出的三个操作中的第一次迭代,最左上角的cube表示权重划分操作,该操作产生了两个互不相关的组,中间的影像则表示对第一组权重的量化操作(绿色表示),第一行最右边表示对第二组的权重(浅蓝色表示)进行重训练。第二行表示了INQ中第二次、第三次、第四次的迭代。在这样的过程中,慢慢地量化参数的比例为50% - 75% - 87.5% - 100%。
对于第lll层来说,权重划分可以被表达为:
Al(1)∪Al(2)={Wl(i,j)},and Al(1)∩Al(2)=∅\mathbf{A}_{l}^{(1)} \cup \mathbf{A}_{l}^{(2)}=\left\{\mathbf{W}_{l}(i, j)\right\}, \text { and } \mathbf{A}_{l}^{(1)} \cap \mathbf{A}_{l}^{(2)}=\emptyset Al(1)∪Al(2)={Wl(i,j)}, and Al(1)∩Al(2)=∅
其中,Al(1)A_l^{(1)}Al(1)表示需要被量化的第一组权重参数,Al(2)A_l^{(2)}Al(2)则表示需要被重训练的第二组参数。具体分组的准则留到实验部分进行进一步地描述。
在这里,定义了一个二值的矩阵TlT_lTl来辅助辨别上述的两类权重。即,Ti(i,j)=0T_i(i,j)=0Ti(i,j)=0表示Wl(i,j)∈Al(1)W_l(i,j) \in A_l^{(1)}Wl(i,j)∈Al(1),而Tl(i,j)=1T_l(i,j)=1Tl(i,j)=1则表示Wl(i,j)∈Al(2)W_l(i,j) \in A_l^{(2)}Wl(i,j)∈Al(2)。
渐进网络量化算法
这一小节主要来介绍训练方法。
仍然以第lll层为例,量化的优化问题可以表示为:
minWlE(Wl)=L(Wl)+λR(Wl)s.t. Wl(i,j)∈Pl,1≤l≤L,\begin{array}{ll} \min _{\mathbf{W}_{l}} & E\left(\mathbf{W}_{l}\right)=L\left(\mathbf{W}_{l}\right)+\lambda R\left(\mathbf{W}_{l}\right) \\ \text { s.t. } & \mathbf{W}_{l}(i, j) \in \mathbf{P}_{l}, 1 \leq l \leq L, \end{array} minWl s.t. E(Wl)=L(Wl)+λR(Wl)Wl(i,j)∈Pl,1≤l≤L,
其中,L(Wl)L(W_l)L(Wl)表示网络损失,R(Wl)R(W_l)R(Wl)为正则项,λ\lambdaλ为正系数,且所有的权重只能从侯选池中选取。直接对这样的优化式进行求解是有挑战的,很容易会遇到不收敛的问题。
而前面我们提到过所谓的权重划分以及逐组量化,这两个操作可以使得公式(6)进一步变化到以下形式:
minWlE(Wl)=L(Wl)+λR(Wl)s.t. Wl(i,j)∈Pl,if Tl(i,j)=0,1≤l≤L,\begin{array}{ll} \min _{\mathbf{W}_{l}} & E\left(\mathbf{W}_{l}\right)=L\left(\mathbf{W}_{l}\right)+\lambda R\left(\mathbf{W}_{l}\right) \\ \text { s.t. } & \mathbf{W}_{l}(i, j) \in \mathbf{P}_{l}, \text { if } \mathbf{T}_{l}(i, j)=0,1 \leq l \leq L, \end{array} minWl s.t. E(Wl)=L(Wl)+λR(Wl)Wl(i,j)∈Pl, if Tl(i,j)=0,1≤l≤L,
由于PlP_lPl和TlT_lTl是已知的,所以该优化式而已直接使用SGDSGDSGD等优化算法进行求解。换句话说,重训练过程中的权重更新方式为:
Wl(i,j)←Wl(i,j)−γ∂E∂(Wl(i,j))Tl(i,j)\mathbf{W}_{l}(i, j) \leftarrow \mathbf{W}_{l}(i, j)-\gamma \frac{\partial E}{\partial\left(\mathbf{W}_{l}(i, j)\right)} \mathbf{T}_{l}(i, j) Wl(i,j)←Wl(i,j)−γ∂(Wl(i,j))∂ETl(i,j)
其中λ\lambdaλ表示正学习率。注意到二值矩阵TlT_lTl的存在会使得只有浮点数才会更新,这类似于某些剪枝方法中只有当前还没有被移除掉的层才会被重训练一样。
INQ的所有流程描述在以下算法中:
实验
ImageNet 上的结果
下表为将全精度不同的CNN模型通过INQ的方式转换为5比特模型时的掉点情况:
权重分组策略
权值分组将直接影响到后续的分组量化和重训练操作。分组的候选策略有两种,一种受剪枝算法的启发,认为绝对值较大的权重相对来说更为重要,再一种则是随机划分。
本节对ResNet进行量化,下表总结了INQ使用不同分组策略时5位量化的对比结果,显然,使用由剪枝算法启发的分组策略效果相对于随机划分要好:
也因此,文章采用了“Pruning-inspired”,即由剪枝算法启发的权值分组策略。
不过,文章也指出如何划分权重可以作为后续值得探索的问题之一。
期望位宽与模型精度之间的trade-off
与章节中3.2的实验设定一样,本节逐渐的减少量化位数(对应地增加迭代次数),观察无损量化的位宽极限。
具体地,有:
量化位数 | 量化渐进比例 |
---|---|
4 | 0.3, 0.5, 0.8, 0.9, 0.95, 1 |
3 | 0.2, 0.4, 0.6, 0.7, 0.8, 0.9, 0.95, 1 |
2 | 0.2, 0.4, 0.6, 0.7, 0.8, 0.85, 0.9, 0.95, 0.975, 1 |
实验结果为:
尽管看起来量化到2比特的时候,掉点比较厉害,但是相对于当时的SOTA来说,已经有所提升,具体对比结果见下表:
低比特压缩
在模型压缩角度上,实验与其他模型压缩的方式进行了对比实验,实验表明INQ在5位或4位的量化上几乎没有损失,且相比起其他压缩的方式,比如说剪枝(Han等, 2015)、矢量量化(vector quantization)(Gong等, 2014)、深度压缩(Han等, 2016)等,INQ的最终权值是2的整数次幂或0,其显著优势在于可以用于FPGA等硬件上。
具体的实验结果见下表:
结论
本文对经典量化方法之一:渐进量化,进行了介绍。该方法依赖三个核心操作:权重分组、分组量化、重训练,对全精度的神经网络模型进行预设位宽的量化。该方法相比起之前的量化方法最大的不同在于并非将所有权重同时进行量化,而是采用了渐进的策略,逐渐地对模型进行量化,与其他SOTA的对比实验结果表现了该策略的优越性。特别地,文章还在实验部分探索了无损量化的极限位宽,结果表明,尽管在两比特(3值)量化的掉点比较严重,却还是相对于当时其他的SOTA要好一些。
参考文献
- Matthieu Courbariaux, Bengio Yoshua, and David Jean-Pierre. Binaryconnect: Training deep neural networks with binary weights during propagations. In NIPS, 2015.
- Song Han, Jeff Pool, John Tran, and William J. Dally. Learning both weights and connections for efficient neural networks. In NIPS, 2015.
- Song Han, Jeff Pool, John Tran, and William J. Dally. Deep compression: Compressing deep neural networks with pruning, trained quantization and huffman coding. In ICLR, 2016.
- Wenlin Chen, James T. Wilson, Stephen Tyree, Kilian Q. Weinberger, and Yixin Chen. Compressing neural networks with the hashing trick. In ICML, 2015.
- Yunchao Gong, Liu Liu, Ming Yang, and Lubomir Bourdev. Compressing deep concolutional networks using vector quantization. arXiv preprint arXiv:1412.6115v1, 2014.
IncrementalNetwork-Quantization: INQ渐进量化方法详解相关推荐
- INQ渐进量化方法详解
作者| Cocoon 编辑| 3D视觉开发者社区 ✨如果觉得文章内容不错,别忘了三连支持下哦
- Incremental-Network-Quantization增量网络量化论文详解
Incremental-Network-Quantization增量网络量化论文详解 笔者将从以下几个方面分析该论文的原理及其实现,由于笔者能力有限,如有错误望诸公指正. 论文作者代码:https:/ ...
- moviepy音视频剪辑:视频剪辑基类VideoClip的属性及方法详解
☞ ░ 前往老猿Python博文目录 ░ 一.概述 在<moviepy音视频剪辑:moviepy中的剪辑基类Clip详解>和<moviepy音视频剪辑:moviepy中的剪辑基类Cl ...
- python统计csv行数_对Python 多线程统计所有csv文件的行数方法详解
如下所示: #统计某文件夹下的所有csv文件的行数(多线程) import threading import csv import os class MyThreadLine(threading.Th ...
- python修改文件内容_Python批量修改文本文件内容的方法详解
这篇文章主要介绍了Python批量修改文本文件内容的方法的相关资料,需要的朋友可以参考下 Python批量替换文件内容,支持嵌套文件夹 import os path="./" fo ...
- python二维元组_python中读入二维csv格式的表格方法详解(以元组/列表形式表示)
如何去读取一个没有表头的二维csv文件(如下图所示)? 并以元组的形式表现数据: ((1.0, 0.0, 3.0, 180.0), (2.0, 0.0, 2.0, 180.0), (3.0, 0.0, ...
- Spring JdbcTemplate方法详解
2019独角兽企业重金招聘Python工程师标准>>> Spring JdbcTemplate方法详解 标签: springhsqldbjava存储数据库相关sql 2012-07- ...
- golang 解析php序列化,golang实现php里的serialize()和unserialize()序列和反序列方法详解...
Golang 实现 PHP里的 serialize() . unserialize() 安装 go get -u github.com/techleeone/gophp/serialize 用法 pa ...
- ES5和ES6数组遍历方法详解
ES5和ES6数组遍历方法详解 在ES5中常用的10种数组遍历方法: 1.原始的for循环语句 2.Array.prototype.forEach数组对象内置方法 3.Array.prototype. ...
最新文章
- Android5.1.1源码 - zygote fork出的子进程如何权限降级
- 神经网络反向传播梯度计算数学原理
- Single Number II(LintCode)
- Python-OpenCV 处理图像(一):基本操作
- 【爬虫笔记】爬虫基础
- 做人要无需,做事要务实!
- phpthink验证旧密码_忘记MacBook密码解决方法
- power bi指标呈现_在Power BI中使用关键绩效指标
- Lync Server 2013 安装体验(二)
- linux里面的命令
- 海归博士程序员光鲜背后:下车间写代码,体验炼钢灼人的热度
- 智慧解析第20集:破解迷魂术
- python pytorch库_一个简单而强大的深度学习库—PyTorch
- Linux 目录权限
- c#仿qq好友列表控件
- 剖析《口袋妖怪复刻版》技术架构
- 至强cpu能装linux吗,至强四核CPU Xeon 安装Linux系统后 能利用到4个核吗?
- 企业上云,安全合规如何进阶 ——一文拆解亚马逊云科技云安全理念与实践
- 蓝天保卫战之产品测试服务
- 幼儿园计算机教师论文,幼儿园计算机辅助教学中教师角色定位研究
热门文章
- 【视觉高级篇】25 # 如何用法线贴图模拟真实物体表面
- Python—实现本地音乐播放器(添加/播放/暂停/下一首/上一首/音量/打开超链接)
- html 分享到新浪微博,JQuery用鼠标选文字来发新浪微博
- 拼多多店铺名可以进行修改吗?
- 2011级-csdn-java-张侃— 过滤器
- 华清远见重庆中心-面向对象技术总结/个人总结
- 基于遗传算法求解车辆路径问题
- 倍福TwinCAT(贝福Beckhoff)基础教程 松下驱动器如何执行绝对值清零
- 图片玻璃光影效果制作
- python获取最新学术文献会违反图书馆规定吗_台湾学术文献数据库