论文:CondenseNet: An Efficient DenseNet using Learned Group Convolutions
链接:https://arxiv.org/abs/1711.09224
代码地址:https://github.com/ShichenLiu/CondenseNet(PyTorch)
一作是康奈尔大学的黄高,主要在于优化了DenseNet网络,使其计算效率更高且参数存储更少。在DenseNet博客中介绍过DenseNet最大的一个缺点就是显存占用较大,主要原因在于生成了额外的较多特征层。在DenseNet后面紧接着有一篇技术文章通过开辟统一存储空间用于存储额外生成的特征,可以在一定程度上减少模型训练时候的显存占用。这篇文章则主要通过卷积的group操作以及在训练时候的剪枝来达到降低显存提高速度的目的。作者的实验证明,CondenseNet可以在只需要DenseNet的1/10训练时间的前提下,达到和DenseNet差不多的准确率。
总结下这篇文章的几个特点:1、引入卷积group操作,而且在1*1卷积中引入group操作时做了改进。2、训练一开始就对权重做剪枝,而不是对训练好的模型做剪枝。3、在DenseNet基础上引入跨block的dense连接。
文中有和ShuffleNet、MobileNet等模型压缩加速算法的对比,这两个算法主要采用depth-wise separable convolution达到提速和压缩的效果,可以参考博客:ShuffleNet、MobileNet。
Figure1中左边图是DenseNet的结构。第三层的1*1 Conv主要起到channel缩减的作用(channel数量从lk减到4k),第五层的3*3 Conv生成k个channel的输出。Figure1中间图是CondenseNet在训练时候的结构,Permute层的作用是为了降低引入1*1 L-Cconv对结果的不利影响,实现的是channel之间的调换过程。需要注意的是原来1*1 Conv替换成了1*1 L-Conv(learned group convolution),原来的3*3 Conv替换成了3*3 G-Conv(group convolution)。Figure1中右边图是CondenseNet测试时候的结构,其中的index层的作用在于feature selection,具体要选择哪些feature map,是在Figure1中间图中训练完的时候就确定的,因此index层只是一个类似0-1操作。另外要注意由于添加了Index层,所以原来Figure1中间图中的1*1 L-Conv层在Figure1右边图中替换成常规的卷积group层:1*1 G-Conv,这是训练和测试时候的一个不同点。
Figure2是卷积中group操作的示意图,其实就是将输入channel分成n个group(图中是3个group),同时卷积核也会分成n个group;然后每个group里的卷积核(图中每个group有2个卷积核)只跟一一对应的group中的feature map(图中是4个feature map)做卷积得到输出。能减少多少计算量呢?假设Figure2中左图的输入输出channel数各是R和O,那么Figure2左图的计算量暂且用R*O表示(更准确的表示是:k^2*m^2*R*O,其中k是卷积核大小(假设是正方形的),m是输出feature map的大小。如果采用G个group来做,计算量就是(R/G)*(O/G)*G=R*O/G(更准确的表示是:k^2*m^2*R*O/G),所以相比之下就是原来计算量的1/G。
前面提到一个名词:Learn Group Convolution,这个和普通的group convolution有什么不同呢?这得从1*1卷积讲起。作者想要在DenseNet的卷积操作中引入group,在3*3卷积中问题不大,但是在1*1卷积中发现直接这样做对最后的结果影响较大,作者推测原因是:We surmise that this is caused by the fact that the inputs to the 1*1 layer are concatenations of feature maps generated by preceding layers. Therefore, they differ in two ways from typical inputs to convolutional layers: 1. they have an intrinsic order; and 2.they are far more diverse. 什么意思呢?个人理解:一般1*1卷积层的作用是对前面层的输出特征做channel上的融合,因此如果加入group,那么融合的输入就少了许多,因此输出的多样性就得不到保证。所以如果能弄个像ShuffleNet那样的shuffle操作,就能增加输出多样性。因此作者通过添加Permute层(该层是变换通道顺序的作用,类似shuffle操作,这样后面每个group的3*3卷积的输入就可以包含1*1卷积的所有group输出),这可以在一定程度上降低在1*1卷积中引入group操作对结果的影响,当然作者也说了,这样做的效果还是不如相同计算量下的直接用更小的DenseNet网络的效果。
Figure3是关于Learned Group Convolution,由前面的解释可知,这主要是针对在1*1卷积中引入group操作。Figure3中文字部分的condensation factor C=3表示每个group可以包含的输入channel个数是[R/C],R是输入channel的总数,[]是取整的意思,也就是剪枝的结果是最终保留1/C的连接。接下来按Figure3从左往右来看。
Condensing Stage1是普通的卷积过程。
Condensing Stage2是自动选择group的过程,假如模型一共要迭代M个epoch,那么stage1+stage2的迭代次数为M/(2*(C-1))。
Optimization Stage是在group确定的前提下进行的剪枝,也就是筛选出每个group中不是很重要的输入feature map。那么怎么衡量重要性呢?比如要衡量第j个channel的输入feature map和卷积核的第g个group之间的重要性,那么就用j和g这个group之间的所有连接(g这个group有多少个卷积核,就有多少个连接)的权重的平均绝对值衡量重要性,本质上就是求权值的L1范数。显然这种剪枝的操作会使得同一个group中的卷积核都是和相同的输入channel做连接,当然这也是作者希望出现的。另外作者还引入了L1正则化,想要达到group-level sparisity的目的,当然文中有一句话不是很懂:To reduce the negative effects on accuracy introduced by weight pruning, L1 regularization is commonly used to induce sparsity。一般在过拟合的时候会通过加大L1正则化权重的方式来减轻过拟合,而且一般会对准确率有影响,这里却说为了提高模型的效果而引入L1正则化。
Testing部分主要是一个index layer操作和一个常规的group操作,比较简单。
Figure4是关于具体的epoch和learning rate以及loss的对应关系。
Figure5表示在原来DenseNet上做的两个改动:一个是不同block的feature map也相互连接(DenseNet中只有一个block内部的几个层之间有dense connection),因此可以在Figure5中看到一些2*2 pooling或4*4pooling层就是为了解决不同block的feature map连接时候的尺寸问题;另一个是随着网络的加深增大了growth rate,growth rate是DenseNet中每一层的输出channel数量,假设有m个block,k0为常量(也是第0个block的growth rate),那么第m个block的growth rate就是:k=2^(m-1)*k0。因此最终的结果就是加宽了网络。
实验结果:
实验在CIFAR-10,CIFAR-100和ImageNet(ILSVRC 2012)数据集上进行。
CIFAR数据集的结果:
首先是验证前面提到的一些操作的效果,分别是LGC(learned group convolution)、IGR(increasing learning rate)和FDC(full dense connectivity)。可以看出三者都不加的情况就是原来的DenseNet网络,三者都加的情况就是本文的CondenseNet,前两者效果还是比较明显的,FDC的提升比较有限。
Table1是和目前优秀算法的对比,可以看出在基本不影响准确率的情况下,参数量和计算量的下降还是比较明显的。
Table2是和其他基于filter的剪枝算法的对比。
ImqageNet数据集结果:主要是和mobileNet以及shuffleNet的对比:
附:在ImageNet数据集上用的CondenseNet网络结构。更多实验结果可以看原文。