本文基于d2l项目内容整理,介绍深度学习历史上的首个成功卷积神经网络LeNet,包括其历史背景、网络架构设计和实现方法。

1. LeNet 的历史地位

我们已经学完了神经网络中的基本组件。现在,我们可以尝试不再展平 Fashion-MNIST 数据集中的图像,而保留空间结构特征,进行模型训练和服装分类。

LeNet 的开创性意义:

由 AT&T 贝尔实验室研究员 Yann LeCun 于 1989 年提出的 LeNet 作为最早的卷积神经网络,在计算机视觉(手写数字识别)任务中表现出了高效的性能。Yann LeCun 发表的文章作为第一篇通过反向传播成功训练神经网络的见证,具有与支持向量机 (SVM) 类似的性能,成为了监督学习的主流方法。


2. 网络架构设计

LeNet网络架构图
LeNet网络架构图

2.1 架构组成

LeNet-5 的核心结构:

LeNet-5 由两个特征提取器和三个分类器组成:

  • 特征提取器:每个包含一个用于提取输入图像的局部特征的卷积层和一个用于下采样、提高变形鲁棒性的平均池化层
  • 分类器:每个都是一个全连接层,用于整合特征提取器生成的高维特征,并降维映射到具体的输出类别

时代特色的设计选择:
虽然 ReLU 函数和最大池化层在现代网络中更高效,但在 LeNet 提出的年代,每个卷积层或全连接层都选择使用 Sigmoid 函数激活。这体现了早期深度学习的技术特点和时代局限性。

LeNet详细架构示意图
LeNet详细架构示意图

2.2 PyTorch 实现

LeNet 的网络架构用 PyTorch 框架实现如下(去掉了最后一个全连接层的高斯激活函数):

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
import torch
from torch import nn, Tensor

class LeNet(nn.Module):
def __init__(self, num_classes=10):
super(LeNet, self).__init__()

# 特征提取器
self.features = nn.Sequential(
# 第一层:卷积 + Sigmoid + 池化
nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, padding=2),
nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2),

# 第二层:卷积 + Sigmoid + 池化
nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5),
nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2),
)

# 分类器
self.classifier = nn.Sequential(
nn.Flatten(),
nn.Linear(in_features=16 * 5 * 5, out_features=120),
nn.Sigmoid(),
nn.Linear(in_features=120, out_features=84),
nn.Sigmoid(),
nn.Linear(in_features=84, out_features=num_classes)
)

def forward(self, x: Tensor) -> Tensor:
x = self.features(x)
x = self.classifier(x)
return x

架构特点分析:

  • 特征图变化:每经过一次卷积层,特征图的高度和宽度都减小,而通道不断增加
  • 池化作用:池化层在保持通道不变的情况下进一步减半特征图的尺寸
  • 分类决策:将特征降维展平后,使用全连接层输出各个结果的概率
  • 维度流向:28×28×1 → 14×14×6 → 5×5×16 → 400 → 120 → 84 → 10

2.3 网络结构分析

为了方便理解各层的输出维度变化,可以用以下方式测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def test_lenet_architecture():
"""测试LeNet各层的输出维度"""
model = LeNet(num_classes=10)
test_input = torch.randn(1, 1, 28, 28)

print(f"输入形状: {test_input.shape}")
print("\n=== 特征提取部分 ===")

x = test_input
for i, layer in enumerate(model.features):
x = layer(x)
print(f"{type(layer).__name__} 输出形状: {tuple(x.shape)}")

print("\n=== 分类器部分 ===")
for i, layer in enumerate(model.classifier):
x = layer(x)
print(f"{type(layer).__name__} 输出形状: {tuple(x.shape)}")

# 运行测试
test_lenet_architecture()
查看输出结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
输入形状: torch.Size([1, 1, 28, 28])

