DenseNet算法详解

论文:Densely Connected Convolutional Networks
论文连接:https://arxiv.org/pdf/1608.06993.pdf
代码的github连接:https://github.com/liuzhuang13/DenseNet
MXNet版本代码(有ImageNet预训练模型): https://github.com/miraclewkf/DenseNetgit

文章详解:
这篇文章是CVPR2017的oral,很是厉害。文章提出的DenseNet(Dense Convolutional Network)主要仍是和ResNet及Inception网络作对比,思想上有借鉴,但倒是全新的结构,网络结构并不复杂,却很是有效!众所周知,最近一两年卷积神经网络提升效果的方向,要么深(好比ResNet,解决了网络深时候的梯度消失问题)要么宽(好比GoogleNet的Inception),而做者则是从feature入手,经过对feature的极致利用达到更好的效果和更少的参数。博主虽然看过的文章不算不少,可是看完这篇感受心潮澎湃,就像当年看完ResNet那篇文章同样!github

先列下DenseNet的几个优势,感觉下它的强大:
一、减轻了vanishing-gradient(梯度消失)
二、增强了feature的传递
三、更有效地利用了feature
四、必定程度上较少了参数数量web

在深度学习网络中,随着网络深度的加深,梯度消失问题会越发明显,目前不少论文都针对这个问题提出了解决方案,好比ResNet,Highway Networks,Stochastic depth,FractalNets等,尽管这些算法的网络结构有差异,可是核心都在于:create short paths from early layers to later layers。那么做者是怎么作呢?延续这个思路,那就是在保证网络中层与层之间最大程度的信息传输的前提下,直接将全部层链接起来!算法

先放一个dense block的结构图。在传统的卷积神经网络中,若是你有L层,那么就会有L个链接,可是在DenseNet中,会有L(L+1)/2个链接。简单讲,就是每一层的输入来自前面全部层的输出。以下图:x0是input,H1的输入是x0(input),H2的输入是x0和x1(x1是H1的输出)……网络

这里写图片描述

DenseNet的一个优势是网络更窄,参数更少,很大一部分缘由得益于这种dense block的设计,后面有提到在dense block中每一个卷积层的输出feature map的数量都很小(小于100),而不是像其余网络同样动不动就几百上千的宽度。同时这种链接方式使得特征和梯度的传递更加有效,网络也就更加容易训练。原文的一句话很是喜欢:Each layer has direct access to the gradients from the loss function and the original input signal, leading to an implicit deep supervision.直接解释了为何这个网络的效果会很好。前面提到过梯度消失问题在网络深度越深的时候越容易出现,缘由就是输入信息和梯度信息在不少层之间传递致使的,而如今这种dense connection至关于每一层都直接链接input和loss,所以就能够减轻梯度消失现象,这样更深网络不是问题。另外做者还观察到这种dense connection有正则化的效果,所以对于过拟合有必定的抑制做用,博主认为是由于参数减小了(后面会介绍为何参数会减小),因此过拟合现象减轻。svg

这篇文章的一个优势就是基本上没有公式,不像灌水文章同样堆复杂公式把人看得一愣一愣的。文章中只有两个公式,是用来阐述DenseNet和ResNet的关系,对于从原理上理解这两个网络仍是很是重要的。学习

第一个公式是ResNet的。这里的l表示层,xl表示l层的输出,Hl表示一个非线性变换。因此对于ResNet而言,l层的输出是l-1层的输出加上对l-1层输出的非线性变换。测试

这里写图片描述

第二个公式是DenseNet的。[x0,x1,…,xl-1]表示将0到l-1层的输出feature map作concatenation。concatenation是作通道的合并,就像Inception那样。而前面resnet是作值的相加,通道数是不变的。Hl包括BN,ReLU和3*3的卷积。设计

这里写图片描述

因此从这两个公式就能看出DenseNet和ResNet在本质上的区别,太精辟。3d

前面的Figure 1表示的是dense block,而下面的Figure 2表示的则是一个DenseNet的结构图,在这个结构图中包含了3个dense block。做者将DenseNet分红多个dense block,缘由是但愿各个dense block内的feature map的size统一,这样在作concatenation就不会有size的问题。

这里写图片描述

