查看全课大纲(第 78 / 93 节)
  1. 1.计算机视觉概述
  2. 2.计算机视觉应用场景
  3. 3.困难与挑战
  4. 4.开源库介绍
  5. 5.图像显示与存储
  6. 6.CLAHE
  7. 7.腐蚀膨胀与开闭运算
  8. 8.滤波与边缘填充
  9. 9.各种滤波
  10. 10.图像金字塔
  11. 11.傅里叶变换
  12. 12.短时傅里叶变换与小波变换
  13. 13.颜色特征与颜色直方图
  14. 14.几何特征_边缘
  15. 15.几何特征-角点与斑点
  16. 16.局部特征-SIFT特征描述子
  17. 17.局部特征-SURF特征描述子
  18. 18.局部特征-ORB特征描述子
  19. 19.其他特征描述子
  20. 20.传统图像分割技术
  21. 21.GraphCut
  22. 22.GrabCut
  23. 23.人脸检测的传统方法
  24. 24.行人检测的传统方法HOG+SVM
  25. 25.行人检测DPM
  26. 26.人工神经网络的架构
  27. 27.目标函数与梯度下降
  28. 28.误差反向传播
  29. 29.可手算的神经网络
  30. 30.改进目标函数与克服梯度消散
  31. 31.神经网络之传统神经网络与深度网络的差异
  32. 32.各种梯度下降算法
  33. 33.如何选择合适的梯度下降算法
  34. 34.避免过适应
  35. 35.CNN的架构
  36. 36.CNN的误差反向传播_卷积层
  37. 37.CNN的误差反向传播_池化层
  38. 38.分类所用的数据集
  39. 39.Alexnet详解
  40. 40.VGG详解
  41. 41.GoogLeNet_v1
  42. 42.BatchNormalization
  43. 43.GoogLeNet_v3v4
  44. 44.ResNet
  45. 45.ResNeXt
  46. 46.CNN设计准则
  47. 47.图像检索与推土机距离
  48. 48.基于颜色相似性
  49. 49.基于形状相似性
  50. 50.基于纹理相似性
  51. 51.基于局部特征相似性
  52. 52.DL的二值哈希编码
  53. 53.高维空间中检索KDTree
  54. 54.高维空间中检索LSH
  55. 55.目标识别任务综述
  56. 56.RCNN
  57. 57.SPP-Net
  58. 58.Fast R-CNN
  59. 59.Faster R-CNN
  60. 60.R-CNN系列模型回顾
  61. 61.R-FCN的设计思路
  62. 62.R-FCN的实现
  63. 63.YOLOv1
  64. 64.YOLOv2_9000
  65. 65.YOLOv3
  66. 66.图像分割应用场景与数据集
  67. 67.上采样的实现方式
  68. 68.FCN网络架构的由来
  69. 69.FCN构建细节
  70. 70.DeepLabv1
  71. 71.CRF
  72. 72.DeepLabv2
  73. 73.DeepLabv3
  74. 74.特定的医学影像分割任务
  75. 75.U-Net
  76. 76.3D U-Net
  77. 77.V-Net
  78. 78.DenseNet
  79. 79.病理切片分析任务及数据集
  80. 80.病理切片分析
  81. 81.图说任务及其传统处理方法
  82. 82.深度语言模型与RNN
  83. 83.LSTM及其变种
  84. 84.NIC模型
  85. 85.SAT模型
  86. 86.图说的性能指标
  87. 87.判别模型与生成模型
  88. 88.KL散度与JS散度
  89. 89.VAE
  90. 90.GAN的基本原理
  91. 91.DCGAN与CGAN
  92. 92.Wasserstein GAN
  93. 93.SRGAN

DenseNet

DenseNet 与 FC-DenseNet

小象实战讲义 · 基于深度学习的计算机视觉

在上一节我们探讨了U-Net及其三维扩展(3D U-Net、V-Net),它们通过编码器-解码器结构和跳跃连接来解决医学影像分割问题。本节我们将介绍另一种极具特色的网络结构——DenseNet,以及其应用于图像分割的全卷积版本FC-DenseNet。DenseNet的核心思想是“特征复用”,通过密集连接极大地增强了特征在网络中的流动和利用效率,从而在减少参数量的同时,提升了模型的性能,尤其在小数据集上表现出优异的抗过拟合能力。学完本节,你将理解DenseNet的设计哲学,掌握其密集连接机制,并了解如何将其改造为适用于分割任务的FC-DenseNet架构。

