一文读懂现代卷积神经网络—使用块的网络(VGG)
目录
什么是使用块的网络(VGG)?
一、VGG 的核心思想:用块(Block)构建网络
二、VGG 的网络结构
三、VGG 的优势
1. 结构简洁统一
2. 强大的特征表达能力
3. 小卷积核的计算效率
4. 良好的迁移学习性能
5. 推动深度学习工程化
四、VGG 的局限性
五、VGG 的应用场景
VGG(VGG11)组织架构
CNN、AAlexNet、VGG(以 VGG11 为代表)的特性对比
一个VGG块最多有多少个卷积层?怎么划分那些卷积层属于那一块?
VGG 模型中每个块的通道数是怎么确定的
完整代码
实验结果
什么是使用块的网络(VGG)?
以下从核心思想、结构特点、优势及应用场景四个维度详细解析:
一、VGG 的核心思想:用块(Block)构建网络
VGG 的最大创新在于提出了 模块化设计理念: 将多个小卷积核(3×3)和ReLU 激活堆叠成块(Block,通过块的重复组合构建深层网络。这种设计使网络结构清晰,易于理解和复现。
对比传统设计:
- 传统 CNN(如 AlexNet)的卷积核尺寸多样(11×11、5×5、3×3),结构零散。
- VGG 则统一使用3×3 卷积核,仅通过调整块内卷积层数和通道数来扩展网络。
二、VGG 的网络结构
VGG 有多个版本(如 VGG11、VGG13、VGG16、VGG19),数字代表网络的层数(卷积层 + 全连接层)。以VGG16为例:
VGG16 由 5 层卷积层、3 层全连接层和 softmax 输出层构成,共 16 层其网络结构可表示为: 卷积 - 卷积- 池化- 卷积- 卷积- 池化- 卷积- 卷积- 卷积- 池化- 卷积- 卷积- 卷积 - 池化 - 卷积 - 卷积 - 卷积 - 池化 - 全连接 - 全连接 - 全连接。输入(224×224×3) →Block1: 2个3×3卷积(64) → ReLU → MaxPool(2×2, stride=2) → Block2: 2个3×3卷积(128) → ReLU → MaxPool(2×2, stride=2) → Block3: 3个3×3卷积(256) → ReLU → MaxPool(2×2, stride=2) → Block4: 3个3×3卷积(512) → ReLU → MaxPool(2×2, stride=2) → Block5: 3个3×3卷积(512) → ReLU → MaxPool(2×2, stride=2) →全连接层1: 4096 → ReLU → Dropout(0.5) → 全连接层2: 4096 → ReLU → Dropout(0.5) → 全连接层3: 1000(分类输出)
关键点:
小卷积核优势: 连续使用 3 个 3×3 卷积核(感受野 7×7)等效于 1 个 7×7 卷积核,但参数量减少 3×(3×3) = 27 vs 7×7 = 49,且增加了非线性(更多 ReLU 层)。
块内通道数递增: 每个块的输出通道数翻倍(64→128→256→512),逐步提取更抽象的特征。
固定池化策略: 每个块后使用 2×2 最大池化,步长 2,将特征图尺寸减半。
三、VGG 的优势
1. 结构简洁统一
- 所有卷积层采用相同配置(3×3 卷积核、padding=1、stride=1),降低设计复杂度。
- 块的重复使用使网络层次清晰,易于复现和调整。
2. 强大的特征表达能力
- 通过深层堆叠(16-19 层),VGG 能学习到从低级边缘到高级语义的多层次特征。
- 在 ImageNet 上的实验表明,更深的 VGG19 比 VGG16 准确率更高(Top-5 错误率:7.3% vs 7.5%)。
3. 小卷积核的计算效率
- 相比大卷积核(如 AlexNet 的 11×11),3×3 卷积核参数量更少,计算更快。
- 多层小卷积核的组合引入更多非线性,增强模型表达能力。
4. 良好的迁移学习性能
- VGG 预训练模型广泛用于各种视觉任务(如目标检测、语义分割)的特征提取器。
- 其特征具有很强的通用性,即使在小数据集上微调也能取得优异结果。
5. 推动深度学习工程化
- VGG 的模块化设计启发了后续 ResNet、Inception 等网络的设计,成为现代 CNN 架构的基础范式。
四、VGG 的局限性
参数量巨大: VGG16 有 1.38 亿参数,主要集中在全连接层,导致模型体积大、训练耗时长。
计算成本高: 深层结构和大量全连接层需要强大 GPU 支持,部署难度较大。
易过拟合: 在小数据集上需依赖数据增强和 Dropout 防止过拟合。
五、VGG 的应用场景
图像分类: 在 ImageNet 等基准测试中取得优异成绩,成为分类任务的基线模型。
目标检测: 作为骨干网络(Backbone)用于 Faster R-CNN、SSD 等检测框架,提取图像特征。
语义分割: 通过 FCN(全卷积网络)改造,用于像素级分类任务。
迁移学习: 预训练的 VGG 模型是计算机视觉领域最常用的特征提取器之一,尤其在数据有限的场景下。
VGG(VGG11)组织架构
CNN、AAlexNet、VGG(以 VGG11 为代表)的特性对比
对比维度 基础 CNN(LeNet-5) AlexNet VGG11 提出时间与团队 1998 年,LeCun 等 2012 年,Krizhevsky 等(多伦多大学) 2014 年,牛津大学 VGG 组 网络深度(带参数层) 5 层(2 卷积 + 3 全连接) 8 层(5 卷积 + 3 全连接) 11 层(8 卷积 + 3 全连接) 核心结构设计 简单串联:卷积→池化→全连接,无标准化模块 分两支 GPU 训练,混合多尺寸卷积核,结构较灵活 模块化块结构:每个块含 1 个 3×3 卷积层 + 1 个池化层(部分块含 2 个卷积层),重复堆叠 卷积核配置 5×5(主要),数量少(如 6、16 个) 11×11(第一层)、5×5、3×3,步长可变(如 11×11 步长 4) 统一 3×3 卷积核,步长 1,padding=1(same 填充),数量从 64→128→256→512 逐步翻倍 各块卷积层数量 无 “块” 概念,单卷积层独立 无 “块” 概念,卷积层分散配置(如第一层 11×11,后续混合 5×5、3×3) 4 个块,卷积层数量:1→1→2→2(总 8 层),块内卷积层连续堆叠 池化层 2×2 平均池化 3×3 最大池化(步长 2) 2×2 最大池化(步长 2),每个块末尾使用,共 4 次,每次池化后特征图尺寸减半 激活函数 sigmoid 或 tanh ReLU(首次大规模应用,解决梯度消失问题) ReLU(每卷积层后必用,增强非线性表达) 正则化手段 无(早期无明确正则化) Dropout(全连接层用,比例 0.5)、数据增强 Dropout(全连接层用,比例 0.5)、数据增强 参数数量 约 6 万(仅 LeNet-5) 约 6000 万 约 9700 万(全连接层占比超 85%) 计算复杂度(FLOPs) 极低(约百万级) 中等(约 7 亿) 较高(约 70 亿) ImageNet 性能(top-5 错误率) 无(未参与该任务) 15.3%(2012 年 ILSVRC 冠军) 8.8%(2014 年 ILSVRC 表现) 优势 结构极简,计算量小,适合入门学习与简单任务(如手写数字识别) 开创性突破,证明深度网络价值,平衡性能与计算成本 保留 VGG 系列模块化优势,比更深 VGG(如 VGG16)轻量,训练速度更快 劣势 特征提取能力弱,无法处理高分辨率或复杂图像 结构不够规整,卷积核尺寸混杂,后期被更优模型超越 深度仍有限,复杂任务性能弱于更深网络,全连接层参数冗余仍较高 典型应用场景 手写数字识别(MNIST)、小尺寸简单图像分类 中等复杂度图像分类、早期迁移学习预训练模型 中等分辨率图像任务(如场景分类)、资源有限场景下的迁移学习 技术贡献 奠定 CNN 基础框架(卷积 + 池化 + 全连接) 推动 GPU 用于深度学习、普及 ReLU 和 Dropout,开启深度视觉革命 验证 “小卷积核(3×3)+ 模块化堆叠” 的有效性,为后续网络结构设计提供参考 通过表格可以清晰看出三者的演进关系:基础 CNN 是理论起点,AlexNet 实现了深度突破,VGG 则在深度和结构标准化上进一步优化,共同推动了卷积神经网络从实验室走向实际应用。
一个VGG块最多有多少个卷积层?怎么划分那些卷积层属于那一块?
- 在 VGG 模型中,一个 VGG 块最多有 3 个卷积层9。
- VGG 网络通常由 5 个卷积块组成,划分卷积层属于哪一块的方法主要依据卷积层和池化层的排列顺序以及通道数的变化。一般来说,连续的若干个卷积层后接一个最大池化层构成一个 VGG 块,且同一块内的卷积层通道数相同。
- 例如在 VGG16 中,第一个块包含 2 个 64 通道的卷积层,第二个块包含 2 个 128 通道的卷积层,第三个块包含 3 个 256 通道的卷积层,第四个块包含 3 个 512 通道的卷积层,第五个块包含 3 个 512 通道的卷积层,每个块的最后都有一个最大池化层用于下采样。
VGG 模型中每个块的通道数是怎么确定的
VGG 模型中每个块的通道数是根据经验和实验确定的,主要遵循以下规律:
- 基于前人研究与经验:VGG 模型是在 AlexNet 等模型的基础上发展而来的。前人的研究表明,增加通道数可以让网络提取更多的特征信息。VGG 模型通过逐步增加通道数来加深网络对图像特征的提取能力。
- 通道数翻倍原则:在经典的 VGG 网络中,通常前两个块各有一个卷积层,第一个块的输出通道数设置为 64,第二个块的输出通道数翻倍为 128。后续三个块各有两个卷积层,通道数继续翻倍,依次为 256、512、512,直到达到 512 后不再增加。
- 与网络深度和计算量平衡:通道数的增加会带来计算量的上升。VGG 模型需要在保证能够提取足够特征的同时,控制计算量和模型参数数量,以避免过拟合和保证训练效率。例如 VGG11 使用了较少的卷积层和相对较少的通道数,而 VGG16 和 VGG19 则通过增加卷积层数量和相应的通道数来提升模型性能,但也需要更多的计算资源和训练数据。
- 与输入数据和任务相关:如果输入数据的通道数不同,第一个 VGG 块的输入通道数也会相应改变。例如在处理 Fashion-MNIST 数据集时,由于图像是单通道的,所以第一个 VGG 块的输入通道数为 1,而在处理 RGB 图像时,输入通道数为 3。同时,不同的任务对特征提取的要求不同,也可能会影响通道数的设置,但一般都会遵循通道数逐渐增加的原则。
完整代码
"""
文件名: 7.2 使用块的网络(VGG)
作者: 墨尘
日期: 2025/7/13
项目名: dl_env
备注: 实现VGG网络的核心思想——通过"块结构"堆叠卷积层,展示模块化设计在深度学习中的应用
"""
# 导入必要库
import torch # PyTorch核心库
from torch import nn # 神经网络模块
from d2l import torch as d2l # d2l库,提供数据加载、训练等工具函数
# 手动显示图像相关库
import matplotlib.pyplot as plt # 绘图库
import matplotlib.text as text # 用于修改文本绘制(解决符号显示问题)# -------------------------- 核心解决方案:解决文本显示问题 --------------------------
# 定义替换函数:将Unicode减号(U+2212,可能导致显示异常)替换为普通减号(-)
def replace_minus(s):if isinstance(s, str): # 判断输入是否为字符串return s.replace('\u2212', '-') # 替换特殊减号为普通减号return s # 非字符串直接返回# 重写matplotlib的Text类的set_text方法,解决减号显示异常
original_set_text = text.Text.set_text # 保存原始的set_text方法
def new_set_text(self, s):s = replace_minus(s) # 调用替换函数处理文本中的减号return original_set_text(self, s) # 调用原始方法设置文本
text.Text.set_text = new_set_text # 应用重写后的方法# -------------------------- 字体配置(确保中文和数学符号正常显示)--------------------------
plt.rcParams["font.family"] = ["SimHei"] # 设置中文字体(支持中文显示)
plt.rcParams["text.usetex"] = True # 使用LaTeX渲染文本(提升数学符号显示效果)
plt.rcParams["axes.unicode_minus"] = True # 确保负号正确显示(避免显示为方块)
plt.rcParams["mathtext.fontset"] = "cm" # 设置数学符号字体为Computer Modern(更美观)
d2l.plt.rcParams.update(plt.rcParams) # 让d2l库的绘图工具继承上述字体配置# -------------------------- VGG网络核心组件:块结构定义 --------------------------
def vgg_block(num_convs, in_channels, out_channels):"""定义VGG中的一个"块"(Block)每个块由多个3x3卷积层 + 1个最大池化层组成(VGG的核心设计)参数:num_convs: 块内卷积层的数量(如2表示该块包含2个卷积层)in_channels: 输入特征图的通道数out_channels: 输出特征图的通道数(所有卷积层共享该输出通道数)返回:一个Sequential容器,包含该块的所有层"""layers = [] # 存储块内的层for _ in range(num_convs):# 添加3x3卷积层:VGG的标志性设计(小卷积核堆叠增强特征提取能力)# padding=1保证卷积后特征图尺寸不变(输入HxW → 输出HxW)layers.append(nn.Conv2d(in_channels=in_channels,out_channels=out_channels,kernel_size=3, # 固定3x3卷积核(VGG的核心特点)padding=1 # 填充1像素,保持尺寸))layers.append(nn.ReLU()) # 卷积后接ReLU激活函数,增强非线性表达in_channels = out_channels # 下一层卷积的输入通道数 = 当前输出通道数# 块的最后添加2x2最大池化层:将特征图尺寸减半(HxW → H/2 x W/2),降低计算量layers.append(nn.MaxPool2d(kernel_size=2, stride=2)) # 步长2实现尺寸减半return nn.Sequential(*layers) # 用Sequential包装层,形成一个块# -------------------------- 构建完整VGG网络 --------------------------
def vgg(conv_arch):"""基于块结构构建完整的VGG网络参数:conv_arch: 列表,每个元素为元组(num_convs, out_channels),定义每个块的配置返回:完整的VGG网络(Sequential容器)"""conv_blks = [] # 存储所有卷积块in_channels = 1 # 输入图像的通道数(这里默认处理灰度图,如Fashion-MNIST)# 1. 构建卷积层部分:堆叠多个vgg_blockfor (num_convs, out_channels) in conv_arch:# 添加一个VGG块,更新输入通道数conv_blks.append(vgg_block(num_convs, in_channels, out_channels))in_channels = out_channels # 下一个块的输入通道 = 当前块的输出通道# 2. 构建全连接层部分:VGG的分类头# 注意:全连接层前需将特征图展平为向量return nn.Sequential(*conv_blks, # 卷积块部分nn.Flatten(), # 展平特征图(N, C, H, W → N, C*H*W)# 全连接层1:4096维(VGG的经典设计,大维度增强拟合能力)nn.Linear(out_channels * 7 * 7, 4096), # 输入尺寸=最后一个卷积块的输出(512x7x7)nn.ReLU(),nn.Dropout(0.5), # Dropout=0.5防止过拟合(随机丢弃50%神经元)# 全连接层2:4096维nn.Linear(4096, 4096),nn.ReLU(),nn.Dropout(0.5),# 输出层:10类(对应Fashion-MNIST数据集)nn.Linear(4096, 10))# -------------------------- 主函数:测试网络结构与训练 --------------------------
if __name__ == '__main__':# 1. 定义VGG的卷积块配置(原始VGG11的简化版)# 每个元组为(num_convs, out_channels):表示每个块的卷积层数量和输出通道数conv_arch = ((1, 64), # 第1块:1个卷积层,输出64通道(1, 128), # 第2块:1个卷积层,输出128通道(2, 256), # 第3块:2个卷积层,输出256通道(2, 512), # 第4块:2个卷积层,输出512通道(2, 512) # 第5块:2个卷积层,输出512通道) # 总卷积层数量=1+1+2+2+2=8,全连接层3层,共11层(对应VGG11)# 2. 测试网络各层输出形状(验证网络结构正确性)net = vgg(conv_arch) # 实例化VGG网络X = torch.randn(size=(1, 1, 224, 224)) # 随机输入(批量大小1,1通道,224x224尺寸)for blk in net: # 遍历网络的每一层/块X = blk(X) # 前向传播# 打印当前层的类名和输出形状(验证尺寸变化是否符合预期)print(blk.__class__.__name__, 'output shape:\t', X.shape)# 3. 简化网络(降低计算量,适合在普通设备上训练)ratio = 4 # 通道数缩减比例(原始VGG参数太多,缩小4倍)small_conv_arch = [(pair[0], pair[1] // ratio) for pair in conv_arch] # 缩减通道数net = vgg(small_conv_arch) # 使用简化后的配置构建网络# 4. 训练参数设置lr = 0.05 # 学习率num_epochs = 10 # 训练轮数batch_size = 128 # 批次大小# 5. 加载数据集(Fashion-MNIST)# 注意:VGG输入为224x224,需将原始28x28的MNIST图像resize到224x224train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)# 6. 训练网络# d2l.train_ch6:d2l库提供的训练函数,自动处理前向传播、反向传播、精度计算等d2l.train_ch6(net, # 模型train_iter, # 训练数据集test_iter, # 测试数据集num_epochs, # 训练轮数lr, # 学习率d2l.try_gpu() # 尝试使用GPU训练(加速训练))# 7. 显示训练过程中的图像(如损失曲线、精度曲线)plt.show(block=True) # block=True:保持图像窗口打开,直到手动关闭