=== 特征提取部分 ===
Conv2d 输出形状: (1, 6, 28, 28)
Sigmoid 输出形状: (1, 6, 28, 28)
AvgPool2d 输出形状: (1, 6, 14, 14)
Conv2d 输出形状: (1, 16, 10, 10)
Sigmoid 输出形状: (1, 16, 10, 10)
AvgPool2d 输出形状: (1, 16, 5, 5)

=== 分类器部分 ===
Flatten 输出形状: (1, 400)
Linear 输出形状: (1, 120)
Sigmoid 输出形状: (1, 120)
Linear 输出形状: (1, 84)
Sigmoid 输出形状: (1, 84)
Linear 输出形状: (1, 10)

3. 模型训练与评估

计算复杂度特点:

与 MLP 相比,虽然卷积神经网络具有更少的参数,但互相关运算往往需要更多的计算资源。因此我们继续使用 Fashion-MNIST 数据集,在 GPU 上训练 LeNet 模型。

3.1 训练环境配置

使用 TensorBoard 执行可视化,启用 TensorBoard 后端:

1
tensorboard --logdir ./runs

然后在浏览器中访问 http://localhost:6006/ 查看训练过程。

3.2 训练代码实现

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

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_lenet():
"""训练LeNet模型"""
# 超参数设置
BATCH_SIZE = 256
EPOCHS = 15 # 减少训练轮数用于演示
LEARNING_RATE = 0.3

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

# 损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=LEARNING_RATE)
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_lenet()

参数初始化说明:
这里使用默认方法初始化模型参数。在实际应用中,可能需要使用 Xavier 均匀分布初始化等更适合的参数初始化方法来获得更好的训练效果。

3.3 训练结果分析

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

Epoch [ 1/15] Train Loss: 2.3105, Train Acc: 10.09%, Test Loss: 2.3149, Test Acc: 10.00%
Epoch [ 2/15] Train Loss: 2.2823, Train Acc: 13.79%, Test Loss: 2.1649, Test Acc: 24.98%
Epoch [ 3/15] Train Loss: 1.5717, Train Acc: 42.73%, Test Loss: 1.2325, Test Acc: 50.35%
Epoch [ 4/15] Train Loss: 1.1198, Train Acc: 56.12%, Test Loss: 1.0465, Test Acc: 58.59%
Epoch [ 5/15] Train Loss: 0.9639, Train Acc: 62.85%, Test Loss: 0.9262, Test Acc: 66.43%
Epoch [ 6/15] Train Loss: 0.8491, Train Acc: 68.36%, Test Loss: 0.8217, Test Acc: 70.62%
Epoch [ 7/15] Train Loss: 0.7814, Train Acc: 70.95%, Test Loss: 0.8526, Test Acc: 67.93%
Epoch [ 8/15] Train Loss: 0.7304, Train Acc: 72.75%, Test Loss: 0.7113, Test Acc: 73.10%
Epoch [ 9/15] Train Loss: 0.6906, Train Acc: 73.90%, Test Loss: 0.7325, Test Acc: 72.51%
Epoch [ 10/15] Train Loss: 0.6545, Train Acc: 74.81%, Test Loss: 0.6730, Test Acc: 73.23%
...
Epoch [ 15/15] Train Loss: 0.6025, Train Acc: 76.48%, Test Loss: 0.6369, Test Acc: 76.09%

# 继续训练会看到最终收敛效果:
Epoch [100/200] Train Loss: 0.2545, Train Acc: 90.52%, Test Loss: 0.3077, Test Acc: 88.67%
Epoch [200/200] Train Loss: 0.1785, Train Acc: 93.33%, Test Loss: 0.2551, Test Acc: 91.06%
LeNet训练过程TensorBoard可视化
LeNet训练过程TensorBoard可视化

训练特点分析

训练收敛特点:

  • 快速起步:前几轮训练准确率迅速从10%提升至70%以上
  • 稳定提升:中期训练过程中准确率稳步上升
  • 最终性能:200轮后训练准确率达93.33%,测试准确率达91.06%

LeNet的优势表现:

  • 参数效率:仅6万多个参数就能达到91%的测试准确率
  • 结构简洁:网络结构清晰,易于理解和实现
  • 稳定训练:使用SGD优化器也能获得稳定的训练效果

