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

VGG详解

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

在上一节我们学习了开启深度学习革命的AlexNet,它奠定了现代深度CNN的基础架构。然而,AlexNet的设计中仍有一些可以改进的地方,例如其使用了较大的卷积核(如11×11),单个卷积层的计算量较大。本节我们将介绍VGG网络,它通过“用小卷积核堆叠代替大卷积核”的核心思想,在等效感受野下减少了单个卷积层的参数量,同时加深了网络深度、提升了模型性能,并因其简洁规整的结构,成为后续许多视觉任务进行迁移学习的首选基础网络。

💡 核心导读

  • VGG的核心改进:用多个连续的3×3小卷积核堆叠,替代AlexNet中的大卷积核(如11×11、5×5);在等效感受野下,这能减少单个卷积层的参数量,并通过ReLU激活引入更多非线性,增强模型的表达能力。
  • “埃菲尔铁塔”结构:VGG网络呈现下宽上窄的规整结构,图像尺寸逐组减半,通道数逐组增加,是早期CNN的经典范式。
  • 网络深度与性能:VGG探索了网络深度对性能的影响,提出了VGG11、VGG13、VGG16、VGG19等不同深度的变体,其中VGG16和VGG19最为常用。
  • 迁移学习的基础:VGG结构简洁、性能稳定,其预训练模型(在ImageNet上训练所得)的特征提取部分具有通用性,成为小数据集任务上进行迁移学习(Fine-tuning)的理想起点。

VGG:对AlexNet的深化与规整

VGG网络由牛津大学视觉几何组(Visual Geometry Group)提出,并在2014年ImageNet图像分类竞赛中获得第二名。它并非一个颠覆性的创新,而是对AlexNet架构一次深思熟虑的“精装修”。

首先,我们来回顾一下AlexNet的“毛坯房”有哪些可以改进之处:

  1. 卷积核尺寸不一:AlexNet中混合使用了11×11、5×5、3×3等多种尺寸的卷积核,结构上不够统一。
  2. 使用了局部响应归一化(LRN):后续研究(包括VGG论文中的实验)表明,LRN层对模型性能的提升作用有限,反而增加了计算开销。
  3. 网络深度相对较浅:AlexNet仅有8层(5个卷积层+3个全连接层),VGG的作者希望探究更深的网络能否带来更好的性能。

VGG针对这些问题,提出了一个极其规整和简洁的设计方案,其整体结构像一座埃菲尔铁塔:底部(靠近输入图像)比较宽,随着网络向上(靠近输出),逐渐变窄、变深。

我们可以通过一个简化的视角来理解VGG的“组”结构。它将网络分为若干个阶段(组),每个阶段结束时,都会通过一个步长为2的最大池化(Max Pooling)层将特征图的空间尺寸(宽和高)缩小为原来的一半(面积变为原来的 1/4)。同时,通道数逐组加倍(64→128→256→512),而每组内部堆叠多少个卷积层则可多可少——这正是 VGG11/13/16/19 之间的主要差别。

import numpy as np

# 模拟VGG中特征图尺寸的变化过程(以VGG16为例,输入224x224)
# 我们只关注空间尺寸(H, W)和大致通道数(C)的变化
input_size = (224, 224, 3)  # 高,宽,通道
print(f"输入图像尺寸: {input_size[0]}x{input_size[1]}x{input_size[2]}")

# 定义VGG16前向过程中,经过每个池化层后的特征图尺寸变化
# 格式: (阶段描述, 卷积操作后尺寸, 池化后尺寸)
# 注意:为简化,此处忽略卷积的padding细节,VGG中使用padding=1保持尺寸
stages = [
    ("2个卷积层(通道64)", (224, 224, 64), (112, 112, 64)),
    ("2个卷积层(通道128)", (112, 112, 128), (56, 56, 128)),
    ("3个卷积层(通道256)", (56, 56, 256), (28, 28, 256)),
    ("3个卷积层(通道512)", (28, 28, 512), (14, 14, 512)),
    ("3个卷积层(通道512)", (14, 14, 512), (7, 7, 512)),
]

