共计 2265 个字符,预计需要花费 6 分钟才能阅读完成。
背景介绍
卷积神经网络(CNN)是计算机视觉领域的基石技术,从图像分类到目标检测,CNN 在多个任务上展现出强大的特征提取能力。对于初学者而言,理解并实现经典 CNN 模型是掌握深度学习的重要一步。AlexNet 和 LeNet 作为 CNN 发展历程中的两个里程碑模型,分别代表了不同时期的技术突破。本文将带您从零开始搭建这两个模型,并分享实战中的优化技巧。

模型对比:AlexNet 与 LeNet
- LeNet-5(1998 年)
- 首个成功应用于手写数字识别的 CNN
- 结构简单:2 个卷积层 + 3 个全连接层
- 使用 tanh 激活函数和平均池化
-
参数量约 60k,适合简单分类任务
-
AlexNet(2012 年)
- ImageNet 竞赛冠军,推动深度学习复兴
- 更深结构:5 个卷积层 + 3 个全连接层
- 引入 ReLU 激活、Dropout 和最大池化
-
使用 GPU 并行训练,参数量约 60M
-
适用场景选择
- LeNet:MNIST 等简单图像分类
- AlexNet:中等复杂度的图像分类任务
实战:PyTorch 实现
LeNet 实现
import torch
import torch.nn as nn
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
self.conv1 = nn.Conv2d(1, 6, 5) # 输入 1 通道,输出 6 通道,5x5 卷积核
self.pool = nn.AvgPool2d(2, 2) # 2x2 平均池化
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16*4*4, 120) # 全连接层
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(torch.tanh(self.conv1(x)))
x = self.pool(torch.tanh(self.conv2(x)))
x = x.view(-1, 16*4*4) # 展平
x = torch.tanh(self.fc1(x))
x = torch.tanh(self.fc2(x))
x = self.fc3(x)
return x
AlexNet 实现(简化版)
class AlexNet(nn.Module):
def __init__(self, num_classes=1000):
super(AlexNet, self).__init__()
self.features = nn.Sequential(nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Conv2d(64, 192, kernel_size=5, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
# 中间层省略...
)
self.classifier = nn.Sequential(nn.Dropout(),
nn.Linear(256*6*6, 4096),
nn.ReLU(inplace=True),
nn.Dropout(),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),
nn.Linear(4096, num_classes),
)
def forward(self, x):
x = self.features(x)
x = torch.flatten(x, 1)
x = self.classifier(x)
return x
性能优化技巧
- 学习率调整
-
使用学习率衰减策略:
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1) -
正则化方法
- L2 正则化(权重衰减):
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, weight_decay=1e-4) -
Dropout 层防止过拟合
-
GPU 加速
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") model = model.to(device)
常见问题解决方案
- 梯度消失
- 使用 ReLU 等非饱和激活函数
-
添加 BatchNorm 层
-
过拟合
- 增加数据增强
transform_train = transforms.Compose([transforms.RandomHorizontalFlip(), transforms.RandomRotation(10), transforms.ToTensor(),]) -
早停法(Early Stopping)
-
训练震荡
- 使用更大的 batch size
- 尝试不同的优化器(如 Adam)
延伸思考
- 模型结构调整方向
- 对于小数据集:减少卷积核数量 / 全连接层神经元
-
对于高分辨率图像:增加卷积层深度
-
现代改进技巧
- 将全连接层替换为全局平均池化
-
添加残差连接
-
部署优化
- 使用 ONNX 格式导出模型
- 量化为 INT8 减少推理耗时
结语
通过本文的实践,我们不仅实现了两个经典 CNN 模型,更重要的是理解了模型设计背后的思想。建议读者在 MNIST 和 CIFAR-10 数据集上分别尝试这两个模型,观察它们在简单和中等复杂度任务上的表现差异。在实际项目中,通常需要根据数据规模和计算资源,在模型复杂度和性能之间找到平衡点。
正文完
发表至: 未分类
近一天内
