卷积神经网络(LeNet)

探索首个成功的卷积神经网络LeNet,了解其历史地位和网络架构设计,掌握早期CNN的实现原理

发布于 2025-08-09 更新于 2025-08-092,206 字 5 分钟
卷积神经网络(LeNet)的文章封面
展开文章目录
  1. 1. LeNet 的历史地位
  2. 2. 网络架构设计
  3. 2.1 架构组成
  4. 2.2 PyTorch 实现
  5. 2.3 网络结构分析
  6. 3. 模型训练与评估
  7. 3.1 训练环境配置
  8. 3.2 训练代码实现
  9. 3.3 训练结果分析
  10. 4. 历史回顾与发展
  11. 4.1 技术发展的两条路径
  12. 4.2 技术发展的瓶颈
  13. 4.3 ImageNet的推动作用
  14. 参考资料

1. LeNet 的历史地位

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


2. 网络架构设计

LeNet网络架构图

2.1 架构组成

LeNet详细架构示意图

2.2 PyTorch 实现

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

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

2.3 网络结构分析

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

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()
查看输出结果
输入形状: 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. 模型训练与评估

3.1 训练环境配置

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

tensorboard --logdir ./runs

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

3.2 训练代码实现

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

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()

3.3 训练结果分析

查看训练过程详细输出
使用设备: 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训练分析

训练收敛特点:

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

LeNet的优势表现:

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

早期CNN的特色:

  • 使用Sigmoid激活函数而非现代的ReLU
  • 采用平均池化而非最大池化
  • 全连接层参数量占主导地位
  • 整体网络深度相对较浅

4. 历史回顾与发展

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

4.1 技术发展的两条路径

技术路径对比

传统机器学习方法:

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

深度学习理念:

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

4.2 技术发展的瓶颈

4.3 ImageNet的推动作用

深度学习发展时间线
  • 1989年:Yann LeCun提出LeNet,首个成功的CNN
  • 1990s-2012年:深度学习进入”寒冬期”,SVM等方法占主导
  • 2012年:AlexNet在ImageNet挑战赛中取得突破性成果
  • 2012年后:深度学习迎来快速发展期

参考资料

如果这篇记录对你有帮助,可以留下一句回应。

前往留言

DISCUSSION

讨论与回应

欢迎补充细节、指出问题,或分享与这篇文章有关的经验。

昵称与邮箱为必填项,邮箱仅用于头像和回复通知,不会公开。网址可以留空。

正在准备留言区…

演示赞赏界面

谢谢你愿意支持长期写作。

第一阶段不会发起支付或收集任何信息。接入真实赞赏渠道后,这里会展示清楚的金额、渠道和完成状态。

输入关键词开始搜索 · 按 Esc 关闭
打开完整搜索页 →