深度模型压缩

在早期工作中,DNN模型时旨在最大化准确率而忽视了具体实现的复杂度,然而这将会导致模型实施和部署遇到挑战,为了解决这个问题,人们进行了很多尝试。最近研究工作表明,DNN模型和硬件的协同设计可以在最小化能耗和成本的同时,最大化模型的准确率和吞吐量,这增加了模型被采用的可能性。本节中,我们将会强调目前在模型和硬件协同设计方面所作的各种不同的努力。我们的目标不仅是减少能耗和增加吞吐量,而且要最小化在精度上的损失。
协同设计方法可以简单划分为以下类别:

  1. 减小操作和操作数的精度,这个包括浮点到定点、较少位宽、非线性量化和权重共享;
  2. 减少操作数的数量和模型大小,这个包括压缩、修剪和紧凑的网络架构。

一: 减小精度

最近的工作中各种用来减小精度的关键技术都被总结在下表1中,包括目前探索应用在权重和激活上的线性和非线性量化技术,表中准确率的影响是以32位浮点数的准确率为基准。
在这里插入图片描述1. 线性量化
在这里插入图片描述
对于单精度浮点数表示方法不懂的同学,可以移步:https://blog.csdn.net/liubing8609/article/details/78844121;
对于一个N位的定点数,其表示的数值大小为(-1)^s x m x 2^(-f),其中s为符号位,m为(N-1)位尾数真值,f决定了小数点的位置,相当于一个比例因子。比如,当f=0时,8位定点数可以表示的动态范围值位-128~127。由于在网络中各层的动态范围值通常是不同的,使用动态定点数,在不进行微调的时候可以将权重和激活值分别较少到8位和10位,而在微调的作用下两者均可以达到8位。

线性量化和对数量化的公式如下:
在这里插入图片描述先介绍线性量化公式,公式中的minV和maxV是原始权重中的最小值和最大值,bitwidth表示为拟用的定点数位宽,round(x)即为令x四舍五入取得的数,clip(x,min,max) = min * I(x<min) + max * I(x>=max) + x * I(min<=x<max);
在对数量化中,LogAP2(x) = sign(x) x 2^(round(log2|x|))。

当我们更为激进的把权重或激活值的精度降低到一位时,我们就得到了二值化网络(Binaryy Nets),它是将权值全都转换位-1或1,这样的话乘加运算就会变为加运算,大大降低了计算复杂性;另一种是三值化网络,权重限制在[-1, 0, 1]的某个值,关于二值化和三值化我会另开篇幅进行介绍。

2. 非线性量化

在这里插入图片描述

当网络中各层权重 分布均匀时,我们倾向于选择线性量化的方式,但是根据上图所示,各层权重和激活值的分布并不均匀,因此非线性量化分方式可能更有利于提高准确率,目前有两种比较流行的方法:
(1)对数量化
当权重分布如上图中的(b)一样,呈现出对数分布,可能采用对数量化更好一点,例如,在VGG-16中,使用4b的线性量化会导致27.8%的准确率损失,而采用以2为底的对数量化则只有5%的准确率损失,而且,采用以2为底的对数量化后,权重是2的指数次方,因此乘法运算就可以用移位操作来代替乘法运算。
(2)权重分享
在这里插入图片描述权重共享就是令多个值很接近的权重共享一个权重值,这样可以大大减少全一个卷积核或者层内不同的权重值,就是先对权重进行分组,然后令每一个组内的权重取同一个权值。这一部分的内容在Deep Compression文章中有详细介绍,如上图所示:
(1)先对权重进行分组,在图中分了四组,对于左上角中的原始权重矩阵中的每一个权重所属分类做了标号得到矩阵custer index,同时取每组权重的中心值作为该组权重的共享值得到centroids;
(2)对于分好组的权重更新梯度时,将梯度矩阵也按原来的分组方式进行排列,将同组的梯度值相加,然后用其于学习率的乘积更新(1)中得到的centroids。
在这里插入图片描述权值共享的权值实际上是聚类中心的值,确定聚类中心的方法:
A. 随机的方法,就是在权重中随机的选取k个值作为聚类中心,如上图中的random initialization;
B. 基于密度的初始化,我们可以看这个图,横轴是对应的权值的值,纵轴是权值的数量,类似于直方图一样,红色的线是权值的直方图统计,蓝色的线是权值的累积统计,类似于概率密度函数和概率累积函数。基于密度的初始化就是把权值的数量从小到大等分成k份,然后每一份分界点的权值就是聚类的中心;
C. 线性的初始化就是直接在最小值最大值之间线性进行划分。

