使用批量归一化层的 LeNet

探索批量归一化在经典LeNet网络中的应用效果,对比自定义实现与PyTorch高级API的性能差异

发布于 2025-08-10 更新于 2025-08-10801 字 2 分钟
使用批量归一化层的 LeNet的文章封面
展开文章目录
  1. 1. 使用自定义的批量归一化实现
  2. 1.1 网络架构设计
  3. 1.2 训练结果分析
  4. 2. 使用PyTorch高级API实现
  5. 2.1 高级API的优势
  6. 2.2 训练结果分析
  7. 3. 性能对比与总结
  8. 参考资料

1. 使用自定义的批量归一化实现

1.1 网络架构设计

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

import torch
from torch import nn, optim, Tensor

from batch_norm import BatchNorm
from training_tools import fashionMNIST_loader, Trainer


class LeNetNorm(nn.Module):
    def __init__(self):
        super().__init__()
        self.model = nn.Sequential(
            nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, padding=2), BatchNorm(6), nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),

            nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5), BatchNorm(16), nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),

            nn.Flatten(),
            nn.Linear(in_features=16 * 5 * 5, out_features=120), BatchNorm(120), nn.Sigmoid(),
            nn.Linear(in_features=120, out_features=84), BatchNorm(84), nn.Sigmoid(),
            nn.Linear(in_features=84, out_features=10)
        )

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


if __name__ == '__main__':
    BATCH_SIZE = 256
    EPOCHS_NUM = 20
    LEARNING_RATE = 0.9

    model = LeNetNorm()
    train_loader, test_loader = fashionMNIST_loader(BATCH_SIZE)
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.SGD(model.parameters(), LEARNING_RATE)
    platform = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

    with Trainer(model, train_loader, test_loader, criterion, optimizer, platform) as trainer:
        trainer.train(EPOCHS_NUM)

1.2 训练结果分析

查看自定义BatchNorm训练过程
第 001/20 轮,训练损失:0.7467,训练精度:72.63%,测试损失:0.5786,测试精度:78.79%
第 002/20 轮,训练损失:0.4560,训练精度:83.42%,测试损失:0.5931,测试精度:78.64%
第 003/20 轮,训练损失:0.3935,训练精度:85.69%,测试损失:0.5317,测试精度:79.71%
第 004/20 轮,训练损失:0.3534,训练精度:87.09%,测试损失:0.4948,测试精度:82.67%
第 005/20 轮,训练损失:0.3278,训练精度:87.98%,测试损失:0.5338,测试精度:79.72%
第 006/20 轮,训练损失:0.3067,训练精度:88.77%,测试损失:0.5119,测试精度:80.34%
第 007/20 轮,训练损失:0.2965,训练精度:89.02%,测试损失:0.5917,测试精度:79.18%
第 008/20 轮,训练损失:0.2863,训练精度:89.48%,测试损失:0.5458,测试精度:80.29%
第 009/20 轮,训练损失:0.2719,训练精度:89.94%,测试损失:0.3808,测试精度:86.62%
第 010/20 轮,训练损失:0.2598,训练精度:90.37%,测试损失:0.3530,测试精度:87.19%
第 011/20 轮,训练损失:0.2532,训练精度:90.56%,测试损失:0.4072,测试精度:86.18%
第 012/20 轮,训练损失:0.2463,训练精度:90.89%,测试损失:0.4431,测试精度:83.19%
第 013/20 轮,训练损失:0.2393,训练精度:91.09%,测试损失:0.3236,测试精度:88.37%
第 014/20 轮,训练损失:0.2312,训练精度:91.41%,测试损失:0.3809,测试精度:86.48%
第 015/20 轮,训练损失:0.2252,训练精度:91.61%,测试损失:0.5903,测试精度:80.33%
第 016/20 轮,训练损失:0.2201,训练精度:91.83%,测试损失:0.3459,测试精度:87.68%
第 017/20 轮,训练损失:0.2157,训练精度:91.94%,测试损失:0.3195,测试精度:88.70%
第 018/20 轮,训练损失:0.2097,训练精度:92.22%,测试损失:0.4688,测试精度:83.59%
第 019/20 轮,训练损失:0.2072,训练精度:92.27%,测试损失:0.3301,测试精度:88.55%
第 020/20 轮,训练损失:0.1993,训练精度:92.52%,测试损失:0.4786,测试精度:85.04%

