八、 DenseNet

  1. DenseNet不是通过更深或者更宽的结构,而是通过特征重用来提升网络的学习能力。

  2. ResNet 的思想是:创建从“靠近输入的层” 到 “靠近输出的层” 的直连。而DenseNet 做得更为彻底:将所有层以前馈的形式相连,这种网络因此称作DenseNet

  3. DenseNet 具有以下的优点:

    • 缓解梯度消失的问题。因为每层都可以直接从损失函数中获取梯度、从原始输入中获取信息,从而易于训练。
    • 密集连接还具有正则化的效应,缓解了小训练集任务的过拟合。
    • 鼓励特征重用。网络将不同层学到的 feature map 进行组合。
    • 大幅度减少参数数量。因为每层的卷积核尺寸都比较小,输出通道数较少 (由增长率 八、 DenseNet - 图1 决定)。
  4. DenseNet 具有比传统卷积网络更少的参数,因为它不需要重新学习多余的feature map

    • 传统的前馈神经网络可以视作在层与层之间传递状态的算法,每一层接收前一层的状态,然后将新的状态传递给下一层。

      这会改变状态,但是也传递了需要保留的信息。

    • ResNet 通过恒等映射来直接传递需要保留的信息,因此层之间只需要传递状态的变化

    • DenseNet 会将所有层的状态 全部保存到集体知识中,同时每一层增加很少数量的feture map 到网络的集体知识中

  5. DenseNet 的层很窄(即:feature map 的通道数很小),如:每一层的输出只有 12 个通道。

8.1 DenseNet 块

  1. 具有 八、 DenseNet - 图2 层的传统卷积网络有 八、 DenseNet - 图3 个连接,每层仅仅与后继层相连。

    具有 八、 DenseNet - 图4 个残差块的 ResNet 在每个残差块增加了跨层连接,第 八、 DenseNet - 图5 个残差块的输出为:八、 DenseNet - 图6 。其中 八、 DenseNet - 图7 是第 八、 DenseNet - 图8 个残差块的输入特征;八、 DenseNet - 图9 为一组与第 八、 DenseNet - 图10 个残差块相关的权重(包括偏置项),八、 DenseNet - 图11 是残差块中的层的数量; 八、 DenseNet - 图12 代表残差函数。

    具有 八、 DenseNet - 图13 个层块的DenseNet 块有 八、 DenseNet - 图14 个连接,每层以前馈的方式将该层与它后面的所有层相连。对于第 八、 DenseNet - 图15 层:所有先前层的feature map 都作为本层的输入,第 八、 DenseNet - 图16 层具有 八、 DenseNet - 图17 个输入feature map ;本层输出的feature map 都将作为后面八、 DenseNet - 图18 层的输入。

  2. 假设DenseNet块包含 八、 DenseNet - 图19 层,每一层都实现了一个非线性变换 八、 DenseNet - 图20 ,其中 八、 DenseNet - 图21 表示层的索引。

    假设DenseNet块的输入为 八、 DenseNet - 图22DenseNet块的第 八、 DenseNet - 图23 层的输出为 八、 DenseNet - 图24 ,则有:

    八、 DenseNet - 图25

    其中 八、 DenseNet - 图26 表示 八、 DenseNet - 图27 层输出的feature map 沿着通道方向的拼接。

    ResNet 块与它不同。在ResNet 中,不同feature map 是通过直接相加来作为块的输出。

    八、 DenseNet - 图28

  3. feature map 的尺寸改变时,无法沿着通道方向进行拼接。此时将网络划分为多个DenseNet 块,每块内部的 feature map尺寸相同,块之间的feature map 尺寸不同。

