Deep Compression
思路
Pruning:less number of the weights.
Quantization:less bits per weihts.
Huffman Encoding.
整体结构
具体实现
Pruing
- 将低于阈值的权值prune,实际上就是将它置为0,因为并没有改变网络结构,因此不会减少运算量。
经过prune之后,权值矩阵也就是卷积核变成稀疏矩阵,因此在嵌入式设备的存储就需要特定的结构,如果没有存储稀疏矩阵的特定存储结构单元,那么prune就没有达到模型压缩的目的。
韩松大佬的做法是利用CSR(Compressed Spare Row)+相对索引(卷积层用8位来编码,全链接层用5位来编码)进行存储。
CSR:将行的信息压缩了,只显式保留每行第一个非零的信息。
三个数组 val , col_ind , row_ptr 。
val 存储的是非零值,从左到右,从上到下。
col_ind 存储的是 val 在其行中对应的索引。
row_ptr 记录的是每一行第一个非零元素对应在 val 的索引,最后一个元素存储非零元素的个数。
假设非零个数为 a ,行数为n ,则利用CSR格式存储的稀疏矩阵就需要存储 2a+n+1 个元素,而不是 n2 个,因为稀疏矩阵情况下 n2≫2a 。the index difference:目的是将绝对的index进行编码从而进一步减少存储空间(以前的卷积核比较大,现在卷积核都已经变得小了,这个存储相对索引是否不重要了)。下面以3位编码说明一下超出最大相对距离的话如何处理:
如果是用3位进行编码的话,那么最大相对距离就是8,如上图所示,如果超出8的话就在 val 补0,之后的相对索引按正常来算。
量化和权值共享
具体做法:
先用k-means聚类方法将权值聚成
k
簇,相应的中心点仍由32位浮点数来表示,而原先的权值分别用其所属的簇的序号索引来表示,原先的权值矩阵就可以由
权值共享:
- k-means聚类,将
W={w1,w2⋯,wn}
聚类到
C={c1,c2,⋯,ck}
,其中
n≫k
,主要就是减少类间的欧氏距离之和,即:
初始化中心点
选择初始化中心点的策略前需要看权值的分布,上图是AlexNet Conv3 layer的权值分布。有三种可选的初始化策略:
1.Forgy(random)
从上图可以看出,权值基本分布在[-0.05,0]和[0,0.05]两个区间中,因此选择Forgy的初始化策略的话,那么中心点会集中分布在这两个区间概率密度函数peak附近(权值出现概率大的话那么随机选到的概率也会增大),Forgy策略会有一个缺点就是会忽略概率密度函数边缘对应的权值,会使它们聚类到非最理想的中心点。
2.Density-based
基于密度的初始化策略具体做法是将CDF(累积分布函数)y坐标进行线性划分,对应回去的x坐标的值就是初始化的中心点,从上图可以看出,这种策略比Forgy有优势,但还是和Forgy有同样的缺点。
3.Linear
Linear策略先将区间[权值的最小值,权值的最大值]进行线性划分,这样的策略是不会受权值的分布所影响,k的值也会影响最终的聚类的效果,因此需要选择一个合适的k。- 反向传播(只更新共享权值)
由上图可以知道,计算中心点的梯度:先计算每个权值的梯度,对应回权值所属的类将其每一类的权值梯度相加就可得到每个中心点的梯度,用数学式子表示就是:
∂L∂Ck=∑i,j∂L∂Wij∂Wij∂Ck=∑i,j∂L∂WijI(Iij=k)
再利用SGD更新中心点的梯度。
- 反向传播(只更新共享权值)
Huffman 编码
哈夫曼编码暂时不讨论
实验结果
韩松大佬做了很多实验,他所做的实验能看出他的研究思路,怪不得能得best papper. 其它的就不看了,只看看在VGG16上得的压缩情况。