因为网络中大的权值往往是更重要的,前两种方法容易让聚类的中心点往概率密度大的地方累积,而线性分类法权值更容易是大的。所以线性的初始化方法比较好,通过后面的实验,也发现通过线性的分类方法取得了更好的准确率。

二:减少操作数的数量和模型大小

除了上面所述通过减小操作数精度的方法之外,还有大量的研究是关于较少操作数数量和模型大小的,这些技术可以简单的分为:利用激活特性、网络剪枝、网络架构设计和知识蒸馏。

1. 利用激活函数的特性
在这里插入图片描述
我们都知道ReLU是一种广泛应用于卷积神经网路中的非线性激活函数,将wx+b的值过ReLU函数时,可以将负数权重值置零,从而得到一个稀疏网络。从这一点来看,使用ReLU作为激活函数要比其它的非线性激活函数要好很多。

除了压缩之后存储成本较少以外,也可以在硬件上做相应改进,当输入为0时,直接跳过读取和MAC过程,这一步可以将能耗成本降低45%。

2. 网络剪枝

为了训练网络容易,我们的网络往往是冗余的,为此,我们可以设定一个阈值,将权重值低于该阈值的权重直接置零,即小权重被修剪,模型经过微调之后可以再次恢复到原来的准确率;在没有微调的情况下,大于有50%的权重可以被剪掉而对模型准确率没有什么影响,如果在剪枝之后,再次训练网络让其恢复原来的准确率(这个过程就叫做微调),通过这种手段我们可以砍掉80%的权重冗余。

然而以单独的权重数量作为能耗的唯一判别标准是不合理的,举个例子,在AlexNet中,在全连接层的权重要比在卷积层的权重要多得多,但是卷积层的能耗要远高于全连接层。一个能耗评估的方法就是对各个层次memory的数据流动、MAC的数量和权重的稀疏度综合考虑。
在这里插入图片描述
经过剪枝之后,怎样能更好的存储稀疏矩阵也是我们非常感兴趣的地方,分为CSR(compression sparse row)和 CSC(compression sparse column)两种方式:
在这里插入图片描述
CSR存储稀疏矩阵的方法

首先把所有的非零值存为AA,假设所有的非零值的元素的个数为a,然后把每一行第一个非零元素对应在AA的位置存为JA,最后一个数是所有非零元素的个数+1,所以JA中的元素就是行数n+1,然后把AA中每一个元素在原始矩阵中的列存为IC。所以我们把一个原始的n×n的稀疏矩阵存为2a+n+1个数字。

第一行AA存储所有的非零元素;
第二行JA存储所有系数矩阵中每行第一个非零元素在AA的位置,例如第一个元素是4.0,在AA中位置是第一个,第二行第一个元素是4.0,在AA中位置是第四个。通过JA可以将AA中所有元素对应的行恢复出来;
第三行JC是所有元素对应的列标。

CSC存储稀疏矩阵的方法:

第一行AA存储所有的非零元素(按照从上到下,从左到右的顺序);
AA = 4.0 2.5 1.0 4.0 1.0 1.0 4.0 1.0 4.0 0.5 2.5 1.0 4.0
第二行JA存储所有稀疏矩阵中每一列第一个非零元素在AA中的位置;
JA = 1 3 6 9 11 14
第三行IC存储所有元素的行标。
IC = 1 5 1 2 3 2 3 4 4 5 1 3 5