8.1.1 增长率

  1. DenseNet 块中,每层的 八、 DenseNet - 图29 输出的feature map 通道数都相同,都是 八、 DenseNet - 图30 个。八、 DenseNet - 图31 是一个重要的超参数,称作网络的增长率。

    八、 DenseNet - 图32 层的输入feature map 的通道数为: 八、 DenseNet - 图33 。其中 八、 DenseNet - 图34 为输入层的通道数。

  2. DenseNet 不同于现有网络的一个重要地方是:DenseNet 的网络很窄,即输出的 feature map 通道数较小,如: 八、 DenseNet - 图35

    一个很小的增长率就能够获得不错的效果。一种解释是:DenseNet 块的每层都可以访问块内的所有早前层输出的feature map,这些feature map 可以视作DenseNet 块的全局状态。每层输出的feature map 都将被添加到块的这个全局状态中,该全局状态可以理解为网络块的“集体知识”,由块内所有层共享。增长率 八、 DenseNet - 图36 决定了新增特征占全局状态的比例。

    因此feature map 无需逐层复制(因为它是全局共享),这也是DenseNet 与传统网络结构不同的地方。这有助于整个网络的特征重用,并产生更紧凑的模型。

8.1.2 非线性变换 H_l

  1. 八、 DenseNet - 图37 可以是包含了 Batch Normalization(BN)ReLU 单元、池化或者卷积等操作的复合函数。
  2. 论文中 八、 DenseNet - 图38 的结构为:先执行BN ,再执行ReLU,最后接一个3x3 的卷积,即:BN-ReLU-Conv(3x3)

8.1.3 bottleneck

  1. 尽管DenseNet 块中每层只产生 八、 DenseNet - 图39 个输出feature map,但是它具有很多输入。当在 八、 DenseNet - 图40 之前采用 1x1 卷积实现降维时,可以减小计算量。

    八、 DenseNet - 图41 的输入是由第 八、 DenseNet - 图42 层的输出 feature map 组成,其中第 0 层的输出feature map就是整个DensNet 块的输入feature map

事实上第八、 DenseNet - 图43 层从DensNet 块的输入feature map 中抽取各种特征。即 八、 DenseNet - 图44 包含了DensNet 块的输入feature map 的冗余信息,这可以通过 1x1 卷积降维来去掉这种冗余性。

因此这种1x1 卷积降维对于DenseNet 块极其有效。

  1. 如果在 八、 DenseNet - 图45 中引入 1x1 卷积降维,则该版本的DenseNet 称作DenseNet-B 。其 八、 DenseNet - 图46 结构为:先执行BN ,再执行ReLU,再接一个1x1 的卷积,再执行BN ,再执行ReLU,最后接一个3x3 的卷积。即:BN-ReLU-Conv(1x1)-BN-ReLU-Conv(3x3)

    其中1x1 卷积的输出通道数是个超参数,论文中选取为 八、 DenseNet - 图47

8.2 过渡层

  1. 一个DenseNet 网络具有多个DenseNet块,DenseNet 块之间由过渡层连接。DenseNet 块之间的层称为过渡层,其主要作用是连接不同的DenseNet块。

  2. 过渡层可以包含卷积或池化操作,从而改变前一个DenseNet 块的输出feature map 的大小(包括尺寸大小、通道数量)。

    论文中的过渡层由一个BN层、一个1x1 卷积层、一个2x2 平均池化层组成。其中 1x1 卷积层用于减少DenseNet 块的输出通道数,提高模型的紧凑性。

    如果不减少DenseNet 块的输出通道数,则经过了 八、 DenseNet - 图48DenseNet 块之后,网络的feature map 的通道数为:八、 DenseNet - 图49 ,其中 八、 DenseNet - 图50 为输入图片的通道数, 八、 DenseNet - 图51 为每个DenseNet 块的层数。

    八、 DenseNet - 图52

  3. 如果Dense 块输出feature map的通道数为 八、 DenseNet - 图53 ,则可以使得过渡层输出feature map 的通道数为 八、 DenseNet - 图54 ,其中 八、 DenseNet - 图55 为压缩因子。

    • 八、 DenseNet - 图56 时,经过过渡层的feature map 通道数不变。

    • 八、 DenseNet - 图57 时,经过过渡层的feature map 通道数减小。此时的DenseNet 称做 DenseNet-C

      结合了DenseNet-CDenseNet-B 的改进的网络称作 DenseNet-BC