💡 核心导读

  • DenseNet的设计动机:不同于单纯增加网络深度(ResNet)或宽度(Inception),DenseNet从特征利用效率入手,通过密集连接实现特征的极致复用。
  • 密集连接机制:每一层的输入都来自前面所有层的输出,从而建立了L层网络间L(L+1)/2个连接,极大地促进了梯度和特征的流动。
  • DenseNet的优势:有效缓解梯度消失、加强特征传递、减少参数量、提高参数利用率、具备隐式深度监督,并在数据匮乏时表现出良好的抗过拟合能力。
  • FC-DenseNet架构:将用于分类的DenseNet改造为全卷积的编码器-解码器结构,用于图像分割,并解释了其解码路径密集连接不对称(Dense Block 的输入不参与输出拼接)的设计原因。
  • Dense Block内部结构:详解Dense Block中每一层的组成(BN-ReLU-Conv-Dropout)以及特征图的增长与堆叠方式。

从“深”与“宽”到“密”

在DenseNet提出之前,提升卷积神经网络性能的主流方向主要有两个:合理的深与合理的宽。

  • 合理的深:以ResNet为代表,通过引入残差连接(恒等映射)解决了极深网络中的梯度消失和模型退化问题,使得网络可以训练到数百甚至上千层。
  • 合理的宽:以GoogLeNet的Inception系列为代表,通过在同一层内并行使用不同尺寸的卷积核(如1x1, 3x3, 5x5)来捕获多尺度特征,拓宽了网络的“宽度”。

注意这两条都是“合理的”深与宽:不加残差连接硬把网络堆到20层以上,效果会越来越差,也就是模型退化;不靠 Inception 式的多分支组合、只是把卷积核变大,同样不会有好结果。

DenseNet则开辟了第三条道路:极致的特征复用。它的设计者从特征本身入手,思考如何让网络中的每一层都能“看到”前面所有层提取到的特征,从而最大化特征的利用效率,在提升性能的同时,还能显著减少模型参数的数量。

DenseNet:密集连接的卷积网络

核心思想与优点

DenseNet的核心思想非常简单却非常强大:确保网络中各层之间实现最大程度的信息流动。具体来说,在DenseNet中,每一层都接受其前面所有层的输出作为自己的输入。

这种密集连接(Dense Connection)带来了诸多优点:

  1. 减轻梯度消失:由于每一层都直接连接到损失函数(通过后续层的密集连接),梯度可以更顺畅地反向传播,缓解了深层网络中的梯度消失问题。
  2. 加强特征传递与复用:特征被显式地重复使用,网络鼓励特征重用,使得学习到的特征更具判别力。
  3. 减少参数量:因为每一层都只需要学习很少的新特征(k个,称为增长率),大部分特征可以从前面层复用,所以整体参数量更少。
  4. 提高参数有效性:参数减少意味着每个参数被利用的效率更高。
  5. 隐式深度监督:密集连接类似于许多“短路”路径,为中间层提供了额外的监督信号。
  6. 优秀的抗过拟合性能:尤其是在训练数据量较少时,DenseNet因其参数效率和强大的正则化能力,往往能取得更好的泛化性能。

密集连接详解

假设一个DenseNet有L层(这里的“层”指的是一个非线性变换,如卷积操作),那么它总共会有 L(L+1)/2 个连接(含输入x0x_0连到各层的那些边)。按同一计数口径,传统的前馈网络 L 层只有 L 条连接;ResNet 在此基础上,每个残差块再额外加一条 shortcut。

用公式来描述:设第l层的非线性变换为Hl(⋅)H_l(\cdot)(通常包含BN、ReLU和卷积)。该层的输入xlx_l是前面所有层输出特征图的拼接(concatenation): xl=Hl([x0,x1,...,xl−1])x_l = H_l([x_0, x_1, ..., x_{l-1}]) 其中 [⋅][ \cdot ] 表示沿通道维度的拼接操作,x0x_0是网络的原始输入。

这意味着:

  • 第一层H1H_1的输入是x0x_0。
  • 第二层H2H_2的输入是[x0,x1][x_0, x_1]。
  • 第三层H3H_3的输入是[x0,x1,x2][x_0, x_1, x_2]。
  • ……
  • 第l层HlH_l的输入是前面l层所有输出特征图的拼接。

