共计 2402 个字符,预计需要花费 7 分钟才能阅读完成。
核心概念
卷积神经网络 (CNN) 通过局部连接和权重共享高效处理图像数据。其核心组件工作原理如下:
-
卷积层:使用滑动窗口(卷积核)提取局部特征,计算公式为:
$$(f * g)(x,y) = \sum_{i=-k}^{k}\sum_{j=-k}^{k} f(x+i,y+j)g(i,j)$$
其中 $f$ 是输入,$g$ 是卷积核,$k$ 是核半径 -
池化层:降低特征图尺寸(常用最大池化),保留显著特征的同时减少计算量

实验设计
数据预处理
- 标准化 :将像素值从[0,255] 线性变换到[-1,1]
- 数据增强:
- 随机水平翻转(概率 0.5)
- 随机旋转(±15 度)
- 颜色抖动(亮度 / 对比度调整)
模型架构
采用经典 LeNet- 5 改进结构:
- 输入层 → Conv1(3@32×32 → 6@28×28)
- MaxPool(6@28×28 → 6@14×14)
- Conv2(6@14×14 → 16@10×10)
- MaxPool(16@10×10 → 16@5×5)
- 全连接层(400 → 120 → 84 → 10)
超参数配置
- 损失函数:交叉熵损失
- 优化器:Adam(lr=0.001)
- Batch Size:64
- Epochs:50
代码实现
import torch
import torchvision
import torch.nn as nn
import torch.optim as optim
from torchvision import transforms
# 数据预处理管道
transform = transforms.Compose([transforms.RandomHorizontalFlip(),
transforms.RandomRotation(15),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
# 加载 CIFAR-10 数据集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)
# 定义 CNN 模型
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
# 卷积层 1:输入 3 通道,输出 6 通道,5x5 卷积核
self.conv1 = nn.Conv2d(3, 6, 5)
# 池化层:2x2 窗口,步长 2
self.pool = nn.MaxPool2d(2, 2)
# 卷积层 2:输入 6 通道,输出 16 通道,5x5 卷积核
self.conv2 = nn.Conv2d(6, 16, 5)
# 全连接层
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(torch.relu(self.conv1(x)))
x = self.pool(torch.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
# 初始化模型、损失函数和优化器
model = CNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练循环
for epoch in range(50):
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
inputs, labels = data
# 梯度清零
optimizer.zero_grad()
# 前向传播 + 反向传播 + 优化
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# 打印统计信息
running_loss += loss.item()
if i % 200 == 199:
print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 200:.3f}')
running_loss = 0.0
结果分析
训练曲线
关键观察点:
1. 前 10 个 epoch 损失快速下降
2. 20-30epoch 出现验证集准确率平台期
3. 40epoch 后出现轻微过拟合(训练精度持续上升但验证精度停滞)
应对策略
- 早停机制:当验证损失连续 3 个 epoch 不下降时终止训练
- 增加 Dropout 层:在全连接层之间添加 dropout(p=0.5)
- L2 正则化:优化器添加 weight_decay 参数(建议 0.001)
避坑指南
- 学习率设置不当
- 现象:损失值震荡或下降缓慢
-
解决:使用学习率调度器(如 ReduceLROnPlateau)
-
批量归一化层缺失
- 现象:深层网络训练困难
-
解决:在卷积层后添加 nn.BatchNorm2d
-
数据未打乱
- 现象:模型收敛方向不稳定
- 解决:确保 DataLoader 的 shuffle=True
实验环境
- GPU:NVIDIA RTX 3060 (12GB)
- PyTorch:1.10.0+cu113
- Python:3.8.10
总结
通过本实验,我们完整实现了 CNN 从数据准备到模型训练的全流程。关键收获包括:
1. 理解卷积 / 池化层的实际运作方式
2. 掌握 PyTorch 构建模型的标准化流程
3. 学会分析训练曲线识别过拟合
建议下一步尝试:
– 使用 ResNet 等现代架构提升准确率
– 添加 TensorBoard 可视化工具
– 在自定义数据集上测试模型泛化能力
正文完
发表至: 未分类
近两天内