8.3 网络性能

  1. 网络结构:ImageNet 训练的DenseNet 网络结构,其中增长率 八、 DenseNet - 图58

    • 表中的 conv 代表的是 BN-ReLU-Conv 的组合。如 1x1 conv 表示:先执行BN,再执行ReLU,最后执行1x1 的卷积。
    • DenseNet-xx 表示DenseNet 块有xx 层。如:DenseNet-169 表示 DenseNet 块有 八、 DenseNet - 图59 层 。
    • 所有的 DenseNet 使用的是 DenseNet-BC 结构,输入图片尺寸为224x224,初始卷积尺寸为7x7、输出通道 2k、步长为2 ,压缩因子 八、 DenseNet - 图60
    • 在所有DenseNet 块的最后接一个全局平均池化层,该池化层的结果作为softmax 输出层的输入。

    八、 DenseNet - 图61

  2. ImageNet 验证集的错误率(single-crop/10-crop):

    模型top-1 error(%)top-5 error(%)
    DenseNet-12125.02/23.617.71/6.66
    DenseNet-16923.80/22.086.85/5.92
    DenseNet-20122.58/21.466.34/5.54
    DenseNet-26422.15/20.806.12/5.29

    下图是DenseNetResNetImageNet 验证集的错误率的比较(single-crop)。左图为参数数量,右图为计算量。

    八、 DenseNet - 图62

    从实验可见:DenseNet 的参数数量和计算量相对ResNet 明显减少。

    • 具有 20M 个参数的DenseNet-201 与具有 40M 个参数的ResNet-101 验证误差接近。
    • ResNet-101 验证误差接近的DenseNet-201 的计算量接近于ResNet-50,几乎是ResNet-101 的一半。
  3. DenseNetCIFARSVHN 验证集的表现:

    • C10+C100+ :表示对CIFAR10/CIFAR100 执行数据集增强,包括平移和翻转。
    • C10/C100/SVHN 三列上的DenseNet 采用了 Dropout
    • DenseNetDepth 列给出的是 八、 DenseNet - 图63 参数。

    八、 DenseNet - 图64

    从实验可见:

    • 不考虑压缩因子和bottleneck八、 DenseNet - 图65八、 DenseNet - 图66 越大DenseNet表现更好。这主要是因为模型容量相应地增长。

      网络可以利用更大、更深的模型提高其表达学习能力,这也表明了DenseNet 不会受到优化困难的影响。

    • DenseNet 的参数效率更高,使用了压缩因子和bottleneckDenseNet-BC 的参数利用率极高。

      这带来的一个效果是:DenseNet-BC 不容易发生过拟合。

      事实上在CIFAR10 上,DenseNet八、 DenseNet - 图67 中,参数数量提升了4倍但是验证误差反而 5.77 下降到 5.83,明显发生了过拟合。而DenseNet-BC 未观察到过拟合。

  4. DenseNet 提高准确率的一个可能的解释是:各层通过较短的连接(最多需要经过两个或者三个过渡层)直接从损失函数中接收额外的监督信息。

8.4 内存优化

