Cheng, Y., Wang, D., Zhou, P., & Zhang, T. (2017). A survey of model compression and acceleration for deep neural networks. arXiv preprint arXiv:1710.09282.
主要内容
目前的DNN太庞大,使得计算需要的时间和空间都很大。为了优化这个问题,科学家们提出了压缩模型的各种方法。
- 4大主流的模型压缩方法——
参数简化和共享 找出模型中多余的参数并去除。
低秩因子分解 用矩阵分解的方法,用分解后简化的矩阵来表示原参数矩阵。
压缩卷积核 增加卷积核之间的约束关系来优化空间和计算。
知识蒸馏 训练一个小网络来逼近大网络的训练效果。 - 新兴的几种方法——动态容积网络,随机深度网络
- 主要用来评估这些算法的指标——压缩率,加速率
- 这个领域的困难与挑战,以及未来可能的发展方向
问题背景
牛逼的那些DNN到底有多大?
2012的CNN(已经算参数少的了),6千万个参数,5卷积层+3全连接。在NVIDIA K40的机器上要训练2-3天 (Krizhevsky et al. , NIPS, 2012) 。人脸识别网络,几亿个参数 (Taigman et al., CVPR, 2014; Lu et al., CoRR, 2016)。纯靠全连接的网络甚至有几十亿个参数 (Dean et al., NIPS, 2012) 。
在移动设备上的使用局限
移动设备的内存,CPU,续航能力都有限,经不起那么大的网络折腾。比如ResNet-50有50个卷积层,仅处理一个图片就需要95M和38亿次的浮点数乘法。经过优化之后可以减少75%的参数,节省50%的计算时间。
四大主流压缩算法
名称 | 简述 | 优化哪些层 | 其他特性 |
---|---|---|---|
参数简化和共享 | 去除多余参数 | 卷+全 | 效果好,通用性好,支持新+预 |
低秩因子分解 | 矩阵分解 | 卷+全 | 标准化流程,易用性,支持新+预 |
压缩卷积核 | 卷积层重设计 | 卷 | 应用场景不同算法不同,通常效果好,只支持新 |
知识蒸馏 | 小网络逼近大网络 | 卷+全 | 应用场景和网络结构设计不同,效果差异很大,只支持新 |
*卷:卷积层;全:全连接层
*新:从头训练的模型(train from scratch);预:预训练模型(pre-trained model)
这些方法各有各的优势,有些可以结合着使用效果更佳,接下来我们就分别对这些方法进行描述。
方法1:参数简化和共享 (Parameter pruning and sharing)
方法1-1:量子化和二值化(Quantization and binarization)
包括用K-means 聚类减少参数数量[6,7],把参数压缩到8-bit[8], 16-bit[9],用霍夫曼编码(Huffman coding)来压缩码表[10]。用二阶偏导来衡量网络参数的重要性[11]。最极端情况干脆二值化参数,也就是参数只有可能是0或1,形成二值网络[12-14]。
缺点 二值网络在简化大型网络的时候损失较大
方法1-2:剪枝和参数共享(Pruning and sharing)
最早的剪枝算法是偏差权重衰减(Biased Weight Decay) [18].
The Optimal Brain Damage [19] and the Optimal Brain Surgeon [20] methods 根据the Hessian of the loss function来削减链接的数量。
这几种方法需要从头训练模型。
近来开始流行对预训练的模型进行剪枝[21,22],用哈希码表来储存参数,实现参数共享[23]。也已经有工作把上述的压缩,剪枝,参数贡献融合在一个统一的流程中[24]。
也有一些新兴的工作,将稀疏约束(sparsity constraints)加入到CNN的训练中[25-28]。大大减少了卷积核的数量,甚至是层数。
缺点 剪枝有很多需要手动调整的地方,对于某些应用场景来说太复杂了。
方法1-3:设计结构矩阵(Structural matrix)
由于全连接层的参数过多,而且f(x,M) = σ(Mx),这里的σ(·)不是一个线性变化(因为引入了层间的非线性变换,如Relu),是对于每个元素特异的变换。
也就是说本来这个矩阵中每个值之间完全没有关系,我就得把每个值都单独存下来, 计算量也是O(mn)。现在我创建一种关系来约束部分的参数,那我只需要存这个关系就好了,不用存那么多值了。
缺点 人为地进行约束会降低模型地准确率,而且对特定任务找到合适的约束关系本身就很难,现在还没有一种靠谱的理论来定位这个约束关系。
方法2:低秩因子分解(low-rank factorization)
这个方法的核心是对卷积核进行低秩分解,分解之后重要的信息被保留下来,计算的速度也提高了。
对于预训练的模型,可以一层一层的分解卷积核,分解完一层之后这层的参数就固定了,但是因为会有损失,下一层要先继续调参,再分解。
也有人提出基于低秩因子分解从头训练的做法[40]。Canonical Polyadic (CP)[39],Batch Normalization (BN)[40]这两种方法都可以做分解,效果都很好,但是前者存在有时候找不到一个最优的秩(best rank-K)的情况。具体是什么数学方法没有看。
全连接层是二维的矩阵,同样也可以用这种方法进行降维。
缺点 分解本身需要的计算量很大;只能逐层分解,不能进行全局的优化;为了达到跟原模型相近的效果,需要重新训练的量较大(因为每一层分解之后都要重新调参)。
方法3:压缩卷积核(transferred/compact convolutional filters)
(这句话也没有引用,但是感觉说的挺有道理在这里存个档。)
CNNs are parameter efficient due to exploring the translation invariant property of the representations to the input image, which is the key to the success of training very deep models without severe over-fitting.
这个方法的核心思想其实跟结构矩阵挺像的,只不过这个方法是针对卷积层做的处理。
由于卷积层中有大量的卷积核,如果对他们进行随机的初始化,会发现最后训练出来也有很多的冗余。比如,有一些卷积核,是另一些卷积核的-1倍。这样我们还不如在一开始定义一些卷积核的约束规则,比如直接定义有一些核是另一些的-1倍[45]。(文献中的方程4)
反正定不定义训练出来都是类似的特征,为什么要定义这个约束呢?当然是首先节省了储存卷积核的空间,同时也节省了训练所需要的计算量。
虽然理论上不知道为什么,但是实际训练显示,如果卷积核之间有些关联的话效果甚至会更好。
缺点
这个方法对比较宽的浅层网络(e.g. VGG)效果较好,但是对窄而深的网络(e.g. GoogleNet,Residual Net)效果不好。另外,这种约束定义之后有时候会造成训练结果的不稳定。
方法4:知识蒸馏(knowledge distillation)
要把一个复杂模型进行压缩,有人想到可以通过迁移的方法来把核心信息提取出来,但是之前这个方法只限于在浅层模型上操作[50]。
知识蒸馏这个概念是后来提出来的,它把复杂模型比作老师,目标的压缩模型,即简单模型比作学生,把老师的知识迁移到学生身上,并让学生在处理问题上的表现尽可能去逼近老师,就是知识蒸馏的核心算法。
数学方法的主要步骤就是,把学生网络和老师网络的输出结果看成两个分布,我要让这两个分布尽可能的接近。那么我首先要把输出结果(例如代表A类的输出神经元的值为0.8,B类的0.2,C类的0.2)转化为标准化的分布,并且我想尽可能突出最大值。这里就用到softmax函数,把输出结果映射到(0,1)上的分布,并且让值的和为1。
接下来我要基于当前两个分布的差异,来定义一个损失函数,我的目标就是让这个损失尽可能的小。这里常用的损失函数就是交叉熵损失函数(CrossEntropy Loss)。
一般我们用KL散度的值表示俩概率分布之间的差异,而交叉熵是等于KL散度加上一个常量(信息熵),其公式相比KL散度更容易计算,因此在机器学习中常常使用交叉熵损失函数而不是KL散度。
现有的KD算法中,FitNets[53] 提出如何将宽而浅的模型,压缩成窄而深的模型。这些算法在各大数据集(e.g. MNIST, CIFAR-10, CIFAR-100, SVHN, AFLW) 都得到了有效的验证,学生网络有的时候甚至比老师网络的效果更好。
之后的工作[54-57]进一步优化了这个算法的计算速度,或是寻找一下更宽松的训练条件(e.g. Attention Transfer (AT) [57]),又能达到相近的效果。
缺点 这个方法只能用在用softmax+crossentrophy loss训练的网络上,所以也有一些局限。另一方面,这个方法有时候约束条件太严格了,不一定训练得出来。
方法5:其他新兴的方法
基于注意的算法是最近比较新的趋势,它的核心思想是,在训练时,选择性地关注那些和任务相关的网络结构,而不是整个网络,通过这种方式来大幅节省计算量。
Dynamic capacity network (DCN) [59] 的设计包括了两个网络,一个小型网络和一个大型网络,训练数据先经过小网络,确定一下主要激活的是哪些区域,然后再喂给大网络,这时只需计算那些重要区域的权重就可以了。
Sparsely-gated mixture-of-experts Layer (MoE) [60] 的思想也是只计算那些重要的梯度,这个MoE模块是由很多个专家网络构成的,并且另外有一个负责做选择的网络,通过训练它可以对不同的输入数据,选择不同的专家网络的组合来学习。
针对残差网络的压缩,也有几项研究提出随机深度(stochastic depth)的算法[63-65],相当于对于每个输入数据(batch),随机(或者根据某种规则)抽掉几层网络进行训练。(感觉跟dropout差不多)
还有一些研究对池化层(pooling)进行优化,但是仅仅是提高计算速度,没有压缩空间。
模型压缩的评估标准和基准模型
压缩工作要基于一些基准的模型进行改进,或者跟他们的效果进行比较,现有的一些基准模型大概如表格所列。
基准模型 | 代表性工作 |
---|---|
Alexnet [1] | structural matrix [29], [30], [32] low-rank factorization [40] |
Network in network [73] | low-rank factorization [40] |
VGG nets [74] | transferred filters [44] low-rank factorization [40] |
Residual networks [75] | compact filters [49], stochastic depth [63] parameter sharing [24] |
All-CNN-nets [72] | transferred filters [45] |
LeNets [71] | parameter sharing [24] parameter pruning [20], [22] |
评估一个压缩工作的效果主要是两方面,空间的压缩程度和计算速度的提升程度。这两方面分别由压缩率(compression rate)和加速率(speedup rate)。
压缩率是用基准模型的参数量a,除以压缩后模型的参数量a*得到的。(也有用右边这种的)
加速率则是用基准模型需要的训练时间s,除以压缩后模型的训练时间s*得到的。
对于小模型来说,这两个评估指标通常是高度相关的。但是不同的模型这两个指标的关系也会有差异。比如图像处理的CNN,它主要是刚开始几层的大量卷积操作,浮点数计算比较耗时间。但有些DNN(几百层的)很瘦的,主要是全连接层的参数占据了大多数的空间和时间。
总结与讨论
关于如何选择压缩算法
总的来说并没有一个统一的准则,而是根据具体的应用场景来的。作者提供了一些参考建议。
- 如果你的应用场景需要压缩一个预训练的深度网络,那么推荐剪枝、参数共享或者低秩因子分解。如果是需要一个端到端的解决方案,可以考虑低秩因子分解和压缩卷积核。
- 在目标数据集集中在某个领域的情况下(比如医学图像识别),用一些人工干预比较多的算法(如压缩卷积核,结构矩阵)更好(可能算是引入一些人的经验和知识?)。
- 对模型准确度保留要求高的,优先选择剪枝和参数共享。
- 如果目标数据集是很小的话,可以使用知识蒸馏,迁移的效果好。
- 多种方法可以组合起来用,比如用低秩因子分解来压缩卷积层,用剪枝来压缩全连接层。
压缩技术面临的挑战
目前对于深度网络的压缩算法还处于一个比较初级的阶段,面临很多的困难和挑战。
- 目前主流的压缩算法都是基于比较成熟的CNN结构的,对于更复杂的网络结构,没有比较好的通用算法。
- 在小型设备(如手机,自动驾驶汽车,机器人)上,深度神经网络的应用还是有局限,怎么利用有限的计算资源是一个亟待解决的问题。
- 剪枝算法虽然有效,但是会带来层结构的改变,影响下一层的输入数据大小(没明白这是什么大问题)。
- 人工干预很多的算法(压缩卷积核,结构矩阵)会带来训练结果的不稳定性,还没有一个好的办法来控制这种影响。
- 知识蒸馏是一种前景很好的方法,还需要更多的研究来提升它的效果。
- 目前最大的挑战在于,搞不清楚信息被删掉或者保留到底是什么原因,目前还是一个黑箱,只知道效果好不好。如果能够知道这个规则的话对于算法来说会很有利。
可能的解决方案
- Learning-to-learn strategies [76,77] 可以帮助解决网络结构的问题。
- 根据硬件结构进行加速设计。
- 对于剪枝算法引起的结构动态变化,有一些工作加入了结构变量。剪枝后留下的结构本身,也可以为网络的设计提供思路。
- 知识蒸馏的一种可能的方法是,根据任务的需要进行部分网络的迁移。数据激活的区域更可能是任务相关的。
- 压缩卷积核和结构矩阵是基于预先给定的一些约束的,通常来说这些约束是空间变化,最好是把约束定为所有空间变化的集合,并且和所有参数一起训练。
- 除了图像识别,在其他领域我们也希望看到一些深度神经网络的压缩工作,比如视频处理,自然语义识别等。
重要词汇 (字母序)
- crossEntropy Loss 交叉熵损失函数,用来评价俩分布之间的差异。https://blog.csdn.net/b1055077005/article/details/100152102
- hessian matrix 黑塞矩阵,又译作海森矩阵、海瑟矩阵、海塞矩阵等,是一个多元函数的二阶偏导数构成的方阵,描述了函数的局部曲率
- low-rank factorization 低秩因子分解
- parameter pruning and sharing 参数简化和共享
- transferred/compact convolutional filters 压缩卷积核
- knowledge distillation 知识蒸馏
- sparsity constraints 稀疏约束,该方法是一种压缩估计。它通过构造一个罚函数得到一个较为精炼的模型,使得它压缩一些系数,同时设定一些系数为零。https://blog.csdn.net/m0_37167788/article/details/78653402
- softmax 用于分类过程,它把一些输出的神经元映射到(0-1)之间的实数,并且归一化保证和为1,从而使得多分类的概率之和也刚好为1。 https://www.jianshu.com/p/7e200a487916
- softmax loss function 说的就是softmax+crossentropy loss,是一个约定俗成的搭配
- state-of-the-art 目前最好的
- train from scratch 从头训练一个模型出来
- train from pre-trained model 拿预先训练好的模型在目标数据集上调优