本文基于d2l项目内容整理,介绍VGG网络的设计理念和实现方法,重点阐述块结构在深度卷积神经网络中的重要作用。

1. VGG 网络的设计理念

AlexNet 首次证明了模型能自动学习特征的能力,但这一突破并没有为后续的研究提供用于构建新网络的模板。

CNN基本结构的认识:

AlexNet 的积极意义之一是意识到了卷积神经网络的基本结构由带填充以保持分辨率的卷积层、ReLU 等非线性激活函数,以及池化层组成。随着深度学习网络设计模式的发展,这种网络基本结构能在更大的尺度上复用,而使研究者的视角从”神经元”到”层”,又逐步转向”块”。

VGG 网络的创新意义:

2015年,牛津大学视觉几何组 (Visual Geometry Group, VGG) 首次提出了一种以 VGG16 和 VGG19 闻名,使用块的深度卷积神经网络架构,改善了在神经网络中难以使用重复结构的现状。

VGG 网络中的每个块由一系列被激活函数处理的卷积层和一个池化层组成,更小的卷积核可以捕获更多特征,有助于形成更深的网络,结构简单而统一,且性能优越。


2. VGG 网络架构

2.1 VGG 块设计

VGG 块是VGG网络的核心构建单元,具有统一而简洁的设计模式:

VGG 块的基本形式:

由两层使用 ReLU 激活函数的 3×3 填充为 1 的卷积层,后接一个 2×2 步幅为 2 的最大池化层组成。可以在卷积时保持宽高、在池化时宽高分辨率减半。

VGG 块的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import torch
from torch import Tensor, nn

class VGGBlock(nn.Module):
"""
VGG 块

由两层使用 ReLU 激活函数的 3×3 卷积层,后接一个 2×2 步幅为 2 的最大池化层组成
"""

def __init__(self, in_channels: int, out_channels: int):
super(VGGBlock, self).__init__()
self.block = nn.Sequential(
# 第一个3×3卷积层
nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1),
nn.ReLU(inplace=True),

# 第二个3×3卷积层
nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1),
nn.ReLU(inplace=True),

# 2×2最大池化层
nn.MaxPool2d(kernel_size=2, stride=2)
)

def forward(self, x: Tensor) -> Tensor:
return self.block(x)

VGG块的设计优势:

  • 统一的3×3卷积核:相比大卷积核,多个小卷积核能够捕获更复杂的特征
  • 保持空间分辨率:padding=1确保卷积操作不改变特征图尺寸
  • 规律的降采样:每个块通过池化层将特征图尺寸减半
  • 模块化设计:可以轻松堆叠多个VGG块构建更深的网络

2.2 完整的 VGG11 网络

与 AlexNet、LeNet 类似,VGG 网络同样由卷积层、汇聚层组成的特征提取模块和由全连接层组成的分类模块组成。

VGG11 网络实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class VGG11(nn.Module):
"""VGG11 网络实现"""

def __init__(self, num_classes: int = 10):
super(VGG11, self).__init__()

# 特征提取器 - 由5个VGG块组成
self.features = nn.Sequential(
VGGBlock(1, 16), # 输入: 224×224×1 -> 输出: 112×112×16
VGGBlock(16, 32), # 输入: 112×112×16 -> 输出: 56×56×32
VGGBlock(32, 64), # 输入: 56×56×32 -> 输出: 28×28×64
VGGBlock(64, 128), # 输入: 28×28×64 -> 输出: 14×14×128
VGGBlock(128, 128), # 输入: 14×14×128 -> 输出: 7×7×128
)

# 分类器 - 由全连接层组成
self.classifier = nn.Sequential(
nn.Dropout(0.5),
nn.Linear(7 * 7 * 128, 4096),
nn.ReLU(inplace=True),

nn.Dropout(0.5),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),

nn.Linear(4096, num_classes)
)

def forward(self, x: Tensor) -> Tensor:
# 特征提取
x = self.features(x)

# 展平特征图
x = torch.flatten(x, 1)

# 分类
x = self.classifier(x)

return x
VGG网络架构示意图
VGG网络架构示意图

VGG11 网络结构特点:

  • 5个VGG块:输出通道数从16逐层翻倍至128
  • 特征图尺寸变化:224×224 → 112×112 → 56×56 → 28×28 → 14×14 → 7×7
  • 分类器设计:3个全连接层(6272→4096→4096→10)
  • 正则化技术:使用Dropout防止过拟合

2.3 网络结构分析

使用 torchinfo 库的 summary 函数来详细分析网络结构:

1
2
3
4
5
from torchinfo import summary

# 创建模型并分析
model = VGG11(num_classes=10)
summary(model, input_size=(1, 1, 224, 224))
查看详细网络结构信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
==========================================================================================
Layer (type:depth-idx) Output Shape Param #
==========================================================================================
VGG11 [1, 10] --
├─Sequential: 1-1 [1, 128, 7, 7] --
│ └─VGGBlock: 2-1 [1, 16, 112, 112] --
│ │ └─Sequential: 3-1 [1, 16, 112, 112] 2,480
│ └─VGGBlock: 2-2 [1, 32, 56, 56] --
│ │ └─Sequential: 3-2 [1, 32, 56, 56] 13,888
│ └─VGGBlock: 2-3 [1, 64, 28, 28] --
│ │ └─Sequential: 3-3 [1, 64, 28, 28] 55,424
│ └─VGGBlock: 2-4 [1, 128, 14, 14] --
│ │ └─Sequential: 3-4 [1, 128, 14, 14] 221,440
│ └─VGGBlock: 2-5 [1, 128, 7, 7] --
│ │ └─Sequential: 3-5 [1, 128, 7, 7] 295,168
├─Sequential: 1-2 [1, 10] --
│ └─Dropout: 2-6 [1, 6272] --
│ └─Linear: 2-7 [1, 4096] 25,694,208
│ └─ReLU: 2-8 [1, 4096] --
│ └─Dropout: 2-9 [1, 4096] --
│ └─Linear: 2-10 [1, 4096] 16,781,312
│ └─ReLU: 2-11 [1, 4096] --
│ └─Linear: 2-12 [1, 10] 40,970
==========================================================================================
Total params: 43,104,890
Trainable params: 43,104,890
Non-trainable params: 0
Total mult-adds (Units.MEGABYTES): 746.44
==========================================================================================
Input size (MB): 0.20
Forward/backward pass size (MB): 24.55
Params size (MB): 172.42
Estimated Total Size (MB): 197.17
==========================================================================================