8.4.1 内存消耗

  1. 虽然 DenseNet 的计算效率较高、参数相对较少,但是DenseNet 对内存不友好。考虑到GPU 显存大小的限制,因此无法训练较深的 DenseNet

  2. 假设DenseNet块包含 八、 DenseNet - 图68 层,对于第 八、 DenseNet - 图69 层有:八、 DenseNet - 图70

    假设每层的输出feature map 尺寸均为八、 DenseNet - 图71、通道数为 八、 DenseNet - 图72八、 DenseNet - 图73BN-ReLU-Conv(3x3) 组成,则:

    • 拼接Concat操作 八、 DenseNet - 图74 :需要生成临时feature map 作为第 八、 DenseNet - 图75 层的输入,内存消耗为 八、 DenseNet - 图76
    • BN 操作:需要生成临时feature map 作为ReLU 的输入,内存消耗为 八、 DenseNet - 图77
    • ReLU 操作:可以执行原地修改,因此不需要额外的feature map 存放ReLU 的输出。
    • Conv 操作:需要生成输出feature map 作为第 八、 DenseNet - 图78 层的输出,它是必须的开销。

    因此除了第 八、 DenseNet - 图79 层的输出feature map 需要内存开销之外,第 八、 DenseNet - 图80 层还需要 八、 DenseNet - 图81 的内存开销来存放中间生成的临时feature map

    整个 DenseNet Block 需要 八、 DenseNet - 图82 的内存开销来存放中间生成的临时feature map 。即DenseNet Block 的内存消耗为八、 DenseNet - 图83,是网络深度的平方关系。

  3. 拼接Concat操作是必须的,因为当卷积的输入存放在连续的内存区域时,卷积操作的计算效率较高。而DenseNet Block 中,第 八、 DenseNet - 图84 层的输入feature map 由前面各层的输出feature map 沿通道方向拼接而成。而这些输出feature map 并不在连续的内存区域。

    另外,拼接feature map 并不是简单的将它们拷贝在一起。由于feature mapTensorflow/Pytorch 等等实现中的表示为 八、 DenseNet - 图85channel first),或者 八、 DenseNet - 图86(channel last),如果简单的将它们拷贝在一起则是沿着mini batch 维度的拼接,而不是沿着通道方向的拼接。

  4. DenseNet Block 的这种内存消耗并不是DenseNet Block 的结构引起的,而是由深度学习库引起的。因为Tensorflow/PyTorch 等库在实现神经网络时,会存放中间生成的临时节点(如BN 的输出节点),这是为了在反向传播阶段可以直接获取临时节点的值。

    这是在时间代价和空间代价之间的折中:通过开辟更多的空间来存储临时值,从而在反向传播阶段节省计算。

  5. 除了临时feature map 的内存消耗之外,网络的参数也会消耗内存。设 八、 DenseNet - 图87BN-ReLU-Conv(3x3) 组成,则第 八、 DenseNet - 图88 层的网络参数数量为:八、 DenseNet - 图89 (不考虑 BN )。

    整个 DenseNet Block 的参数数量为 八、 DenseNet - 图90 ,即 八、 DenseNet - 图91。因此网络参数的数量也是网络深度的平方关系。

    • 由于DenseNet 参数数量与网络的深度呈平方关系,因此DenseNet 网络的参数更多、网络容量更大。这也是DenseNet 优于其它网络的一个重要因素。
    • 通常情况下都有 八、 DenseNet - 图92 ,其中 八、 DenseNet - 图93 为网络feature map 的宽、高,八、 DenseNet - 图94 为网络的增长率。所以网络参数消耗的内存要远小于临时feature map 消耗的内存。

