查看全课大纲(第 72 / 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

DeepLabv2

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

在上一节中,我们学习了DeepLab v1如何通过空洞卷积(Atrous Convolution)和全连接条件随机场(Fully Connected CRF)来提升语义分割的精度。DeepLab 系列由一位华裔科学家主导设计,版本迭代很快,从 v1 到 v2、v3 以及 v3 之后的版本,前后至少有四代。然而,v1 模型在处理多尺度目标时仍有局限。本节我们将介绍DeepLab v2,它通过引入空洞空间金字塔池化(Atrous Spatial Pyramid Pooling, ASPP) 和更强大的骨干网络,显著提升了模型对多尺度特征的捕捉能力,是语义分割发展史上的一个重要里程碑。

💡 核心导读

  • 核心改进:DeepLab v2在v1基础上进行了两大关键改进:尝试了 ResNet-101 等更强的骨干网络(同时保留 VGG16 版本),以及引入ASPP模块。
  • 多尺度捕获:ASPP模块通过多个并行的、具有不同空洞率(rate)的空洞卷积层,同时捕获图像中不同尺度的上下文信息。
  • 特征融合:ASPP 各分支输出的各类别得分(softmax 之前的 logits)按元素相加,再统一归一化为概率图,最终得到更精细、鲁棒的分割结果。
  • 性能验证:在 Cityscapes 等数据集上的实验表明,基于 ResNet-101 的 DeepLab v2 优于基于 VGG16 的版本。

从DeepLab v1到v2:为何需要多尺度?

DeepLab v1的核心创新在于:将VGG16的pool4、pool5步长(stride)由2改为1,使总降采样倍数从32降为8,从而保住了特征图的分辨率;但步长减小会让后续卷积的感受野随之变小,于是引入空洞卷积,在不增加参数量和计算量的前提下把感受野恢复回来。然而,它面临一个经验性问题:空洞率(rate)应该设置为多大?

在v1的Conv6层,空洞率被设置为4。但讲师在视频中指出:“不管你定多少,一定会有反例来反对你。” 这是因为现实世界中的物体尺度变化万千。一个固定的感受野可能对某些尺度的物体分割效果很好,但对过大或过小的物体则效果不佳。

为了解决这个问题,一个直观的想法是:与其纠结于选择一个“最佳”的空洞率,不如同时使用多个不同空洞率的卷积来并行提取特征。这种思想借鉴了空间金字塔池化(Spatial Pyramid Pooling, SPP)的思路,旨在构建一个多尺度的特征表达。这就是DeepLab v2的核心改进——空洞空间金字塔池化(ASPP)。

DeepLab v2的两大关键改进

根据视频讲解和课件,DeepLab v2的改进主要集中在以下两个方面:

1. 更强的骨干网络(Backbone)

DeepLab v1主要基于VGG16网络。DeepLab v2 则同时提供了 VGG16 与 ResNet-101 两种骨干网络版本,对比实验后发现ResNet-101的效果更好。

  • 为什么是ResNet? 视频中提到,GoogLeNet 在分类任务上针对性较强(讲师的说法是“有点过适应”),若想比 VGG 取得更好的效果,更应换成 ResNet;此前目标检测中的 R-FCN 等工作也采用了 ResNet,道理相同。ResNet 的残差结构主要解决的是深层网络的退化问题(层数加深反而误差变大),同时改善梯度传播,使上百层的网络仍能稳定训练,从而学习更丰富、更深层的特征,这对像素级的语义分割任务至关重要。
  • 实践结论:在 Cityscapes 等复杂场景分割数据集上,基于 ResNet-101 的 DeepLab v2 优于基于 VGG16 的版本。

2. 空洞空间金字塔池化(ASPP)

这是DeepLab v2最具标志性的创新。其核心思想是:在网络的某个层级(通常是高层特征处),并行部署多个空洞卷积层,每个卷积层使用不同的空洞率(rate)。

ASPP模块的工作机制:

  1. 并行分支:特征从骨干网络的最后一个池化层之后引出(VGG16 版本即 Pool5,课件记作 Conv6 的输入),复制成 4 份,送入 4 条并行的分支。
  2. 空洞卷积配置:每个分支都包含相同的卷积操作序列(课件中记为 Fc6 -> Fc7 -> Fc8,对应 3x3卷积 -> 1x1卷积 -> 1x1卷积)。四路的卷积核大小、层数完全一致,3x3 核本身仍是 3x3;关键区别在于第一个 3x3 卷积的空洞率(rate)不同。视频和课件中给出的取值为:rate = 6, 12, 18, 24。配合各自的 padding 补零,四路输出保持相同的空间尺寸。
  3. 感受野计算:k×k 卷积核在空洞率 r 下的等效采样跨度(课件称其为该分支的“感受野”)为 k + (k-1)(r-1) = (k-1)*r + 1。注意这只是一层卷积在输入上的覆盖宽度,并不等于整网的感受野——骨干网络上游各层还会继续累积。对 3x3 卷积核:
    • rate=6: 感受野 ≈ (3-1)*6 + 1 = 13x13
    • rate=12: 感受野 ≈ (3-1)*12 + 1 = 25x25
    • rate=18: 感受野 ≈ (3-1)*18 + 1 = 37x37
    • rate=24: 感受野 ≈ (3-1)*24 + 1 = 49x49 这样,四个分支就分别专注于捕捉小、中、大等不同尺度范围的上下文特征。
  4. 特征融合:四个分支独立提取特征后,得到四张空间分辨率相同(靠 padding 对齐)、但关注的尺度范围不同的得分图。DeepLab v2 采用逐元素相加的方式进行融合,课件和视频口语中称之为概率相加(Score Fusion)。严格说,相加发生在 softmax 之前:每个分支最后一层 1x1 卷积输出的是每个像素属于各类别的得分(logits),四路得分按元素相加后,再统一做 softmax 得到概率图,之后经过上采样和 CRF 后处理得到最终分割结果。

ASPP的结构示意(基于课件描述):

输入特征图 (来自骨干网络,如Pool5后)
        |
        | (复制为4份)
        |——————————————————————————————————————————————
        |                    |                    |                    |
[分支1]              [分支2]              [分支3]              [分支4]
3x3 Conv (rate=6)   3x3 Conv (rate=12)  3x3 Conv (rate=18)  3x3 Conv (rate=24)
1x1 Conv            1x1 Conv            1x1 Conv            1x1 Conv
1x1 Conv (输出C类)  1x1 Conv (输出C类)  1x1 Conv (输出C类)  1x1 Conv (输出C类)
        |                    |                    |                    |
        ——————————————————————————————————————————————
                        |
                得分相加 (Element-wise Sum)
                        |
                融合后的C类得分图

通过ASPP模块,DeepLab v2能够同时利用多个尺度的上下文信息,从而更鲁棒地分割出大小不一的物体,进一步提升了模型在复杂场景下的分割性能。

代码演示:理解空洞卷积与多尺度感受野

为了更直观地理解不同空洞率如何影响感受野和特征提取,我们可以用一个小例子来模拟。我们将创建一个简单的“特征图”,并思考不同空洞率的卷积核如何与其交互。

import numpy as np

# 模拟一个小的输入特征图 (8x8),中心有一个“激活”区域
input_feature = np.zeros((8, 8))
input_feature[2:6, 2:6] = 1  # 中心4x4区域值为1
print("模拟输入特征图 (中心4x4区域为1):")
print(input_feature)
print()

# 定义不同空洞率(r)的3x3卷积核的“有效采样位置”
# 对于rate=r,卷积核元素间隔为r-1个零。
def get_dilated_kernel_indices(rate):
    """返回3x3卷积核在给定空洞率下,相对于中心点的坐标偏移"""
    base = [-1, 0, 1]
    indices = []
    for i in base:
        for j in base:
            indices.append((i * rate, j * rate))
    return indices

# 查看不同rate下,卷积核覆盖的像素位置(以特征图中心(4,4)为卷积中心点)
center = (4, 4)
print("以特征图中心(4,4)为卷积中心点时,不同rate的3x3卷积核覆盖的坐标:")
for rate in [1, 2, 4, 6]:
    indices = get_dilated_kernel_indices(rate)
    covered_positions = [(center[0] + dx, center[1] + dy) for (dx, dy) in indices]
    print(f"rate={rate}: 覆盖位置 {covered_positions}")
    # 简单计算感受野大小(近似)
    rf = (3 - 1) * rate + 1
    print(f"  近似感受野大小: {rf}x{rf}")
print()

# 模拟一个更具体的例子:一个一维信号上的空洞卷积
print("一维信号上的空洞卷积示例:")
signal_1d = np.array([0, 0, 1, 1, 1, 0, 0])  # 长度为7的信号,中心三个点为1
kernel_1d = np.array([1, 1, 1])  # 3x1的卷积核,权重均为1
print(f"信号: {signal_1d}")
print(f"卷积核: {kernel_1d}")

def dilated_conv_1d(signal, kernel, rate):
    """执行一维空洞卷积(仅演示覆盖位置,不计算具体输出值)"""
    k_size = len(kernel)
    output_len = len(signal) - (k_size - 1) * rate
    if output_len <= 0:
        return []
    # 我们只关心在某个中心位置(如索引3),卷积核覆盖了信号的哪些位置
    center_idx = 3
    covered_indices = []
    for k in range(k_size):
        signal_idx = center_idx + (k - (k_size//2)) * rate
        if 0 <= signal_idx < len(signal):
            covered_indices.append(signal_idx)
    return covered_indices

for r in [1, 2, 3]:
    covered = dilated_conv_1d(signal_1d, kernel_1d, r)
    covered_values = signal_1d[covered]
    print(f"rate={r}: 卷积核覆盖的信号索引 {covered}, 对应值 {covered_values}")
模拟输入特征图 (中心4x4区域为1):
[[0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 1. 1. 1. 1. 0. 0.]
 [0. 0. 1. 1. 1. 1. 0. 0.]
 [0. 0. 1. 1. 1. 1. 0. 0.]
 [0. 0. 1. 1. 1. 1. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]]

以特征图中心(4,4)为卷积中心点时,不同rate的3x3卷积核覆盖的坐标:
rate=1: 覆盖位置 [(3, 3), (3, 4), (3, 5), (4, 3), (4, 4), (4, 5), (5, 3), (5, 4), (5, 5)]
  近似感受野大小: 3x3
rate=2: 覆盖位置 [(2, 2), (2, 4), (2, 6), (4, 2), (4, 4), (4, 6), (6, 2), (6, 4), (6, 6)]
  近似感受野大小: 5x5
rate=4: 覆盖位置 [(0, 0), (0, 4), (0, 8), (4, 0), (4, 4), (4, 8), (8, 0), (8, 4), (8, 8)]
  近似感受野大小: 9x9
rate=6: 覆盖位置 [(-2, -2), (-2, 4), (-2, 10), (4, -2), (4, 4), (4, 10), (10, -2), (10, 4), (10, 10)]
  近似感受野大小: 13x13

一维信号上的空洞卷积示例:
信号: [0 0 1 1 1 0 0]
卷积核: [1 1 1]
rate=1: 卷积核覆盖的信号索引 [2, 3, 4], 对应值 [1 1 1]
rate=2: 卷积核覆盖的信号索引 [1, 3, 5], 对应值 [0 1 0]
rate=3: 卷积核覆盖的信号索引 [0, 3, 6], 对应值 [0 1 0]

从输出可以看出:

  • rate=1(普通卷积)时,卷积核紧密地覆盖中心区域[2,3,4],全部感受到“1”,适合捕捉局部细节。
  • rate=2时,卷积核覆盖[1,3,5],中心是“1”,两侧是“0”,能结合中心激活与周边背景信息。
  • rate=3时,覆盖[0,3,6],同样中心是“1”,但感受野更大,能捕捉更遥远的上下文(虽然此例中两侧是0)。 这模拟了ASPP的思想:演示中的 rate=1 只是普通卷积的参照基线(真实 ASPP 的四路是 6/12/18/24,不含 1);rate 越大,同一个中心点覆盖的范围越宽,rate=2、rate=3 就能把更远处的上下文纳入进来。在真实图像中,不同尺度的物体需要不同rate 的分支来最优地捕捉其特征。

📝 动手练一练

  1. 概念辨析:DeepLab v2的ASPP模块中,四个并行分支的根本区别是什么?是卷积核的大小、卷积层的数量,还是其他参数?

    👉 点击查看参考答案

    四个并行分支的根本区别在于第一个3x3卷积层的空洞率(dilation rate)不同。课件和视频中给出的典型值是rate = 6, 12, 18, 24。这使得每个分支具有不同的感受野,从而能够捕获不同尺度范围的上下文特征。卷积核大小(3x3)、卷积层数量(Fc6, Fc7, Fc8)在各分支中是相同的。

  2. 感受野计算:根据课件,当空洞率rate=12时,对应的感受野大小是25x25。请写出感受野的计算公式,并验证当rate=18时,感受野是否为37x37。

    👉 点击查看参考答案对于一个大小为`k x k`(例如`3x3`)的卷积核,当空洞率为`r`时,其等效采样跨度(课件称“感受野”)`RF`为: `RF = k + (k - 1)(r - 1) = (k - 1) * r + 1` 将`k=3, r=18`代入公式: `RF = (3 - 1) * 18 + 1 = 2 * 18 + 1 = 37` 因此,感受野大小为`37x37`,与课件信息一致。

本章小结

本节我们深入学习了DeepLab v2,它是语义分割领域一个承前启后的重要模型。通过引入空洞空间金字塔池化(ASPP),DeepLab v2巧妙地解决了多尺度物体分割的难题,无需再手动调优单一的空洞率。同时,采用ResNet-101作为骨干网络,进一步提升了特征提取的能力。这两项关键改进使得DeepLab v2在Cityscapes等复杂场景数据集上取得了优于 VGG16 版本的性能。

需要如实定位的是:DeepLab v2 于 2016 年提出,属于 2019 年之前的经典分割方案,它仍依赖全连接 CRF 做后处理,骨干网络也沿用分类任务现成的 VGG/ResNet。此后 DeepLab v3 与 v3+ 继续沿着 ASPP 的多尺度并行思路演进,并逐步弱化甚至去掉了 CRF;今天语义分割的主流已转向 Transformer 与分割大模型,但“多个空洞率并行”的多尺度设计仍被广泛沿用。

📋 行动清单

  • 理解ASPP的核心思想:明确ASPP通过多个不同空洞率的并行分支来捕获多尺度上下文,其输出按元素相加融合(课件称“概率相加”,实际加在 softmax 之前的得分上)。
  • 掌握感受野计算:记住空洞卷积等效采样跨度的计算公式(课件称“感受野”) RF = (k - 1) * r + 1,并能根据给定的k和r进行计算。
  • 对比v1与v2:能够清晰阐述DeepLab v2相对于v1的两个主要改进点(骨干网络和ASPP),并理解其背后的动机。

—— 小象教研组