这种结构使得网络能够从所有先前层中收集并保留“集体知识”。

从DenseNet到FC-DenseNet

整体架构

为了将用于图像分类的DenseNet应用于像素级预测的医学影像分割任务,我们需要将其改造成一个全卷积的编码器-解码器架构,即FC-DenseNet。其整体结构与U-Net类似,包含一个下采样(编码)路径和一个上采样(解码)路径。

输入图像
  |
[初始卷积] -> 特征图
  |
  v
+---------------------+      +---------------------+
|  编码路径 (下采样)   |      |  解码路径 (上采样)   |
|                     |      |                     |
|  Dense Block (DB)   |      |  Dense Block (DB)   |
|        |            |      |        ^            |
|  Transition Down(TD)|      | Transition Up (TU) |
|        v            |      |        |            |
|  ... (重复) ...     |      |  ... (重复) ...     |
+---------------------+      +---------------------+
         |                             ^
         +--------- Skip Connection ---+
  • 编码路径:由多个 Dense Block (DB) 和 Transition Down (TD) 层交替组成。DB负责密集地提取和复用特征;TD层(1×1 卷积 + 池化)负责降低特征图的空间分辨率(下采样)。注意 FC-DenseNet 的 TD 只缩小空间尺寸,不压缩通道数。
  • 解码路径:同样由多个 Dense Block (DB) 和 Transition Up (TU) 层交替组成。TU层(通常使用转置卷积)负责提升特征图的空间分辨率(上采样)。
  • 跳跃连接:与U-Net类似,编码路径中每个DB的输出会通过跳跃连接,与解码路径中对应分辨率TU层的输出进行拼接,为解码器提供高分辨率的细节信息,这对于精确分割边界至关重要。请特别注意:这里的合并是通道拼接(concatenation),不是 ResNet 那种逐元素相加——特征图越拼越厚,这正是 DenseNet 与 ResNet 最容易被混为一谈的地方。

关键设计:不对称的密集连接

一个值得注意的细节是,在FC-DenseNet的解码路径中,Dense Block的输入并不与其自身的输出进行拼接。这与编码路径以及原始DenseNet的思想似乎相悖。原文对此的解释是:为了避免特征图数量的线性爆炸式增长。

  • 在编码路径:特征图数量随着DB的堆叠而增长是有益的,因为网络底层需要足够多的通道来表达各种模式;而 TD 只缩小空间尺寸、不压缩通道,所以通道数一路递增(48→112→192→304→464→656→896)。
  • 在解码路径:我们的目标是逐步恢复空间分辨率,同时让通道数回落,最终收敛到分割类别数。如果解码路径的DB也把输入拼进输出,特征图数量会随深度线性增长,与“尺度越来越大、通道越来越少”的初衷背道而驰,还会带来可观的额外计算和显存开销。

因此,解码路径中每个DB内部的各个层之间仍然是密集连接,差别只在于这个DB的输入不再进入输出拼接,即DB的输出只包含本块新产生的 L×kL \times k 个特征图,通道数于是逐段回落(12k→10k→7k→5k→4k12k \to 10k \to 7k \to 5k \to 4k)。这是性能与效率之间的一个巧妙权衡。

深入Dense Block与过渡层

Dense Block 结构

Dense Block是构成DenseNet的基本模块。一个包含L个层的Dense Block内部结构如下:

输入: [x0, x1, ..., x_{l-1}] (来自前l层的拼接)
      |
      v
+-----------------------------+
|  第 l 层 (H_l):             |
|  1. Batch Normalization     |
|  2. ReLU                    |
|  3. 3x3 Convolution         | -> 输出 k 个特征图 (称为增长率)
|  4. Dropout (可选)          |
+-----------------------------+
      |
      v
输出: x_l (k个特征图)
  • 增长率 (k):每个H_l层产生固定数量k个新的特征图。k通常设置得较小(分类版DenseNet常用12、24、32,本节要讲的FC-DenseNet103取16),这使得网络非常紧凑。
  • 特征图增长:假设进入第一个DB的输入有m0m_0个特征图。经过第一个层H1H_1后,总特征图数变为m0+km_0 + k。经过第二个层H2H_2后,变为m0+2km_0 + 2k,以此类推。一个包含L层的DB,其最终输出特征图数为m0+L×km_0 + L \times k。所有中间特征图都被保留并传递给后续层。