8.4.2 内存优化

  1. 论文《Memory-Efficient Implementation of DenseNets》通过分配共享内存来降低内存需求,从而使得训练更深的DenseNet 成为可能。

    其思想是利用时间代价和空间代价之间的折中,但是侧重于牺牲时间代价来换取空间代价。其背后支撑的因素是:Concat操作和BN 操作的计算代价很低,但是空间代价很高。因此这种做法在DenseNet 中非常有效。

  2. 传统的DenseNet Block 实现与内存优化的DenseNet Block 对比如下(第 八、 DenseNet - 图95 层,该层的输入feature map 来自于同一个块中早前的层的输出):

    • 左图为传统的DenseNet Block 的第 八、 DenseNet - 图96 层。首先将 feature map 拷贝到连续的内存块,拷贝时完成拼接的操作。然后依次执行BNReLUConv 操作。

      该层的临时feature map 需要消耗内存 八、 DenseNet - 图97,该层的输出feature map 需要消耗内存 八、 DenseNet - 图98

      • 另外某些实现(如LuaTorch)还需要为反向传播过程的梯度分配内存,如左图下半部分所示。如:计算 BN 层输出的梯度时,需要用到第 八、 DenseNet - 图99 层输出层的梯度和BN 层的输出。存储这些梯度需要额外的 八、 DenseNet - 图100 的内存。
      • 另外一些实现(如PyTorch,MxNet)会对梯度使用共享的内存区域来存放这些梯度,因此只需要 八、 DenseNet - 图101 的内存。
    • 右图为内存优化的DenseNet Block 的第 八、 DenseNet - 图102 层。采用两组预分配的共享内存区Shared memory Storage location 来存Concate 操作和BN 操作输出的临时feature map

    八、 DenseNet - 图103

  3. 第一组预分配的共享内存区:Concat 操作共享区。第 八、 DenseNet - 图104 层的 Concat 操作的输出都写入到该共享区,第 八、 DenseNet - 图105 层的写入会覆盖第 八、 DenseNet - 图106 层的结果。

    • 对于整个Dense Block,这个共享区只需要分配 八、 DenseNet - 图107 (最大的feature map )的内存,即内存消耗为 八、 DenseNet - 图108 (对比传统DenseNet八、 DenseNet - 图109)。

    • 后续的BN 操作直接从这个共享区读取数据。

    • 由于第 八、 DenseNet - 图110 层的写入会覆盖第 八、 DenseNet - 图111 层的结果,因此这里存放的数据是临时的、易丢失的。因此在反向传播阶段还需要重新计算第 八、 DenseNet - 图112 层的Concat 操作的结果。

      因为Concat 操作的计算效率非常高,因此这种额外的计算代价很低。

  4. 第二组预分配的共享内存区:BN 操作共享区。第 八、 DenseNet - 图113 层的 BN 操作的输出都写入到该共享区,第 八、 DenseNet - 图114 层的写入会覆盖第 八、 DenseNet - 图115 层的结果。

    • 对于整个Dense Block,这个共享区也只需要分配 八、 DenseNet - 图116 (最大的feature map )的内存,即内存消耗为 八、 DenseNet - 图117 (对比传统DenseNet八、 DenseNet - 图118)。

    • 后续的卷积操作直接从这个共享区读取数据。

    • Concat 操作共享区同样的原因,在反向传播阶段还需要重新计算第 八、 DenseNet - 图119 层的BN 操作的结果。

      BN 的计算效率也很高,只需要额外付出大约 5% 的计算代价。

  5. 由于BN 操作和Concat 操作在神经网络中大量使用,因此这种预分配共享内存区的方法可以广泛应用。它们可以在增加少量的计算时间的情况下节省大量的内存消耗。

8.4.3 优化结果

  1. 如下图所示,DenseNet 不同实现方式的实验结果:

    • Naive Implementation(LuaTorch):采用LuaTorch 实现的,不采用任何的内存共享区。
    • Shared Gradient Strorage(LuaTorch):采用LuaTorch 实现的,采用梯度内存共享区。
    • Shared Gradient Storage(PyTorch):采用PyTorch 实现的,采用梯度内存共享区。
    • Shared Gradient+BN+Concat Strorate(LuaTorch):采用LuaTorch 实现的,采用梯度内存共享区、Concat内存共享区、BN内存共享区。
    • Shared Gradient+BN+Concat Strorate(PyTorch):采用LuaTorch 实现的,采用梯度内存共享区、Concat内存共享区、BN内存共享区。

    注意:

    • PyTorch 自动实现了梯度的内存共享区。

    • 内存消耗是参数数量的线性函数。因为参数数量本质上是网络深度的二次函数,而内存消耗也是网络深度的二次函数。

      如前面的推导过程中,DenseNet Block 参数数量 八、 DenseNet - 图120,内存消耗 八、 DenseNet - 图121。因此 八、 DenseNet - 图122,即 八、 DenseNet - 图123

  1. ![](/projects/huaxiaozhuan-ai/2a7fa2ac67ee4d48d4147b7dd8fa26eb.png)
  1. 如下图所示,DenseNet 不同实现方式的训练时间差异(NVIDIA Maxwell Titan-X ):

    • 梯度共享存储区不会带来额外时间的开销。
    • Concat内存共享区、BN内存共享区需要额外消耗 15%(LuaTorch) 或者20% (PyTorch) 的时间。

    八、 DenseNet - 图124

  2. 如下图所示,不同DenseNet的不同实现方式在ImageNet 上的表现(single-crop test):

    • DenseNet cosine 使用 八、 DenseNet - 图125 学习率。

    • 经过内存优化的DenseNet 可以在单个工作站(8 NVIDIA Tesla M40 GPU )上训练 264 层的网络,并取得了top-1 error=20.26% 的好成绩。

      网络参数数量:232 层DenseNetk=48,55M 参数。 264 层DenseNetk=32,33M 参数;k=48,73M 参数。

    八、 DenseNet - 图126