1. 摘要
在许多现实应用中,深度神经网络的部署由于其高额的计算成本变得很困难。在这篇论文中,我们提出了一种新颖的CNNs学习方案,它同时满足:
- 减小模型大小;
- 减少运行时的内存占用;
- 在不影响精度的同时,降低计算操作数;
利用通道稀疏化这样一个简单但却有效的方法,上面的条件很容易获得。不同于许多已经存在的方法,我们的方法可以直接应用到现代CNN网络架构中,在训练过程引入最小的花销,而且不需要其他特殊的软硬件加速器。我们将我们的方法称为“网络瘦身”,输入模型是一个宽大的网络,但是在训练期间不重要的通道可以被自动鉴别,随后删除,进而在几乎没有精度损失的情况下得到一个瘦且紧凑的网络。我们通过几个最先进的CNN模型,包括VGGNet、ResNet、DenseNet,在几种不同的图像分类数据集上展示了我们的方法的有效性。对于VGGNet,网络瘦身的Muti-pass方案(实质上就是将网络瘦身这个过程多重复几次)使得在模型大小上压缩了20x,在计算量上面压缩了5x。
论文链接:https://arxiv.org/abs/1708.06519
代码:https://github.com/liuzhuang13/slimming
2. 背景介绍
CNN网络在现实应用中的部署主要面临三大挑战:
- 模型大小:CNN优异的性能表现来源于上百万可训练的参数。那些参数和网络结构信息需要被存储到硬盘,然后在推理期间加载到内存中。举个例子,一个在ImageNet上预训练好的模型需要超过300M空间,这对于嵌入式设备来说是一个很大的负担;
- 运行时间占用内存:在推理期间,CNN的中间激活值/响应存储空间甚至需要比存储模型参数的大,即使batchsize是1.这对于高性能的GPU来说不是问题,但对于低计算能力的许多应用来说这是不可承担的;
- 计算量:在高分辨率图片上卷积操作可能会计算密集,一个大的CNN在嵌入式设备上可能要花费几分钟来处理一张单个图片,这使得在真实应用中采用很不现实;
许多工作都已经被提出来压缩大的CNN模型,使其可以直接学习更高效的模型来做快速推理。这些方法包括低秩近似、网络量化、二值化、权重剪枝、动态推理等。然而,它们都只能解决上面提到的一到两个挑战,而且,这些技术需要特别设计专门的软硬件加速器来执行加速。
减少大的CNN资源消耗的另一个方向就是稀疏化网络,在不同结构层次上稀疏化,会产生可观的模型大小压缩和推理的加速。然而,这些方法通常需要特别的软硬件加速器来获得内存和时间上的节省,尽管这已经比非结构稀疏化权重矩阵容易的多。
在这篇论文中,我们提出了网络瘦身,它解决了前面提到的所有挑战。我们的方法是将L1正则化施加到BN层的缩放因子上,L1正则化推动BN层的缩放因子趋向于零,这使得我们能够鉴别出不重要的通道或者神经元,因为每一个缩放因子都和一个特定的CNN卷积通道(或者全连接层的一个神经元)相关联。这有助于后续的通道剪枝,另外正则化也很少损伤性能,甚至一些情况下它会导致更高的泛化准确率,剪掉不重要的通道有时候虽然会暂时降低性能,但是通过之后对剪枝网络的微调可以对精度补偿。在剪枝之后,更窄的网络会在模型大小、运行阶段的内存占用、计算量方面都会更显得紧凑。将上面的过程重复几次,就可以通过多阶段的网络瘦身获得更紧凑的模型。
在几个基准数据集和不同的网络架构上的实验表明我们可以将CNN模型大小压缩20倍、计算量压缩5倍,同时实现相同甚至更高的准确度。而且,我们的方法使用传统硬件和深度学习软件包实现模型压缩和推理加速。
在本文我们将从五个方面讨论相关工作:
- 低秩分解:“Exploiting linear structure within convolutional networks for efficient evaluation”这篇工作中使用像奇异值分解(SVD)这样的低秩近似技术,但是这种方法主要是在全连接层的表现比较好,可以将模型大小压缩3倍,但是没有明显的速度加速,因为CNN的计算量主要是来自卷积层;
-
权重量化:“Compressing neural networks with the hashing trick”这篇工作中的HashNet提出了量化网络权重,在训练之前,网络权重被分为不同的组,在每一个组内的权重共享权值。按照这种方法,只有共享的权重值和哈希索引需要被存储,因此可以节省大量的存储空间。在深度压缩中使用提高的量化技术在AlexNet和VGGNet上实现了 35x-49x 的压缩比。然而,这些技术既不能节省运行时的内存,又不能节省推理时间,因为在推理期间,共享的权重需要被恢复到原来的位置(相当于还多了个解码的过程)。
“Imagenet classification using binary convolutional neural networks” 和“Training deep
neural networks with weights and activations constrained to+1 or-1”将真实的权重值量化为二值/三值化权重(即将真实值限制为{-1,1}或{-1,0,1}),这极大的压缩了模型大小,同时由于位操作库的使用速度也很快。然而,这种激进的低位近似方法通常会伴随着相当的精度损失。 -
权重剪枝/稀疏化:韩松之前的“Learning both weights and connections for efficient neural network.”这篇工作中,提出了在训练网络中剪枝掉不重要的连接关系,这样的话网络中的权重大多数变成了0,可以使用一种稀疏的模式存储模型。然而,这些方法需要专门的稀疏矩阵运算库或硬件来做加速,运行时的内存占用节省非常有限,因为产生的激活值仍然是密集的。
韩松的这篇工作在训练期间没有给稀疏化任何指导,“Training sparse neural networks”这篇工作中通过给每个权重引入额外的门变量强加了稀疏约束,实现了更高的压缩比率。但是其仍然没有解决上面的缺点。 -
结构剪枝/稀疏化:目前,"Pruning filters for efficient convnets"提出了在训练CNNs时剪枝通道,然后通过微调来恢复精度;"The power of sparsity in convolutional neural networks"在训练之前,通过随机抛弃channel-wise的连接引入稀疏化,也得到了一个更小的网络;与这些网络相比,我们是在训练过程中将channel-wise稀疏化强加到优化目标函数中,导致了一种更平滑的通道剪枝过程和比较的小的精度损失。
"Towards compact cnns"在训练期间引入神经元级别的稀疏化,因此一些神经元会被剪掉从而获得紧凑的网络。"Learning structured sparsity in deep neural networks"提出了一种SSL方法来对结构的不同层级稀疏化。这两种方法都在训练时使用了"组稀疏正则化"来获得结构稀疏化,与前面的方法不同,我们的方法将简单的L1稀疏化强加到channel-wise的缩放因子上,优化目标更加简单。
由于这些方法都是对网络结构的(channels,neurons等)一部分做剪枝或稀疏化,而不是对个别权重,因此它们不太需要特别的库来实现推理加速和运行时的内存节省。我们的网络瘦身就属于这个类别,完全不需要其他的特定库支撑。 - 神经结构学习:最先进的模型比如VGG、GoogleNet、ResNet等通常都是由专家设计的,也有一些在自动学习网络结构方面的探索,"Neural network architecture optimization through submodularity and supermodularity"在有限的资源预算下,为网络结构搜索引入了子模块/超模块;"Neural architecture search with reinforcement learning"和"Designing neural network architectures using reinforcement learning"这两篇工作提出了使用强化学习自动学习神经网络结构,这些方法的搜索空间非常大,因此常常需要从上百个模型中辨别好坏,网络瘦身可以看作是一种结构学习的方法,尽管对于每个层的宽度选择非常有限,然而,与前面的方法相比,网络瘦身仅通过单个训练过程就学习到网络结构,这是十分高效的。
3. 网络瘦身
我们提供了一种简单的方案来实现通道级稀疏化。在本节,我们首先讨论通道级稀疏化的优势和遇到的挑战,然后介绍我们利用BN的缩放层来高效鉴别和剪枝不重要的层。
channel-wise稀疏化的优势:正如之前讨论的,稀疏化可以在不同级别实现(weight-level,kernel-level,channel-level,layer-level)。细粒度的稀疏化(weight-level)由最高的灵活性和泛化性能,也能获得更高的压缩比率,但是它通常需要特殊的软硬件加速器才能在稀疏模型上快速推理。相反,粗粒度 layer-level稀疏化不需要特殊的包做推理加速,但是它灵活性上不如细粒度。事实上,只有深度足够深(超过50层),移除某些层才会很高效。相比之下,channel-wise稀疏化在灵活性和实现上做了一个平衡,它可以被应用到任何典型的CNN或者全连接层(将每个神经元看作一个通道),由此得到的网络本质上也是一个瘦的网络,可以在卷积CNN平台上快速推理。
挑战:实现通道稀疏化需要将和一个通道有关联的所有输入和输出的连接都剪掉,但是对于已经预训练好的一个模型来说,不太可能做大这点,因此这个对已经预训练好的模型做通道剪枝效率不高,比如对预训练好的ResNet做通道剪枝,在不损伤准确率的情况下,只能减少10%的参数量。"Learning structured sparsity in deep neural networks"这篇文章中通过将稀疏正则化强加到训练目标函数中,具体来讲,就是采用group Lasso来使得所有filters的同一个通道在训练时同时趋于0。然而,这个方法需要额外计算新引入的和所有filters有关的梯度项,这是一个问题。
缩放因子和稀疏性惩罚:我们的注意是对每一个通道都引入一个缩放因子γ\gammaγ,然后与通道的输出相乘。接着联合训练网络权重和这些缩放因子,最后将小缩放因子的通道直接剪除,微调剪枝后的网络。特别地,我们的方法的目标函数定义为:
(x,y)是训练输入和目标,W是网络中可训练参数,第一项是CNN网络的训练损失函数,g(.)是在缩放因子上的惩罚项,λ\lambdaλ是两项的平衡因子。在我们的实验中,我们选择g(s)=|s|,即L1-正则化,被广泛地用于稀疏化。次梯度下降法作为不平滑(不可导)的L1惩罚项的优化方法,另一个建议是使用平滑的L1正则项取代L1惩罚项,尽量避免在不平滑的点使用次梯度。
剪掉一个通道的本质是要剪掉所有与这个通道相关的输入和输出连接关系,我们可以直接获得一个窄的网络(Figure 1),而不需要借用任何特殊的稀疏计算包。缩放因子扮演的是通道选择的角色,因为我们缩放因子的正则项和权重损失函数联合优化,网络自动鉴别不重要的通道,然后移除掉,几乎不影响网络的泛化性能。
利用BN层的缩放因子:BN层已经被大多数现代CNN网络采用,作为一种标准的方法来使得网络快速收敛并获得更好的性能。BN归一化激活值的方法给了我们设计一种简单高效的方法的灵感,即与channel-wise缩放因子的结合。尤其是,BN层使用mini-batch的统计特性对内部激活值归一化。$z_{in}$和$z_{out}$分别是BN层的输入和输出,B指代现在的minibatch,BN层执行下面的转换:
通常的做法是在卷积层之后插入一个BN层,引入channel-wise的缩放/平移参数。因此,我们直接将BN层的γ\gammaγ参数作为我们网络瘦身的缩放因子,这样做的一个优势在于没有给网络带来额外的花销。事实上,这也可能是我们能够学习到的最有意义的做通道剪枝的缩放因子:
- 如果我们不使用BN层,而在卷积层之后加入一个缩放层,缩放因子的值对于评估一个通道的重要性没有任何意义,因为卷积层和缩放层就是一种线性变换而已。我们可以通过一方面降低缩放因子的值一方面方法卷积层的权重来使最终的结果保持不变;
- 如果我们在BN层之前插入一个缩放层,缩放层的影响将完全被BN层所掩盖;
- 如果在BN层之后插入一个缩放层,那么对于每个通道将会有两个连续的缩放因子;
通道剪枝和微调:引入缩放因子正则项之后,我们得到的模型中许多缩放因子都会趋于0(如Figure 1所示)。然后我们剪掉接近零的缩放因子对应的通道,这里说的再清楚一点,假设经过卷积之后的feature map 的维度为 h x w x c,h和w分别为特征图的高和宽,c为通道数,将其送入BN层会得到归一化之后的特征图,c个feature map中的每一个都对应一组$\gamma$和$\lambda$,前面所说的剪掉小的$\gamma$对应的通道实质上就是直接剪掉这个feature map对应的卷积核。至于什么样的$\gamma$算小的呢?这个取决于我们为整个网络所有层设置的一个全局阈值,它被定义为所有缩放因子值的一个比例,比如我们将剪掉整个网络中70%的通道,那么我们先对缩放因子的绝对值排个序,然后取从小到大排序的缩放因子中70%的位置的缩放因子为阈值,通过这样做,我们就可以得到一个较少参数、运行时占内存小、低计算量的紧凑网络。
Muti-pass方案:我们可以将我们提出的方法从单阶段的学习方案扩展到多阶段,什么意思呢?通俗来讲,就是多次进行“网络瘦身”,这样可以得到一个更紧凑的模型。如Figure 2所示:
处理跨层的连接和预激活结构:上面介绍的网络瘦身过程可以直接用到大多数比较简单的CNN结构,如AlexNet、VGGNet等。但是对于有跨层连接和预激活设计的网络ResNet和DenseNet等,又应该如何使用这个方法呢?对于这些网络,每一层的输出会作为后续多个层的输入,且其BN层是在卷积层之前,在这种情况下,稀疏化是在层的输入末端得到的,一个层选择性的接受所有通道的子集去做下一步的卷积运算。为了在测试时节省参数和计算量,我们需要放置一个通道选择层鉴别出重要的通道。
4. 实验
分别在CIFAR、SVHN、ImageNet、MNIST数据上上做测试
-
使用SGD算法从头开始训练网络;
-
在CIFAR和SVHN数据集上,minibatch为64,epoches分别为160和20,初始的学习率为0.1,在训练迭代次数的50%和75%时均缩小10倍;
-
在ImageNet和MNIST数据集上,训练的迭代次数epoches分别为60和30,minibatch为256,初始学习率为0.1,在训练迭代次数的1/3和2/3时缩小10倍;
-
权重衰减率为$10{{-4}}$,所有的实验中,所有通道的缩放因子都初始化为0.5;
-
超参数$\lambda$的取值要靠网络搜索得到,常见的范围为$10{{-3}}$、$10{{-4}}$、$10{{-5}}$,对于VGGNet,我们选择$\lambda=10{{-4}}$;对于ResNet和DenseNet,我们选择$\lambda=10{{-5}}$;对于ImageNet上的VGG-A,我们选择$\lambda=10{{-5}}$;
-
我们对训练模型的通道做剪枝时,不像"Pruning filters for efficient
convnets"中对不同的层使用不同的阈值做剪枝,我们这里对所有的层设置了一个全局阈值,这是为了简单化。然后剪枝阈值是由所有比例因子中的百分比决定,例如修剪40%或60%的通道。
修剪过程是通过构建一个新的更窄的模型,并将原来训练好的稀疏化模型的相关权重复制到新模型中; -
在剪枝过后,我们获得了一个更窄更紧凑的模型,接下来便是微调,在CIFAR、SVHN、MNIST数据集上,微调使用和训练相同的优化设置;在ImageNet数据集上,由于时间的限制,我们仅对剪枝后的VGG-A使用$10{{-3}}$的学习率学习5个epoches;
4.1 CIFAR和SVHN上的结果
4.2 Parameter and FLOP reductions
4.3 Results on ImageNet and MNIST
4.4 Results for Multi-pass Scheme
5. 分析
在网络瘦身中有两个关键的超参数,剪枝百分比$t$和 稀疏正则项系数$\gamma$,下面我们来具体分析它们的影响:
剪枝百分比的影响:$t$设置的过小,节省的资源会很有限,设置的过大,剪掉太多的通道会给准确率带来永久性损伤,无法通过后续的微调恢复;我们在CIFAR-10上训练了一个DenseNet-40模型,$\gamma=10{{-5}}$,Figure 5展示了结果:
通道稀疏正则化的影响:Figure 4展示的时不同的γ\gammaγ取值下,缩放因子值的分布情况。可以看到$\gamma=10{{-4}}$时,几乎所有的缩放因子值都掉到了一个接近零的区域,这个过程中可以看成是一种类似于网络中间层的选择过程,只有不可忽视的缩放因子对应的通道才会被选择。我们进一步通过热力图对这个过程可视化,Figure 6展示的是VGGNet的某一层缩放因子的幅值随迭代次数的变化情况,每个通道开始的初始权重相同,缩放因子值也相同,随着训练的进行,一些通道的缩放因子会逐渐变大(变亮),一些变小(变暗)。
6. 最后
模型压缩之Learning Efficient Convolutional Networks through Network Slimming