3. 紧凑的网络架构

权重数量和操作次数也是可以通过改进网络结构减少的,趋势就是使用一系列小的卷积核替代一个大卷积核,这样可以使得参数量大大减少。这个步骤既可以应用在网络训练之前,即在模型设计过程中做替代;也可以在模型训练后去分解大的卷积核。通常来讲后者避免了训练网络时的麻烦性,但是也增加了局限性,比如现有的方法只能将大的卷积核分解为中间无非线性激活层的小卷积核。

(1) 训练前

关于如何用多个尺寸较小的卷积核来替代一个大卷积核以及 1 x 1 卷积核的作用,我在之前的 “视觉分类任务”已经讨论过,下面是链接地址:https://blog.csdn.net/h__ang/article/details/87883103

(2) 训练后

张量分解可以在不影响准确率的情况下对训练后的网络进行分解,它是将一个四维张量分解为小维度张量的结合。这一部分牵扯到的数学知识比较深,我也没有完全看懂(哭脸),先推荐一个链接,感觉写的还可以,等我理解了自己再写一篇总结:https://zhuanlan.zhihu.com/p/24798389

4. 知识蒸馏

使用深度神经网络或者集成多个模型有助于提高预测的准确率,但是这样做的话计算复杂度会更高,为了能够在两者之间取得平衡,Hinton大神在2015年提出了一种叫做“知识蒸馏(Knowledge Distillation)”,Hinton在一些报告中称之为Dark Knowledge。核心思想是通过迁移知识,从而通过训练好的大模型得到更加适合推理的小模型。这个概念最早在06年的Paper: Model Compression中, Caruana提出一种将大模型学习到的函数压缩进更小更快的模型,而获得可以匹敌大模型结果的方法。

soft target(大模型的预测输出)这个概念,传统的分类问题实际上就是一种从输入空间到输出空间的映射,假如说我们有1000个类别,那么输出空间就对应有1000个点,每个点就是一个one hot编码的类别信息,而我们在训练网络时使用的标签一般都是离散的,即每一张图对应的one hot标签只有一个对应位置为1,其余为0;其实这样做有一个很大的问题,就是类别之间的相似性信息没有被体现出来,比如说一个图片分类数据库有猫,狗,自行车,卡车,汽车等类别,图片的标定只给了这张图A是狗,这张图B是卡车,而并没有给出图A里面的狗会更像猫,图B里面的卡车会更像汽车。而 KD就是一种简单弥补分类问题监督信号不足的方法
在这里插入图片描述知识蒸馏的一个核心思想就是使用soft target辅助hard target(真实标签)一起训练,步骤如下:
1、训练大模型:先用hard target,也就是正常的label训练大模型;
2、计算soft target:利用训练好的大模型来计算soft target,也就是大模型“软化后”再经过softmax的output;
3、训练小模型,在小模型的基础上再加一个额外的soft target的loss function,通过lambda来调节两个loss functions的比重;
4、预测时,将训练好的小模型按常规方式(右图)使用。

值得注意的是,教师网络(左侧)的预测输出在送入softmax之前除了一个温度参数(Temperature),这样可以获得软化的概率分布(软目标),数值介于0~1之间,取值分布较为缓和。Temperature数值越大,分布越缓和;而Temperature数值减小,容易放大错误分类的概率,引入不必要的噪声。举个例子,加入说本来未送入softmax前的向量为[6, 3, 1],经过softmax放大之后,1处对应的概率仅为0.0063,而如果我们在送入之前先除个比例因子10将向量变为[0.6, 0.3, 0.1],那么1处对应的概率就是0.25,这样得到的概率更号的表征了类与类之间的相似性。

猜你喜欢

转载自blog.csdn.net/h__ang/article/details/88072278