Transition Down 与 Transition Up 层

  • Transition Down (TD) - 下采样过渡层:

    输入
      |
      v
    Batch Normalization
      |
      v
    ReLU
      |
      v
    1x1 Convolution (通道数保持不变,只做通道间的线性组合)
      |
      v
    Dropout (可选)
      |
      v
    2x2 Max Pooling (stride=2) -> 输出 (空间尺寸减半)

    TD层位于两个DB之间:1×1卷积把上一块的通道做线性组合(通道数不变,所以省计算量并不靠它),真正的计算量下降来自随后的 2×2 池化——空间分辨率减半,后面各层的特征图面积就只剩四分之一。FC-DenseNet 的 TD 保持通道数不变(只有分类版 DenseNet 的 transition layer 才会用压缩率 θ 压低通道),所以编码路径上通道数只增不减(48→112→…→896)。

  • Transition Up (TU) - 上采样过渡层:

    输入
      |
      v
    3x3 Transposed Convolution (stride=2) -> 输出 (空间尺寸加倍)

    TU层位于解码路径,主要作用是通过转置卷积(反卷积)将特征图的空间尺寸放大,为与跳跃连接的特征拼接以及后续处理做准备。

FC-DenseNet 实例:FC-DenseNet103

一个具体的FC-DenseNet实现(如FC-DenseNet103,增长率 k=16)架构如下:

输入 (e.g., 224x224x3)
  |
3x3 Conv (输出 m=48 通道)
  |
DB1 (4层)  -> 48 + 4*k  = 112 通道,224x224
  |
TD1 (1x1 卷积 + 2x2 池化,通道 112,尺寸减半)
  |
DB2 (5层)  -> 112 + 5*k = 192 通道,112x112
  |
TD2 (通道 192,尺寸减半)
  |
DB3 (7层)  -> 192 + 7*k = 304 通道,56x56
  |
TD3 (通道 304,尺寸减半)
  |
DB4 (10层) -> 304 + 10*k = 464 通道,28x28
  |
TD4 (通道 464,尺寸减半)
  |
DB5 (12层) -> 464 + 12*k = 656 通道,14x14
  |
TD5 (通道 656,尺寸减半)
  |
DB6 (15层) -> 656 + 15*k = 896 通道,7x7   <- 瓶颈层
  |
------------- 编码路径结束 / 解码路径开始 -------------
  |
TU1 (3x3 转置卷积,stride=2) + 与 DB5 输出(656) 拼接 -> 7x7 放大到 14x14
  |
DB7 (12层) -> 只输出 12*k = 192 个新特征图
  |
TU2 (上采样) + 与 DB4 输出(464) 拼接 -> 28x28
  |
DB8 (10层) -> 10*k = 160 个新特征图
  |
TU3 (上采样) + 与 DB3 输出(304) 拼接 -> 56x56
  |
DB9 (7层)  -> 7*k = 112 个新特征图
  |
TU4 (上采样) + 与 DB2 输出(192) 拼接 -> 112x112
  |
DB10 (5层) -> 5*k = 80 个新特征图
  |
TU5 (上采样) + 与 DB1 输出(112) 拼接 -> 224x224
  |
DB11 (4层) -> 4*k = 64 个新特征图
  |
1x1 Conv (输出通道数 = 分割类别数 C)
  |
Softmax -> 输出分割图 (224x224xC)

可以看到,编码路径中DB的层数逐渐增加,通道数在DB内累积、在TD处保持不变(只缩小尺寸);解码路径在尺度与层数上与编码路径镜像对应,但密集连接是不对称的:TU 先放大尺寸,再与编码端同分辨率的DB输出拼接,随后的DB只输出本块新增的 L×kL \times k 个特征图,通道数逐段回落,最后经 1×1 卷积与 Softmax 得到 C 类分割图。把图里的层数加一遍——11 个DB共 91 层,加 5 个TD、5 个TU,再加首尾两个卷积,正好 103 层,这就是“103”的由来。

最后那个 1×1 卷积的输出通道数 C,指的是掩码上要标注的语义类别数(如 CamVid 的路面场景类别),不是图像分类任务里的类别数。

📝 动手练一练

  1. 概念辨析:ResNet中的残差连接是F(x) + x(加法),而DenseNet中的密集连接是[x, F(x)](拼接)。请简要分析这两种连接方式在特征传递和梯度流动上的主要区别。