网络参数分析:

  • 总参数量:约4310万个参数,其中绝大部分来自全连接层
  • 特征提取器:约59万个参数(仅占1.4%)
  • 分类器:约4250万个参数(占98.6%)
  • 内存占用:约197MB的总估算大小

可以看出,每个 VGGBlock 使特征图宽高逐步减半至 7×7,展平后在全连接层映射到 10 种类别。全连接层的参数数量远超卷积层,这也是VGG网络参数量巨大的主要原因。


3. 模型训练与评估

3.1 训练配置

继续使用 training_tools.py 中的工具来训练和评估VGG11模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import torch
from torch import nn, optim
from training_tools import fashionMNIST_loader, Trainer

def train_vgg11():
"""训练VGG11模型"""
# 超参数设置
BATCH_SIZE = 128
EPOCHS = 15 # 减少训练轮数用于演示
LEARNING_RATE = 0.005 # 降低学习率以获得更稳定的训练

# 创建模型和数据加载器
model = VGG11(num_classes=10)
train_loader, test_loader = fashionMNIST_loader(BATCH_SIZE, resize=224)

# 损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE, weight_decay=1e-4)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

print(f"使用设备: {device}")
print(f"模型参数数量: {sum(p.numel() for p in model.parameters()):,}")

# 开始训练
with Trainer(model, train_loader, test_loader, criterion, optimizer, device) as trainer:
trainer.train(EPOCHS)

if __name__ == '__main__':
train_vgg11()

3.2 训练结果分析

查看训练过程详细输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
使用设备: cuda
模型参数数量: 43,104,890

Epoch [ 1/15] Train Loss: 2.3027, Train Acc: 9.90%, Test Loss: 2.3026, Test Acc: 10.00%
Epoch [ 2/15] Train Loss: 2.3028, Train Acc: 9.85%, Test Loss: 2.3027, Test Acc: 10.00%
...
Epoch [ 12/15] Train Loss: 2.3027, Train Acc: 9.88%, Test Loss: 2.3025, Test Acc: 10.00%
Epoch [ 13/15] Train Loss: 2.3025, Train Acc: 10.22%, Test Loss: 2.3021, Test Acc: 10.00%
Epoch [ 14/15] Train Loss: 2.2864, Train Acc: 17.02%, Test Loss: 2.3021, Test Acc: 10.00%
Epoch [ 15/15] Train Loss: 1.6031, Train Acc: 38.25%, Test Loss: 0.6503, Test Acc: 74.66%

# 继续训练会看到快速提升:
Epoch [ 16/30] Train Loss: 0.5281, Train Acc: 80.15%, Test Loss: 0.4621, Test Acc: 83.29%
Epoch [ 20/30] Train Loss: 0.2704, Train Acc: 90.00%, Test Loss: 0.2714, Test Acc: 90.12%
Epoch [ 30/30] Train Loss: 0.1174, Train Acc: 95.60%, Test Loss: 0.2576, Test Acc: 92.31%
VGG11训练过程损失和准确率曲线
VGG11训练过程损失和准确率曲线

训练特点分析

训练过程的三个阶段:

  • 停滞期(1-12轮):模型几乎没有学习到有用的特征,准确率徘徊在10%左右
  • 突破期(13-21轮):模型开始学习有效特征,精度迅速提高
  • 稳定期(22-30轮):训练精度稳定在约95%左右,测试精度稳定在92%左右

训练初期停滞的原因:

  • 网络深度:VGG11相对较深,梯度传播困难
  • 学习率设置:可能初始学习率不够合适
  • 权重初始化:深层网络对初始化更加敏感
  • 优化器选择:SGD相比Adam在深层网络上收敛较慢

改善训练的策略:

降低学习率并使用学习率衰减策略

使用Xavier或He权重初始化

采用Adam等自适应优化器

添加批归一化层加速收敛

使用预训练权重进行迁移学习

VGG网络的训练特点:

VGG网络由于其较深的结构和大量的参数,在训练初期容易出现梯度消失问题,导致学习停滞。但一旦突破瓶颈,模型能够快速收敛并达到较好的性能。这种训练特点在早期的深度网络中比较常见,后来通过批归一化、残差连接等技术得到了很好的解决。


总结

本文介绍了VGG网络的核心设计理念和实现方法:

  1. 模块化设计:VGG块作为基本构建单元,使网络设计更加模块化和可复用
  2. 统一的架构:使用统一的3×3卷积核和2×2池化,设计简洁而有效
  3. 深度网络:通过堆叠VGG块构建更深的网络,提高特征表示能力
  4. 训练特点:深层网络训练需要合适的优化策略和技巧

VGG网络的成功证明了”简单而深入”的设计理念的有效性,其模块化的设计思想也为后续的网络架构设计提供了重要启发,是深度学习发展史上的又一重要里程碑。