这个Table1就是整个网络的结构图。这个表中的k=32,k=48中的k是growth rate,表示每一个dense block中每层输出的feature map个数。为了不网络变得很宽,做者都是采用较小的k,好比32这样,做者的实验也代表小的k能够有更好的效果。根据dense block的设计,后面几层能够获得前面全部层的输入,所以concat后的输入channel仍是比较大的。另外这里每一个dense block的3*3卷积前面都包含了一个1*1的卷积操做,就是所谓的bottleneck layer,目的是减小输入的feature map数量,既能降维减小计算量,又能融合各个通道的特征,何乐而不为。另外做者为了进一步压缩参数,在每两个dense block之间又增长了1*1的卷积操做。所以在后面的实验对比中,若是你看到DenseNet-C这个网络,表示增长了这个Translation layer,该层的1*1卷积的输出channel默认是输入channel到一半。若是你看到DenseNet-BC这个网络,表示既有bottleneck layer,又有Translation layer。

这里写图片描述

再详细说下bottleneck和transition layer操做。在每一个Dense Block中都包含不少个子结构,以DenseNet-169的Dense Block(3)为例,包含32个1*1和3*3的卷积操做,也就是第32个子结构的输入是前面31层的输出结果,每层输出的channel是32(growth rate),那么若是不作bottleneck操做,第32层的3*3卷积操做的输入就是31*32+(上一个Dense Block的输出channel),近1000了。而加上1*1的卷积,代码中的1*1卷积的channel是growth rate*4,也就是128,而后再做为3*3卷积的输入。这就大大减小了计算量,这就是bottleneck。至于transition layer,放在两个Dense Block中间,是由于每一个Dense Block结束后的输出channel个数不少,须要用1*1的卷积核来降维。仍是以DenseNet-169的Dense Block(3)为例,虽然第32层的3*3卷积输出channel只有32个(growth rate),可是紧接着还会像前面几层同样有通道的concat操做,即将第32层的输出和第32层的输入作concat,前面说过第32层的输入是1000左右的channel,因此最后每一个Dense Block的输出也是1000多的channel。所以这个transition layer有个参数reduction(范围是0到1),表示将这些输出缩小到原来的多少倍,默认是0.5,这样传给下一个Dense Block的时候channel数量就会减小一半,这就是transition layer的做用。文中还用到dropout操做来随机减小分支,避免过拟合,毕竟这篇文章的链接确实多。

实验结果:
做者在不一样数据集上采用的DenseNet网络会有一点不同,好比在Imagenet数据集上,DenseNet-BC有4个dense block,可是在别的数据集上只用3个dense block。其余更多细节能够看论文3部分的Implementation Details。训练的细节和超参数的设置能够看论文4.2部分,在ImageNet数据集上测试的时候有作224*224的center crop。

Table2是在三个数据集(C10,C100,SVHN)上和其余算法的对比结果。ResNet[11]就是kaiming He的论文,对比结果一目了然。DenseNet-BC的网络参数和相同深度的DenseNet相比确实减小了不少!参数减小除了能够节省内存,还能减小过拟合。这里对于SVHN数据集,DenseNet-BC的结果并无DenseNet(k=24)的效果好,做者认为缘由主要是SVHN这个数据集相对简单,更深的模型容易过拟合。在表格的倒数第二个区域的三个不一样深度L和k的DenseNet的对比能够看出随着L和k的增长,模型的效果是更好的。

这里写图片描述

Figure3是DenseNet-BC和ResNet在Imagenet数据集上的对比,左边那个图是参数复杂度和错误率的对比,你能够在相同错误率下看参数复杂度,也能够在相同参数复杂度下看错误率,提高仍是很明显的!右边是flops(能够理解为计算复杂度)和错误率的对比,一样有效果。

这里写图片描述

Figure4也很重要。左边的图表示不一样类型DenseNet的参数和error对比。中间的图表示DenseNet-BC和ResNet在参数和error的对比,相同error下,DenseNet-BC的参数复杂度要小不少。右边的图也是表达DenseNet-BC-100只须要不多的参数就能达到和ResNet-1001相同的结果。

这里写图片描述

另外提一下DenseNet和stochastic depth的关系,在stochastic depth中,residual中的layers在训练过程当中会被随机drop掉,其实这就会使得相邻层之间直接链接,这和DenseNet是很像的。

总结:
博主读完这篇文章真的有点相见恨晚的感受,半年前就在arxiv上挂出来了,据说当时就引发了轰动,后来又被选为CVPR2017的oral,感受要撼动ResNet的地位了,再加上如今不少分类检测的网络都是在ResNet上作的,这岂不是大地震了。惊讶之余来总结下这篇文章,该文章提出的DenseNet核心思想在于创建了不一样层之间的链接关系,充分利用了feature,进一步减轻了梯度消失问题,加深网络不是问题,并且训练效果很是好。另外,利用bottleneck layer,Translation layer以及较小的growth rate使得网络变窄,参数减小,有效抑制了过拟合,同时计算量也减小了。DenseNet优势不少,并且在和ResNet的对比中优点仍是很是明显的。