current_size = input_size
for desc, after_conv, after_pool in stages:
    print(f"\n{desc}:")
    print(f"  卷积层输出: {after_conv[0]}x{after_conv[1]} (空间) x {after_conv[2]} (通道)")
    print(f"  池化层输出: {after_pool[0]}x{after_pool[1]} (空间) x {after_pool[2]} (通道)")
    current_size = after_pool
print(f"\n最终,特征图被展平,送入全连接层。")
输入图像尺寸: 224x224x3

2个卷积层(通道64):
  卷积层输出: 224x224 (空间) x 64 (通道)
  池化层输出: 112x112 (空间) x 64 (通道)

2个卷积层(通道128):
  卷积层输出: 112x112 (空间) x 128 (通道)
  池化层输出: 56x56 (空间) x 128 (通道)

3个卷积层(通道256):
  卷积层输出: 56x56 (空间) x 256 (通道)
  池化层输出: 28x28 (空间) x 256 (通道)

3个卷积层(通道512):
  卷积层输出: 28x28 (空间) x 512 (通道)
  池化层输出: 14x14 (空间) x 512 (通道)

3个卷积层(通道512):
  卷积层输出: 14x14 (空间) x 512 (通道)
  池化层输出: 7x7 (空间) x 512 (通道)

最终,特征图被展平,送入全连接层。

从输出可以清晰看到“埃菲尔铁塔”式的变化:空间尺寸从224→112→56→28→14→7逐级减半,而通道数则从3→64→128→256→512逐步增加。这种规整的设计是VGG的一大特点。

核心思想:小卷积核的堆叠艺术

VGG最核心、最精彩的贡献在于其用小卷积核堆叠代替大卷积核的设计思想。

为什么这么做? 在AlexNet中,第一层就使用了11×11的大卷积核。若输入通道数为 CC、输出通道数也为 CC,一个 11×11 卷积层的参数数量是 11×11×C×C=121C211 \times 11 \times C \times C = 121C^2;即便只看单个输出通道,每个空间位置也要做 121×C121 \times C 次乘加,计算量巨大。

VGG的作者思考:能否用一系列更小的卷积核来等效替代一个大卷积核,同时还能获得额外的好处?

答案是肯定的。例如,一个5×5的卷积核,其感受野(能“看到”的输入区域大小)是5×5。我们可以用两个3×3的卷积核堆叠来代替它:

  • 第一个3×3卷积核的感受野是3×3。
  • 第二个3×3卷积核作用在第一个卷积核输出的特征图上,但因为它“看”的是第一个卷积的结果,而第一个卷积的每个点又对应输入的一个3×3区域,所以第二个卷积核的等效感受野就扩大到了5×5(3 + 3 - 1 = 5)。

同理,一个7×7的卷积核可以用三个3×3的卷积核堆叠来替代。

这样做有什么好处?

  1. 参数数量大幅减少:这是最直接的好处。假设输入和输出通道数都是C。

    • 一个7×7卷积层的参数量:7×7×C×C=49C27 \times 7 \times C \times C = 49C^2。
    • 三个3×3卷积层堆叠的参数量:3×(3×3×C×C)=27C23 \times (3 \times 3 \times C \times C) = 27C^2。
    • 参数量降为原来的约 55%(27/49≈55%27/49 \approx 55\%),即减少约 45%,计算量和模型存储开销都显著降低。
  2. 引入了更多的非线性:这是更深层次的优势。在堆叠的小卷积层之间,都使用了ReLU激活函数。相比于单一的大卷积核(本质是线性变换+一次非线性激活),多层小卷积核堆叠引入了多次非线性变换。这使得网络的表达能力更强,能够学习更复杂、更抽象的特征组合。就像活字印刷(小卷积核灵活组合)比雕版印刷(固定的大卷积核)更灵活、更具表现力一样。