👉 点击查看参考答案

特征传递:

  • ResNet (加法):强调的是特征修正。残差块学习的是目标映射与恒等映射之间的残差F(x)。输出是x + F(x),允许网络轻松地学习微小的调整或恒等映射,有助于解决深度网络退化问题。特征信息更多是“流动”和“修正”,而非大量累积。
  • DenseNet (拼接):强调的是特征复用与累积。每一层都将前面所有层的特征图原封不动地保留并传递下去。新的层可以自由选择使用前面任何层的特征,实现了显式的特征重用。特征信息是不断“积累”和“丰富”的。

梯度流动:

  • ResNet:加法操作在反向传播时,梯度可以无衰减地通过x这条捷径(Shortcut)直接传递到更早的层,有效缓解了梯度消失。公式为:∂L∂x=∂L∂(x+F(x))⋅(1+∂F(x)∂x)\frac{\partial L}{\partial x} = \frac{\partial L}{\partial (x+F(x))} \cdot (1 + \frac{\partial F(x)}{\partial x})。
  • DenseNet:由于每一层都直接连接到损失函数(通过后续层的密集连接),梯度到浅层网络的路径非常短且多样。损失函数相对于浅层参数的梯度包含了来自许多深层路径的梯度之和,这同样极大地缓解了梯度消失问题。拼接操作本身不改变梯度值,只是将梯度路由到对应的输入特征图上。
  1. 通道数计算:假设FC-DenseNet编码路径中一个Dense Block的增长率k=12。若该Block的输入特征图数为M=64,且该Block包含5个层。请问:
    • a) 经过这个Dense Block后,输出的总特征图数是多少?
    • b) 这个Block后面紧接一个Transition Down层(1×1卷积保持通道数不变,再做2×2最大池化),TD输出的通道数与空间尺寸各是多少?
👉 点击查看参考答案

a) 编码路径中,Dense Block的输出特征图数 = 输入特征图数 + 层数 × 增长率 输出通道数=M+L×k=64+5×12=64+60=124输出通道数 = M + L \times k = 64 + 5 \times 12 = 64 + 60 = 124

b) FC-DenseNet的TD不压缩通道:1×1卷积后仍是124个通道,随后的2×2最大池化只把空间尺寸减半。 所以 TD输出通道数=124TD输出通道数 = 124,空间尺寸变为原来的一半。

本章小结

本节我们深入学习了DenseNet这一通过密集连接实现特征极致复用的经典网络结构,并探讨了其应用于图像分割任务的变体——FC-DenseNet。

  • DenseNet的核心创新在于让网络中的每一层都与之前所有层直接相连,形成了密集的特征复用网络,从而在减少参数量的同时,获得了更强的性能、更顺畅的梯度流以及更好的抗过拟合能力。
  • FC-DenseNet将DenseNet的思想融入U-Net式的编码器-解码器框架,用于像素级分割。它巧妙地处理了编码路径与解码路径中密集连接的不对称性,在充分利用特征的同时,避免了解码路径中特征图的爆炸性增长。
  • Dense Block作为基本构建块,其内部由多个「BN-ReLU-3×3卷积-Dropout」小层顺序堆叠而成,每个层只产生少量新特征(增长率k),大部分特征来自复用。
  • 还要分清一个易错点:FC-DenseNet的TD只缩小空间尺寸、通道数保持不变;解码路径的DB内部仍是密集连接,只是DB的输入不参与输出拼接,通道数才得以逐段回落。

需要说明的是,DenseNet(2017年)与 FC-DenseNet(即 Tiramisu,2017年)都是这一时期的经典工作,今天已属历史而非主力:当前医学影像分割更多采用 nnU-Net 这类自配置框架,以及 Transformer 分割网络和 SAM 系列分割基础模型;密集连接更多是作为「特征复用、参数高效」的设计思想被后续网络借鉴。

📋 行动清单

  • 在脑海中绘制DenseNet中第l层与前面所有层的连接示意图,理解L(L+1)/2个连接的由来。
  • 对比记忆ResNet的残差连接(加)与DenseNet的密集连接(拼接)在公式和思想上的本质区别。
  • 根据FC-DenseNet103的架构描述,尝试在纸上画出其简化的数据流图,特别关注编码与解码路径中DB、TD、TU的对应关系和跳跃连接的位置。

—— 小象教研组