自定义BatchNorm训练过程可视化


2. 使用PyTorch高级API实现

2.1 高级API的优势

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

import torch
from torch import nn, optim, Tensor

from torch.nn import BatchNorm1d, BatchNorm2d
from training_tools import fashionMNIST_loader, Trainer


class LeNetNorm(nn.Module):
    def __init__(self):
        super().__init__()
        self.model = nn.Sequential(
            nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, padding=2), BatchNorm2d(6), nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),

            nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5), BatchNorm2d(16), nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),

            nn.Flatten(),
            nn.Linear(in_features=16 * 5 * 5, out_features=120), BatchNorm1d(120), nn.Sigmoid(),
            nn.Linear(in_features=120, out_features=84), BatchNorm1d(84), nn.Sigmoid(),
            nn.Linear(in_features=84, out_features=10)
        )

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


if __name__ == '__main__':
    BATCH_SIZE = 256
    EPOCHS_NUM = 12
    LEARNING_RATE = 0.9

    model = LeNetNorm()
    train_loader, test_loader = fashionMNIST_loader(BATCH_SIZE)
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.SGD(model.parameters(), LEARNING_RATE)
    platform = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

    with Trainer(model, train_loader, test_loader, criterion, optimizer, platform) as trainer:
        trainer.train(EPOCHS_NUM)

2.2 训练结果分析

查看PyTorch高级API训练过程
第 001/20 轮,训练损失:0.7319,训练精度:73.59%,测试损失:0.5507,测试精度:79.77%
第 002/20 轮,训练损失:0.4581,训练精度:83.33%,测试损失:0.5434,测试精度:80.35%
第 003/20 轮,训练损失:0.3874,训练精度:86.01%,测试损失:0.4753,测试精度:82.32%
第 004/20 轮,训练损失:0.3445,训练精度:87.58%,测试损失:0.6090,测试精度:78.65%
第 005/20 轮,训练损失:0.3152,训练精度:88.48%,测试损失:0.5935,测试精度:77.56%
第 006/20 轮,训练损失:0.2993,训练精度:89.00%,测试损失:0.4295,测试精度:84.09%
第 007/20 轮,训练损失:0.2863,训练精度:89.49%,测试损失:0.4920,测试精度:83.13%
第 008/20 轮,训练损失:0.2702,训练精度:90.05%,测试损失:0.3630,测试精度:86.45%
第 009/20 轮,训练损失:0.2612,训练精度:90.37%,测试损失:0.3293,测试精度:88.18%
第 010/20 轮,训练损失:0.2516,训练精度:90.73%,测试损失:0.8095,测试精度:72.46%
第 011/20 轮,训练损失:0.2451,训练精度:90.92%,测试损失:0.3142,测试精度:88.69%
第 012/20 轮,训练损失:0.2333,训练精度:91.42%,测试损失:0.2834,测试精度:89.40%
第 013/20 轮,训练损失:0.2266,训练精度:91.52%,测试损失:0.3581,测试精度:86.73%
第 014/20 轮,训练损失:0.2222,训练精度:91.62%,测试损失:0.3546,测试精度:87.98%
第 015/20 轮,训练损失:0.2146,训练精度:92.02%,测试损失:0.3224,测试精度:89.06%
第 016/20 轮,训练损失:0.2088,训练精度:92.15%,测试损失:0.3792,测试精度:86.32%
第 017/20 轮,训练损失:0.2040,训练精度:92.38%,测试损失:0.3774,测试精度:86.00%
第 018/20 轮,训练损失:0.1987,训练精度:92.54%,测试损失:0.3286,测试精度:88.51%
第 019/20 轮,训练损失:0.1935,训练精度:92.78%,测试损失:0.3452,测试精度:87.89%
第 020/20 轮,训练损失:0.1880,训练精度:92.97%,测试损失:0.7534,测试精度:78.21%

PyTorch高级API训练过程可视化


3. 性能对比与总结

性能对比分析

两种实现方式的性能对比:

批量归一化在LeNet中的作用机制:

  • 解决内部协变量偏移问题
  • 支持更大的学习率设置
  • 加速训练收敛过程
  • 提高模型的训练稳定性
  • 在一定程度上起到正则化作用

实际应用中的选择建议:


参考资料

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

前往留言

DISCUSSION

讨论与回应

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

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

正在准备留言区…

演示赞赏界面

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

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

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