import numpy as np

# 演示感受野的计算:堆叠两个3x3卷积等效于一个5x5卷积的感受野
def receptive_field_of_stacked_convs(kernel_size, num_layers):
    """计算堆叠多个相同尺寸卷积核后的等效感受野"""
    rf = kernel_size
    for _ in range(1, num_layers):
        rf = rf + (kernel_size - 1)
    return rf

# 计算堆叠2个3x3卷积的等效感受野
rf_2x3x3 = receptive_field_of_stacked_convs(3, 2)
print(f"堆叠 2 个 3x3 卷积的等效感受野大小: {rf_2x3x3}x{rf_2x3x3}")

# 计算堆叠3个3x3卷积的等效感受野
rf_3x3x3 = receptive_field_of_stacked_convs(3, 3)
print(f"堆叠 3 个 3x3 卷积的等效感受野大小: {rf_3x3x3}x{rf_3x3x3}")

# 参数量对比计算(假设输入输出通道数C=64)
C = 64
params_7x7 = 7 * 7 * C * C
params_3x3_stack = 3 * (3 * 3 * C * C)

print(f"\n假设通道数 C = {C}:")
print(f"  一个7x7卷积层参数量: {params_7x7:,}")
print(f"  三个3x3卷积层参数量: {params_3x3_stack:,}")
print(f"  参数量减少比例: {(1 - params_3x3_stack/params_7x7)*100:.1f}%")
堆叠 2 个 3x3 卷积的等效感受野大小: 5x5
堆叠 3 个 3x3 卷积的等效感受野大小: 7x7

假设通道数 C = 64:
  一个7x7卷积层参数量: 200,704
  三个3x3卷积层参数量: 110,592
  参数量减少比例: 44.9%

计算证实了我们的分析:用3个3×3卷积层堆叠,确实获得了与7×7卷积层相同的感受野,同时参数量减少了约45%。VGG网络将这一思想贯彻到底,全部使用3×3的卷积核,构建了一个深度更大、结构更统一、效率更高的网络。

VGG家族:从11层到19层

VGG论文中系统性地探索了网络深度,提出了从A到E的多种配置,对应我们常说的VGG11、VGG13、VGG16、VGG19等。其结构可以用一个非常简洁的表格来描述:

所有配置共享同一套骨架:每个阶段(组)由若干 3×3 卷积(stride=1、padding=1)堆叠,阶段末尾接一个 2×2、stride=2 的最大池化;最后统一接 3 个全连接层(4096–4096–1000)与 Softmax。各组内部堆叠的卷积层数如下:

配置组1组2组3组4组5卷积层数总层数(含3个全连接层)
A(VGG11)11222811
A-LRN1(后接LRN)1222811
B(VGG13)222221013
C(16层,含1×1)223※3※3※1316
D(VGG16)223331316
E(VGG19)224441619

※ C 配置在组 3、4、5 的末尾各使用一个 1×1 卷积,其余卷积均为 3×3。

表格解读:

  • conv3-64 这类写法表示一个 3×3 卷积、输出 64 个通道。所有 3×3 卷积都使用 padding=1 以保持空间尺寸,直到池化层才下采样。
  • A(VGG11):最浅的版本,8 个卷积层 + 3 个全连接层。
  • A-LRN:在 A 的第一个卷积后加入 LRN 作为对照实验,论文结论是 LRN 收益有限、反而增加开销。
  • B(VGG13):在 A 的基础上,在第 1、2 组各增加一个卷积层,共 10 个卷积层。
  • C(16 层配置):在 B 的基础上,在第 3、4、5 组的末尾各加入一个 1×1 卷积,共 13 个卷积层。1×1 卷积相当于对通道做线性组合,实验收益有限,因此最终采用的 D 全部使用 3×3。
  • D(VGG16):在 B 的基础上,在第 3、4、5 组的末尾各加入一个 3×3 卷积,共 13 个卷积层 + 3 个全连接层 = 16 层,这就是通常所说的 VGG16。
  • E(VGG19):在 D 的基础上,在第 3、4、5 组再各加入一个 3×3 卷积,共 16 个卷积层 + 3 个全连接层 = 19 层。

