https://arxiv.org/abs/1608.06993
深度卷积神经网络由于相关信息和梯度在前向传递和反向传播时都需要经过很多层,会导致梯度弥散以及梯度消失的问题。为了解决这类问题,以ResNet
为代表的相关工作,都采用了在early layer
和later layer
之间建立短路连接的方法。
下图展示了ResNet中残差块的设计
而本文基于此核心,提出了DenseNet
,对同一分辨率下的所有网络层进行连接,进一步地最大化网络层之间的信息流。一个具有l
层传统卷积神经网络有一共存在l
条连接,而DenseNet设置下会存在l(l+1)/2
条连接,如下图所示。
除了解决梯度消失的问题,DenseNet还具有"加强特征传播,特征重用,并减少参数量"的优点。
单看上面这幅图肯定会有觉得这种设计实现起来非常麻烦,要为不同的layer之间构建skip connection
,但实际上就是将resnet短路连接中的add
操作变为concate
操作,这样会使得每一层的输入都包含了之前所有层的信息。
input( x l x_l xl) = [ x 0 , x 1 , . . . , x l − 1 x_0, x_1, ..., x_{l-1} x0,x1,...,xl−1]
因为每一层的输入都考虑了之前所有层的特征映射,在网络中存在多条信息流动路线,并且每一层都能够直接接触到来自loss function
计算的梯度以及origin input
信息,这也是一种深度监督(deep supervision)。
由于DenseNet架构明确区分了添加到网络的信息(当前层的输出)和保留的信息(即之前网络层的输出),网络中每一层都设计的非常窄(通道数较少),仅向网络的"集体知识"添加一小组特征图,最终分类器根据网络中的所有特征图做出决定。这种深-窄型的结构也使得DenseNet的参数量比较少。
最终DenseNet能在更少参数量的情况下达到更优的性能,整体性能也达到了SOTA。并且也有作者在采访时也指出DenseNet
在下游任务中可以不依赖预训练模型,甚至达到更好的精度,见参考链接[2]。
与ResNet的区别
其实从上一节的描述中,两者的区别就已经显现地非常明显了。作者也列出了两个公式,对于ResNet,第l
层的输出可以表示为:
而DenseNet可以表示为:
可以看到,ResNet是额外添加了短路连接进行恒等映射,而DenseNet是拼接了之前的所有特征输出,两者都能解决梯度弥散的问题。对于ResNet,虽然梯度可以直接通过恒等函数从后面的层流向早期的层,但相加操作可能会阻碍信息的流动。而DenseNet可以让每一层都能直接获取到不同层级的梯度和信息流。
DenseNet网络结构
如上图所示,DenseNet主要由多个Dense Block组成,每一个Block内特征图分辨率一致,因此可以直接应用密集连接操作(concat)。在Block之间会应用下采样操作减少特征图尺度,文中将其称为trasition layers
,包含卷积、池化操作【bn + 1x1 conv + 2x2 avgpool】。
在DenseNet中,有个新的超参数为Growth rate
(增长率),假设一个Block的初始输入特征维度为 k 0 k_0 k0,如果增长率为k
,应用密集连接操作后,对于第 l l l层的输入特征维度为k_0 + k*(l-1)
。与其他的网络不同,DenseNet非常窄(即每个节点 / 每一层 [图2中的每一个点] 的输出特征维度都比较小,例如k=12),并且取得了非常不错的结果。并且作者也为此找到一个不错的解释,因为每一层特征都可以直接获取之前的所有输出(集体知识collective knowledge
),如果将特征图视为网络的全局状态,每层都将自己的输出(k个特征映射)添加到状态中。因此,增长率可以用来调整每层输出对全局状态新增信息的贡献量。全局状态一旦写入,可以从网络中的任何位置进行访问,与传统网络架构不同,无需逐层复制它。
我个人觉得主要是因为concat的关系,如果每个节点输出的特征维度还非常宽的话,会大大增加显存和计算。并且提一嘴,虽然作者提到 “全局状态一旦写入,可以从网络中的任何位置进行访问,无需逐层复制它”,但现有框架的concat操作基本上会额外开辟空间进行复制,导致整个网络占内存较大,但也有节省内存的高效实现,见参考链接[2].
在每个Dense Block中,也可以采用了bottleneck结构,先对输入使用1x1 conv
进行降维,再使用3x3 conv
,这种结构称为DenseNet-B
。此外,在每个transition layer
中也可以进行降维操作,实验中是将通道数降到原来的0.5
倍,这种架构称为DenseNet-C
。若两个都采用,则称之为DenseNet-BC
。
用于ImageNet数据集进行分类任务的DenseNet具体网络结构如下所示:
值得注意的是,这里每个
conv
表示bn-relu-conv
操作,这参考了《Identity mappings in deep residual networks》这篇文章,其证明采用bn-relu-conv
的pre-activation比原始的resnet效果更好,详情参考链接[3]。
部分实验:
介绍部分实验结果,更详细的实验请看原文。
下表介绍了模型在CIFAR和SVHN数据集上的结果,可以看到:① 相同参数下DenseNet性能更好,相同性能下DenseNet参数更少;② 增加深度,模型不会过拟合以及优化困难;③ DenseNet可能具有更强的抗过拟合能力,在不使用数据增广的前提下,DenseNet表现的性能更好,并且增加容量性能增加【但C10上的k=24效果比k=12要差】。
下面的表和图展示了DenseNet-BC在ImageNet上的性能,以及与ResNet的比较:使用更少的参数量就能获取到相同的性能。
DenseNet最大的特点就是每一层都可以直接获取到之前所有层的输出结果,因此,作者做了一个实验来探索训练好的网络是否用到了这个特性? 下图展示了在C10+上训练好的DenseNet中第l
层与之前s
层之间的平均权重,横轴表示目标层(在block内的次序),纵轴表示源层(当前目标层的输入,前s层的输出)。这幅图可以表示当前层对之前某一层输出特征的复用率。作者主要提到四点结论:
DenseNet是2017年CVPR的best paper,其思想简单,效果不错。和作者在[1]中说的一样,在没有了解其网络结构与实现时,听到密集连接Densely Connected
这个词,第一时间就觉得那参数量肯定很多,模型很复杂。后面在看文中的网络图示时,心想这不就是增加了很多条skip connection
了嘛,实现起来肯定很复杂。
但其实,本文与ResNet的最大区别就只在于将+
改成了concat
操作【逻辑上】,就这一个小细节,诞生了两个不同的网络结构,密集连接操作使得每一层都能够直接获取到之前所有层的输出。正因为这种特性,所以作者可以把网络设计得很窄同时保持高性能【参数少、计算量小】,并且这种设计会提供【抗过拟合】的能力。
关于抗过拟合,作者解释道,神经网络每一层提取的特征都相当于对输入数据的一个非线性变换,而随着深度的增加,变换的复杂度也逐渐增加(更多非线性函数的复合)。相比于一般神经网络的分类器直接依赖于网络最后一层(复杂度最高)的特征,DenseNet 可以综合利用浅层复杂度低的特征,因而更容易得到一个光滑的具有更好泛化性能的决策函数。实际上,DenseNet 的泛化性能优于其他网络是可以从理论上证明的:去年的一篇几乎与 DenseNet 同期发布在 arXiv 上的论文(AdaNet: Adaptive Structural Learning of Artificial Neural Networks)所证明的结论(见文中 Theorem 1)表明类似于 DenseNet 的网络结构具有更小的泛化误差界。
从做雷达图像方向和医学图像方向的同学那里也了解到,这种
Dense Block
的设计确实会带来不少的提升。我猜原因之一就是这些领域数据量较少,其他的网络架构更容易过拟合。
[1] CVPR 2017最佳论文作者解读:DenseNet 的“what”、“why”和“how”
[2] DenseNet简析以及Pytorch内存高效实现
[3] ResNetV2:ResNet深度解析