卷积神经网络(CNN)从原理到实现
什么是卷积神经网络(CNN)?
卷积神经网络(Convolutional Neural Network, CNN)是一种深度学习模型,主要应用于图像分类、目标检测和自然语言处理等领域。与传统神经网络不同,CNN 通过局部感受野、权值共享和池化操作有效减少参数量,同时保留空间信息。
CNN 结构图:
CNN 的核心概念
CNN 包括三大核心操作:卷积、激活函数 和 池化。
1. 卷积层(Convolution Layer)
卷积层的目的是提取特征,通过卷积核(Filter)对输入进行特征提取。卷积的数学公式如下:
y [ i , j ] = ∑ m = 0 k − 1 ∑ n = 0 k − 1 x [ i + m , j + n ] ⋅ w [ m , n ] + b y[i, j] = \sum_{m=0}^{k-1} \sum_{n=0}^{k-1} x[i+m, j+n] \cdot w[m, n] + b y[i,j]=m=0∑k−1n=0∑k−1x[i+m,j+n]⋅w[m,n]+b
- (x):输入图像
- (w):卷积核权重
- (b):偏置项
- (k):卷积核大小
卷积操作示意图:
2. 激活函数(Activation Function)
激活函数引入非线性因素,常用的是 ReLU 函数:
f ( x ) = max ( 0 , x ) f(x) = \max(0, x) f(x)=max(0,x)
ReLU 函数示意图:
3. 池化层(Pooling Layer)
池化层通过降维保留关键信息,常用的是最大池化(Max Pooling):
y [ i , j ] = max m , n ∈ window x [ i + m , j + n ] y[i, j] = \max_{m, n \in \text{window}} x[i+m, j+n] y[i,j]=m,n∈windowmaxx[i+m,j+n]
池化操作示意图:
LeNet-5 的结构
本文实现了经典的 LeNet-5 模型,用于 MNIST 手写数字分类。
LeNet-5 的结构如下:
层类型 | 输入大小 | 卷积核大小 | 输出大小 |
---|---|---|---|
输入层 | 1 x 28 x 28 | - | 1 x 28 x 28 |
卷积层 1 | 1 x 28 x 28 | 5 x 5 | 6 x 24 x 24 |
池化层 1 | 6 x 24 x 24 | 2 x 2 | 6 x 12 x 12 |
卷积层 2 | 6 x 12 x 12 | 5 x 5 | 16 x 8 x 8 |
池化层 2 | 16 x 8 x 8 | 2 x 2 | 16 x 4 x 4 |
全连接层 1 | 256 | - | 120 |
全连接层 2 | 120 | - | 84 |
输出层 | 84 | - | 10 |
示意图:
PyTorch 实现
数据加载
使用 torchvision.datasets
下载 MNIST 数据集,数据经过归一化和转换为张量。
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True)
test_dataset = datasets.MNIST(root='./data', train=False, transform=transform, download=True)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
LeNet-5 模型
LeNet-5 使用两层卷积、两层池化和三层全连接。
import torch
from torch.nn import Module
from torch import nn
class LeNet5(Module):
def __init__(self):
super(LeNet5, self).__init__()
self.conv1 = nn.Sequential(
nn.Conv2d(1, 6, 5),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.conv2 = nn.Sequential(
nn.Conv2d(6, 16, 5),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.fc1 = nn.Sequential(
nn.Linear(256, 120),
nn.ReLU()
)
self.fc2 = nn.Sequential(
nn.Linear(120, 84),
nn.ReLU()
)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = x.view(x.size(0), -1)
x = self.fc1(x)
x = self.fc2(x)
x = self.fc3(x)
return x
模型训练
模型使用交叉熵损失函数和 Adam 优化器。
import torch.optim as optim
from torch import nn
model = LeNet5()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
for epoch in range(10):
model.train()
for batch_idx, (data, label) in enumerate(train_loader):
output = model(data)
loss = criterion(output, label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if batch_idx % 100 == 0:
print(f"Epoch {epoch+1}/10 | Batch {batch_idx}/{len(train_loader)} | Loss: {loss.item():.4f}")
torch.save(model.state_dict(), 'mnist_lenet5.pth')
print("模型训练完成,已保存至 'mnist_lenet5.pth'")
模型验证
训练完成后,验证模型的准确率。
model.eval()
correct = 0
total = 0
with torch.no_grad():
for data, label in test_loader:
output = model(data)
_, predicted = torch.max(output.data, 1)
total += label.size(0)
correct += (predicted == label).sum().item()
accuracy = correct / total
print(f"模型在测试集上的准确率: {accuracy * 100:.2f}%")
结果分析
训练模型的损失值逐渐下降,最终测试集准确率为 99.2%,表明模型在手写数字分类任务上的效果非常好。
Epoch | Batch | Loss |
---|---|---|
1 | 100 | 2.3096 |
5 | 500 | 0.0701 |
10 | 900 | 0.0268 |
总结
本文从原理、实现到结果分析详细介绍了卷积神经网络和 LeNet-5 模型。关键点包括:
- 卷积、激活函数和池化操作 是 CNN 的核心。
- LeNet-5 是 CNN 的经典结构,适用于简单任务。
- PyTorch 提供了强大的工具链,帮助快速构建和训练模型。
参考文献:
- LeNet-5 Paper
- PyTorch Documentation