一个有趣的发现是,尽管网络深度从 11 层增加到 19 层,但总参数量增长并不剧烈(从 1.33 亿到 1.44 亿)。这是因为参数绝大部分集中在顶部的全连接层(尤其第一个全连接层 7×7×512×4096 就有约 1.03 亿个参数),而 VGG 通过小卷积核堆叠加深卷积部分时,新增的参数量相对有限。这体现了其设计的高效性。

在ImageNet竞赛中,VGG16(D)和VGG19(E) 表现最佳,也因此成为最流行、最常用的VGG变体。

VGG的遗产:迁移学习的首选基石

VGG虽然在2014年的竞赛中屈居第二(冠军是GoogLeNet),但它有一个无可比拟的优势:结构极其规整、简洁、易懂。这使得VGG成为后续许多计算机视觉任务进行迁移学习(Transfer Learning) 和微调(Fine-tuning) 的首选基础网络(Backbone)。

为什么VGG特别适合迁移学习? 迁移学习的核心假设是:不同的图像任务(如分类猫狗、识别车辆、检测病变)在底层所依赖的视觉特征是通用的,例如边缘、角点、纹理、基本形状等。只有高层特征才与具体任务高度相关。

VGG网络恰好提供了一个完美的分层特征提取器:

  1. 底层(靠近输入):学习到的是通用、基础的特征(边、角、纹理)。
  2. 中层:学习到的是更复杂的图案和部件组合。
  3. 高层(靠近输出):学习到的是与ImageNet千类物体高度相关的抽象语义特征。

当我们有一个新的、但数据量较小的任务时(例如,只有几千张猫狗图片),我们可以这样做:

  1. 拿来主义:直接加载在ImageNet上预训练好的VGG16模型权重。
  2. 冻结底层:固定(冻结)网络前几层的参数,不让它们在新数据上更新。因为这些层提取的通用特征对我们的新任务依然有用。
  3. 微调高层:只让网络最后面的几层(通常是最后1-2个全连接层)在新数据上进行训练,学习与新任务(猫/狗)相关的特异性特征。
  4. 替换分类头:将原来的1000类分类层(softmax)替换为新的2类分类层(猫/狗)。
# 迁移学习/微调(Fine-tuning)的伪代码流程示意
# 原课基于TensorFlow 1.x,该写法在TF2起需改用`tf.keras`或迁移到PyTorch

# 1. 加载预训练的VGG16模型(不含顶部分类层)
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(224, 224, 3))

# 2. 冻结基础模型的前N层,使其在训练过程中不更新
for layer in base_model.layers[:N]:
    layer.trainable = False

# 3. 在基础模型之上,添加新的自定义分类层
x = base_model.output
x = GlobalAveragePooling2D()(x)  # 或 Flatten()
x = Dense(256, activation='relu')(x)
predictions = Dense(2, activation='softmax')(x)  # 新任务:2类

# 4. 构建最终模型
model = Model(inputs=base_model.input, outputs=predictions)

# 5. 编译并训练,使用较小的学习率进行“微调”
model.compile(optimizer=optimizers.RMSprop(lr=1e-5),
              loss='categorical_crossentropy',
              metrics=['accuracy'])
model.fit(new_training_data, new_training_labels, epochs=10, ...)

通过这种方式,我们只需要几千张新图片和普通的CPU/GPU资源,就能训练出一个性能不错的猫狗分类器,完美解决了小数据集无法训练大模型的过拟合难题。VGG因其结构的经典和预训练模型的广泛可用性,在这一领域发挥了巨大作用,其影响持续至今。

