基于 PyTorch CNN 实现 MNIST 手写数字识别
一、学习总结
本次学习围绕卷积神经网络 CNN 与手写数字图像分类展开,以 PyTorch 为开发框架,完成 MNIST 手写数字识别完整项目实践。
系统掌握了图像分类基础流程:数据集加载、数据标准化预处理、卷积神经网络搭建、模型迭代训练、精度评估与结果可视化。理解了卷积层负责提取图像局部纹理与轮廓特征、池化层压缩特征维度、全连接层完成最终分类的核心原理,对比全连接网络,认识到 CNN 在图像处理上的优势。
熟练使用 torchvision 加载公共数据集,通过 DataLoader 实现批量数据读取与打乱训练;学会搭建简易 CNN 网络,合理设置卷积核、通道数、激活函数;掌握模型训练的完整逻辑:前向传播计算损失、反向传播更新参数、利用 GPU 加速运算;同时实现模型测试、准确率统计与单张图片预测可视化,完整落地深度学习项目流程。
实践中熟悉了张量维度变换、模型评估关闭梯度、数据设备迁移等实操细节,通过迭代训练直观看到损失下降、准确率提升,深入理解模型优化原理。深度学习项目流程规范,合理的数据处理与网络设计是模型高性能的核心,本次实践为后续计算机视觉相关学习积累了实操经验。
二、项目介绍
MNIST 是经典手写数字数据集,包含 0~9 共 10 类灰度手写图片。本文使用两层卷积 + 池化的轻量 CNN 模型,基于 PyTorch 完成训练、测试与单图预测,模型识别精度高,适合深度学习入门练习。
三、环境依赖
bash
运行
pip install torch torchvision matplotlib
四、完整代码
python
运行
# 导入必要库
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
# 1. 数据预处理与加载
transform = transforms.Compose([
transforms.ToTensor(), # 转为Tensor并归一化到[0,1]
transforms.Normalize((0.1307,), (0.3081,)) # 用MNIST数据集的均值和标准差标准化
])
# 加载MNIST数据集
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=1000, shuffle=False)
# 2. 构建CNN模型
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
# 卷积层
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
# 池化层
self.pool = nn.MaxPool2d(2, 2)
# 全连接层
self.fc1 = nn.Linear(64 * 7 * 7, 128)
self.fc2 = nn.Linear(128, 10)
# 激活函数
self.relu = nn.ReLU()
def forward(self, x):
x = self.pool(self.relu(self.conv1(x)))
x = self.pool(self.relu(self.conv2(x)))
x = x.view(-1, 64 * 7 * 7)
x = self.relu(self.fc1(x))
x = self.fc2(x)
return x
# 初始化模型、损失函数、优化器
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = CNN().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 3. 模型训练
def train(model, train_loader, criterion, optimizer, device, epochs=5):
model.train()
for epoch in range(epochs):
running_loss = 0.0
for images, labels in train_loader:
images, labels = images.to(device), labels.to(device)
outputs = model(images)
loss = criterion(outputs, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
running_loss += loss.item()
print(f"Epoch {epoch+1}, Loss: {running_loss/len(train_loader):.4f}")
train(model, train_loader, criterion, optimizer, device)
# 4. 模型评估
def test(model, test_loader, device):
model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
images, labels = images.to(device), labels.to(device)
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f"Test Accuracy: {100 * correct / total:.2f}%")
test(model, test_loader, device)
# 5. 单张图片预测演示
def predict_single_image(model, test_dataset, device, index=10):
model.eval()
image, label = test_dataset[index]
image = image.unsqueeze(0).to(device)
with torch.no_grad():
output = model(image)
_, predicted = torch.max(output, 1)
plt.imshow(image.squeeze().cpu().numpy(), cmap='gray')
plt.title(f"True Label: {label}, Predicted: {predicted.item()}")
plt.axis('off')
plt.show()
predict_single_image(model, test_dataset, device, index=10)
五、运行结果
控制台输出:
plaintext
Epoch 1, Loss: 0.1527
Epoch 2, Loss: 0.0479
Epoch 3, Loss: 0.0316
Epoch 4, Loss: 0.0233
Epoch 5, Loss: 0.0179
Test Accuracy: 99.15%
训练损失持续下降,测试集准确率达到 99% 以上。同时弹出可视化窗口,展示手写数字原图、真实标签与模型预测结果,识别准确。
六、核心原理简析
- 数据预处理:将图像转为张量并标准化,加快模型收敛;
- CNN 结构:卷积提取图像特征,池化降维减参,全连接层完成多分类;
- 训练机制:使用交叉熵损失 + Adam 优化器,通过反向传播不断更新网络权重;
- 模型推理:关闭梯度计算,提升测试速度,结合 matplotlib 实现结果可视化。
七、总结
本次通过 CNN 完成手写数字识别,完整走完深度学习图像分类全流程。CNN 凭借优秀的特征提取能力,在视觉任务中表现突出。本项目代码简洁、易复现,适合新手入门学习,后续可通过增加网络层数、添加正则化、调整超参数等方式进一步优化模型性能。
更多推荐


所有评论(0)