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

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%
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%
3. 性能对比与总结
性能对比分析
两种实现方式的性能对比:
批量归一化在LeNet中的作用机制:
- 解决内部协变量偏移问题
- 支持更大的学习率设置
- 加速训练收敛过程
- 提高模型的训练稳定性
- 在一定程度上起到正则化作用
实际应用中的选择建议:
参考资料
如果这篇记录对你有帮助,可以留下一句回应。

DISCUSSION
讨论与回应
欢迎补充细节、指出问题,或分享与这篇文章有关的经验。
昵称与邮箱为必填项,邮箱仅用于头像和回复通知,不会公开。网址可以留空。