📝 动手练一练

  1. 概念辨析:VGG网络用多个3×3卷积核堆叠来代替大卷积核(如7×7)。请简述这样做带来的两个主要好处,并解释“引入更多非线性”这一好处为什么能增强模型的表达能力。
👉 点击查看参考答案

主要好处:

  1. 大幅减少参数量和计算量:例如,3个3×3卷积堆叠的参数量(27C²)远少于1个7×7卷积(49C²),降低了模型复杂度和计算开销。
  2. 引入更多非线性,增强表达能力:在堆叠的每个3×3卷积层后都使用了ReLU激活函数。相比于单一线性变换+一次非线性激活,多层非线性变换的堆叠使得网络能够拟合更复杂、更抽象的函数关系,从而学习到更丰富的特征组合,模型表达能力更强。
  1. 迁移学习策略选择:假设你有两个新任务:A) 识别不同品种的花(数据量:5万张图片);B) 识别肺部X光片中的特定纹理(数据量:500张图片)。如果都计划使用VGG16预训练模型进行迁移学习,对于这两个任务,在“冻结多少层”和“学习率设置”上,策略会有什么不同?为什么?
👉 点击查看参考答案
  • 任务A(数据量较大,5万张):

    • 冻结层数:可以冻结较少的层(例如只冻结前一半),甚至可以考虑解冻全部层进行微调。因为数据量相对充足,更新更多参数也不至于严重过拟合。
    • 学习率:可以使用相对较大的学习率(例如1e-4),因为需要调整的参数可能较多,数据量也能支持更积极的更新。
  • 任务B(数据量很小,500张):

    • 冻结层数:需要冻结绝大部分层(例如冻结除最后1-2个全连接层外的所有层)。因为数据量极小,如果更新底层参数(提取通用特征),极易导致过拟合。
    • 学习率:必须使用非常小的学习率(例如1e-5或更小),进行精细的“微调”,避免大的权重更新破坏预训练好的通用特征,并减少过拟合。

本章小结

本节我们深入剖析了VGG网络,它是卷积神经网络发展史上的一个重要里程碑。VGG的核心贡献在于其“小卷积核堆叠”的设计哲学,以及由此构建的规整、深层的“埃菲尔铁塔”式网络结构。这一设计在等效感受野下降低了单个卷积块的参数量,并通过增加网络深度和非线性提升了模型性能;需要注意的是,VGG 全网络的总参数量(1.38 亿)和计算量(约 15.5 GFLOPs)其实都高于 AlexNet,不能把它理解为整体更“省”。尽管在当年的ImageNet竞赛中位列第二,但VGG因其极致的简洁性和有效性,成为后续众多计算机视觉任务进行迁移学习的黄金标准基础网络,其影响力深远。

放到今天看,VGG 在分类任务上早已被 ResNet、EfficientNet、ViT 等更深、更高效的骨干网络取代,其 1.38 亿参数中绝大部分集中在全连接层的设计也已被全局平均池化淘汰。但“小卷积核堆叠 + 分组下采样”的思路仍是理解现代 backbone 的经典入口;VGG 预训练特征至今仍在风格迁移、感知损失(perceptual loss)等场景中被用作特征提取器。

📋 行动清单

  • 理解核心理念:能够清晰阐述为什么用多个3×3卷积堆叠优于单个大卷积核,并从参数量和非线性表达能力两方面进行说明。
  • 熟悉网络结构:记住VGG16或VGG19的大致结构(几组、每组几个卷积、池化位置、尺寸变化趋势),并能画出其“埃菲尔铁塔”式的简化框图。
  • 掌握迁移学习思路:理解基于预训练VGG模型进行微调(Fine-tuning)的基本步骤(冻结底层、修改顶层、小学习率训练),并能根据新任务的数据量大小,合理选择冻结策略和学习率。

—— 小象教研组