早期CNN的特色:

使用Sigmoid激活函数而非现代的ReLU

采用平均池化而非最大池化

全连接层参数量占主导地位

整体网络深度相对较浅

训练效果评估:

  • 收敛速度:LeNet在Fashion-MNIST上展现出良好的收敛特性
  • 泛化能力:测试准确率达到91%,展现出不错的泛化性能
  • 历史价值:作为早期CNN,其设计思想影响了后续网络架构的发展
  • 参数规模:相比现代网络,LeNet参数量很少,计算效率高

4. 历史回顾与发展

即使是首个通过反向传播成功训练的 LeNet 提出,也并没有使卷积神经网络成为图像识别分类领域的主导。因为,LeNet 在更大、更真实的数据集上取得的突破并不比传统方法显著。

4.1 技术发展的两条路径

传统机器学习方法:

  • 手工特征设计:输入都需要从像素开始的手工精心特征设计
  • 领域知识:来自光学、几何学等领域的专业知识指导特征提取
  • 特征提取技术:SIFT、SURF、HOG等手工设计的特征描述子
  • 算法优化:越有巧思的特征提取,就会产生性能更好的机器学习算法

深度学习理念:

  • 端到端学习:模型应该自动学习数据特征,无需手工设计
  • 简单预处理:仅在预处理阶段进行简单的居中、缩放操作
  • 原始数据:直接使用原始像素值训练,让网络自己学习特征
  • 自动特征:通过多层网络自动提取从低级到高级的特征表示

4.2 技术发展的瓶颈

LeNet时代的技术限制:

当时的深度学习技术赖以实践的关键要素仍处于萌芽阶段:

  • 计算平台:高性能GPU计算尚未普及
  • 数据集:缺乏大规模、高质量的标注数据集
  • 参数初始化:启发式参数初始化方法还不成熟
  • 优化技术:随机梯度下降等优化技术有待完善
  • 激活函数:非饱和激活函数(如ReLU)尚未提出
  • 正则化技术:有效的正则化方法还在发展中

4.3 ImageNet的推动作用

ImageNet数据集的重要意义:

ImageNet 为深度学习的发展提供了一个大规模视觉数据库:

  • 数据规模:超过1,400万张有人工标注、提供边界框信息的图像
  • 类别丰富:涵盖1,000个不同类别
  • 挑战赛:2010年起每年举办ILSVRC挑战赛,促进技术突破
  • 标准基准:为深度学习方法提供了统一的评估标准
深度学习发展时间线
  • 1989年:Yann LeCun提出LeNet,首个成功的CNN
  • 1990s-2012年:深度学习进入”寒冬期”,SVM等方法占主导
  • 2012年:AlexNet在ImageNet挑战赛中取得突破性成果
  • 2012年后:深度学习迎来快速发展期

发展瓶颈的原因:

这些技术限制使得20世纪90年代到2012年AlexNet提出前,神经网络方法长期被支持向量机(SVM)等机器学习方法超越。与以理论发展为增长点的机器学习不同,深度学习的模型性能依赖于更大、更干净的数据集。此时,稍微改进的特征提取方案将带来与传统机器学习相比更大的突破。


总结

本文介绍了深度学习历史上的首个成功卷积神经网络LeNet:

  1. 历史地位:作为第一个通过反向传播成功训练的CNN,开创了深度学习的先河
  2. 网络架构:简洁的”卷积+池化+全连接”结构,奠定了现代CNN的基础框架
  3. 训练特点:在Fashion-MNIST上能达到91%的测试准确率,展现出良好的学习能力
  4. 时代意义:虽然当时受到技术限制,但为后续深度学习的发展提供了重要启发

LeNet不仅在技术上具有开创性意义,更重要的是它证明了卷积神经网络的可行性,为整个深度学习领域的发展奠定了基础,是计算机视觉历史上不可忽视的重要里程碑。