An Entropy-based Pruning Method for CNN Compression
摘要
首先通过提出基于熵(entropy-based)的方法来评估每个滤波器的重要性。然后剪枝,最后采用微调方法(fine-tuning)恢复了剪枝过程中损坏的泛化能力(generalization ability)。我们的方法可以减少中间激活(intermediate activations)的大小,中间激活在模型训练阶段占用大部分内存,但在以前的压缩方法中不太受关注。
1、引言
CNN模型的资源消耗主要来自运行时间,模型参数大小和中间激活大小(intermediate activation size)三个方面 。首先,当batch size 比较大时,中间激活将主导大部分内存占用。事实上,在小型设备中,那些用现在的方法压缩的CNN模型很难被微调(fine-tunr),因为激活的规模太大了。第二,减少激活将同时加快推理速度,减少内存占用。最后,每一层中的通道数都是在training purpose中人工设计的。我们的主要观点是,如果一个特定的过滤器的集火输出(activation output)包含更少的信息,这个过滤器似乎不那么重要,因此应该被删除,以获得一个小的网络。由于普通的迭代剪枝策略太耗时,我们提出了一个学习时间表(learning schedule)来寻求训练速度和模型精度之间的权衡(有这个矛盾吗?)。
我们使用两种常用的CNN模型来评估我们的图像分类剪枝框架:VGG-16(2015)和最近突出的ResNet-50(2016)。这两个模型都在ImageNet存储库(ImageNet repository)的基准数据集(benchmark dataset)ILSVRC-12上进行了修剪。
我们的目标是将一个繁琐的网络转换为一个苗条的模型,它可以在现成的深度学习库(deep learning libraries)上运行,而不需要进行任何修改。我们认为对新的数据集或任务进行微调是必要的(而不是只使用压缩网络进行ImageNet分类),但网络层和架构上的任何变化都不会得到当前的深度学习库的支持。因此,我们认为修剪滤波器是最合适的策略。我们还将修剪后的网络与两个不同领域的特定数据集CUB-200-2011和Indoor-67,以证明我们的方法的领域自适应能力。其主要优势和贡献总结如下:
·提出了一个简单有效的框架,以在训练和推理阶段加速和压缩CNN模型。我们的方法可以压缩中间激活的大小,大大减少运行时内存的消耗,这在以前的工作中没有收到足够的关注
·我们提出了一种有效的学习时间表策略(learning schedule strategy),通过该策略来寻求在训练速度和分类精度之间进行更好的权衡。
·我们的方法不依赖于专用的库来获得加速和压缩性能,因此可以被任何当前流行的深度学习库完全支持。
2、相关工作
低秩近似(Low-rank approximation):在大多数深度模型中,每一层的参数形成了一个大而密集的矩阵,这导致了存储和计算的困难。从数学上讲,如果我们可以用几个低秩小尺度矩阵来近似这个密集矩阵,就可以用快速傅里叶变换(FFT)等特殊技术将矩阵向量乘法快速完成。因此,可以显著减少内存占用和计算复杂度。受此想法的启发,人们提出了许多近似原始权值的方法。Sindhwani等人,利用几个结构化矩阵的线性组合来建模原始参数矩阵。这些结构化矩阵可以通过一些数学运算转换为非常低秩的矩阵。Denton等人,采用矩阵分解的方法来探索神经网络的线性结构。他们使用奇异值分解(SVD)来构造近似值。
网络剪枝(Network pruning):之前的参数剪枝方法,低于阈值的小权重连接将被丢弃,从而导致一个稀疏的架构。但他们的方法没有减少激活张量的大小,当batch size很大时,激活张量将主导内存占用。因此,一些研究人员将注意力集中在滤波器剪枝以减少激活张量的通道数量。Hu等人提出了一种数据驱动的神经元修剪方法来去除不重要的神经元。Li等人也用了类似的方法。他们使用绝对权重和来测量每一个过滤器的重要性,并删除不太重要的滤波器。我们的方法与这些方法类似,但在通道选择和模型微调中使用了完全不同的策略。
参数量化(Parameter quantization):参数量化是另一种已得到充分研究的经典压缩方法。其中一种广泛使用的方法是乘积量化,它将空间分解为低维子空间的笛卡尔乘积,并且立即量化每个子空间。Gong等人将产品量化(product quantization)与几种不同的量化方法进行了比较,法相即使使用一种简单的基于k-means的方法,他们的方法也能取得令人印象深刻的结果。(下面不看了,这不是这个领域的)
3、Entropy-based pruning method(基于熵的修剪方法)
3.1.Framework
图1说明了我们提出的中间激活剪枝方法的总体框架。对于我们想要修剪的特定层(即第i层),我们首先关注它的激活张量。如果它的激活张量的几个通道足够弱(例如,所有元素都具有相同的值),我们就有信心相信相应的滤波器也不那么重要,可以被修剪。我们提出了一个基于熵的度量来重新评估每个弱的通道。如图1所示,这些通道用黄色突出显示。
然后,这些弱滤波器都从原始模型中移除,从而产生更紧凑的网络架构。下一层中相应的过滤器通道也被删除。与原始模型相比,修剪过的网络的参数要少得多,因此可以减少运行时间和内存消耗。更重要的是,激活的大小也被减小了,这在以前的压缩方法中不那么受关注。
最后,根据稀疏表示和分布式表示的性质(the property of sparse and distributed representations)(每个概念(concept)都由许多神经元表示,每个神经元都参与了许多概念的表示)。虽然这些过滤器很弱,但其中也存储了一些知识。因此,修剪后的模型的泛化能力(为什么是泛化能力受影响而不是精度)将受到影响。为了恢复其性能,我们对整个网络进行了微调。我们采用不同的学习时间表(learning schedule)来训练修建模型。这不仅减少了整体训练时间,而且防止了它被吸引到糟糕的局部最小值。
3.2 基于熵的过滤器选择
注意每个滤波器对应于其激活张量的单个通道(还有其实卷积feature map的归一化激活不是很明白,全卷积层的挺好理解,就是一行向量做个单位化,如果feature map的话是不是一个channel归一化一次呢。也就是这里的激活实际是激活运算还是激活得到的feature map,又或者它们本来就是一个东西,也就是说对激活进行裁剪就是对输出维度进行裁剪,因为激活层没有参数,就是一个固定运算,它的运算量决定于输入的数量,不涉及特征提取,本来就没有裁剪的概念)各过滤器的鉴别能力与其激活通道密切相关。一个简单的策略是计算每个激活通道中零的平均百分比(APoZ)(这里又蒙了,这个策略计算什么零的百分比,又回到回来算参数的路子里去了???)但这不是一个最优的指标。首先,一个小量(如0.0001,接近于0,但不完全是0),将被忽略,它实际上应该被剪掉。其次,如果一个过滤器总是产生相似的值,我们可以相信这个过滤器包含的信息更少,因此不那么重要。不可能使用APoZ来选择这个过滤器。
在本文中,我们提出了一个基于熵的度量来评估每个滤波器的重要性。熵是信息论中测量无序或不确定性的常用度量方法。熵值越大,系统包含的信息就越多。
首先,我们对第i层的输出进行平均值池化,把c × h × w的张量转换成1×c向量。这样,(第i等的激活结果和第i+1层的输入)的每个通道都有一个对应的分数。为了计算熵,需要手机更多的输出值,这可以使用一个评估集(evaluation set)得到。在实践中,评估集可以简单的是原始训练集,或者是它的一个子集。最后,我们得到一个矩阵(这个矩阵是怎么得到的,也就是说,这里用于评估的熵是通过跑评估集得到的数据,网络经过训练之后可以得到这个layer的权重信息,但是不够用,所以用了评估集跑了n次训练,得到了n个权重的值,因为测试不会改变权重的值,所以评估只可能是训练,但可能这个训练的数据不会更新,不然把模型给跑坏了咋办。这里思考了一下评估的过程,一张图放进去可以算出一个损失,优化器根据损失更新权重的值,这里涉及到学习率之类的东西,但是因为模型已经收敛了,用原来的参数去训练其实不咋会改变模型。原来训练得到的只是最后一轮epoch中最后一张图算出来的权重。评估集相当于获得了n个差不多的权重值,但是我感觉这个权重应该差不多吧,毕竟都收敛了,搞这么多干啥呢),其中n是评估集中的图像数,c是通道数。对于每个通道j,我们注意的分布,为了计算这个通道的熵值,我们首先把它们划分为m个不同的箱子(bins),并计算每个箱子的概率。最后,熵可以如下计算:
其中,是bin i的概率,是第j个通道的熵。一般来说,如果一些层足够弱,例如,它们的大部分激活是零(激活为啥会是0,这是回到原来那个数0的策略了吗,这里不是引入熵了,不是应该评估的是数据的混沌程度吗,但确实大部分是0的话熵也会比较小,但为什么是0,大部分是1不行吗),那么它们的熵就比较小。的得分越小,意味着通道j在这一层中不那么重要,因此可以被删除。
这里没有选择用熵的阈值作为裁剪边界,作者认为阈值是超参数很难指定,文中使用了恒定的剪枝率,依据熵进行排序了之后剪枝,只保留k个滤波器。当然中对应的通道也被删除
3.3. Pruning strategy(剪枝策略)
这里提到了一下当时出现了用全局平均池化来代替全连接层,以减少参数数量。对于恒等映射的ResNet,作者认为剪后面的层会使其维度变化。所以剪中间的来减少后面的参数数量.
3.4 Learning Schedule
作者认为,一次性剪枝省时间但是如果剪掉太多没法通过微调来恢复;每次剪之后再训练,耗时间。所以要找时间和性能的平衡。下面是方法:
当修剪每一层时,整个网络都会用一个或两个epoch进行微调,以略微恢复其性能。当然,这种性能还不是最佳的,但正在密切接近它。只有在最后一层被修剪后,网络才会用许多epoch进行仔细地微调。使用这样的Learning Schedule,训练时间可以大大减少。但更重要的是,这种策略防止微调网络在早期学习阶段陷入糟糕的局部最小值。由于深度神经网络的训练过程是高度非凸的(highly non-convex),如果我们总是对网络进行微调直到修剪后收敛,网络在早期很可能会被一组差值(a set of poor values)所吸引。
实验以后看,这篇了解一下就好。