引言:开启深度学习之旅
手写数字识别是计算机视觉领域的"Hello World",也是理解深度学习核心概念的最佳起点。本文将带您使用PyTorch框架,在Anaconda环境中实现一个强大的手写数字识别系统。通过Jupyter Notebook的交互式体验,您将从零开始构建神经网络模型,并见证AI如何学会识别数字。
一、环境配置:Anaconda+PyTorch GPU环境搭建
1. 安装Anaconda
前往Anaconda官网下载并安装适合您操作系统的版本
==> 看我出的Anaconda教学 <==
2. Anaconda Prompt中创建虚拟环境
conda create -n pytorch27 python=3.9
conda activate pytorch27
3. 安装PyTorch 2.7版本及相关库
==> 看我出的PyTorch的GPU环境安装教程 <==
4. 安装Jupyter Notebook
可以直接使用pip下载
pip install jupyter notebook
5. 下载python所需的内核
pip install ipykernel
6. 在Jupyter中注册内核
python -m ipykernel install --user --name=myenv --display-name="ipykernel_name"
`--user` —— 表示安装时针对当前用户;
`--name` —— 指定了内核的名称,应与你创建Conda的虚拟环境名称一致;
`--displey-name="ipykernel_name"` —— 设置在Jupyter Notebook的中显示的内核名称
7. 修改Jupyter Notebook启动默认路径
1)找到Jupyter Notebook快捷方式
2)右键快捷方式,点击属性
3)找到目标里的引号内容,将引号内容改为你自己喜欢的路径
7. 启动Jupyter Notebook
jupyter notebook
8. 验证安装
右键新建一个Notebook,右上角选择你创建的内核,在Jupyter Notebook中运行:
import torch
print(f"PyTorch版本: {torch.__version__}")
print(f"GPU可用: {torch.cuda.is_available()}")
print(f"设备名称: {torch.cuda.get_device_name(0)}")
显示以下内容就证明GPU环境配置成功啦!!!
二、数据准备:MNIST数据集揭秘
数据集介绍
MNIST包含70,000张28x28像素的手写数字灰度图像:
-
60,000张训练图像
-
10,000张测试图像
-
10个类别(0-9)
加载与预处理
import torch
import torchvision
from torchvision import transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
# 定义数据预处理
transform = transforms.Compose([
transforms.ToTensor(), # 转为Tensor,并归一化到[0,1]
transforms.Normalize((0.1307,), (0.3081,)) # MNIST均值和标准差
])
# 加载数据集
train_dataset = torchvision.datasets.MNIST(
root='./data', train=True, download=True, transform=transform
)
test_dataset = torchvision.datasets.MNIST(
root='./data', train=False, download=True, transform=transform
)
# 创建DataLoader
batch_size = 64
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
可视化样本数据
# 可视化样本
def show_images(images, labels, n=6):
plt.figure(figsize=(10, 5))
for i in range(n):
plt.subplot(2, 3, i+1)
plt.imshow(images[i].squeeze(), cmap='gray')
plt.title(f"Label: {labels[i]}")
plt.axis('off')
plt.tight_layout()
plt.show()
# 获取一批数据
images, labels = next(iter(train_loader))
show_images(images, labels)
三、模型构建:从全连接到卷积神经网络
1. 全连接神经网络(FCN)
import torch.nn as nn
class NeuralNetwork(nn.Module):
def __init__(self):
super(NeuralNetwork, self).__init__()
self.flatten = nn.Flatten()
self.layers = nn.Sequential(
nn.Linear(28*28, 400), # 输入层784 -> 隐藏层400
nn.ReLU(),
nn.Linear(400, 200), # 隐藏层400 -> 200
nn.ReLU(),
nn.Linear(200, 100), # 隐藏层200 -> 100
nn.ReLU(),
nn.Linear(100, 10) # 隐藏层100 -> 输出层10
)
def forward(self, x):
x = self.flatten(x)
return self.layers(x)
# 实例化模型(CPU)
model = NeuralNetwork()
print(model)
若使用的是GPU,实例化模型如下所示
# 实例化模型并移至GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = NeuralNetwork().to(device)
print(model)
2. 卷积神经网络(CNN) - 更强大的选择
这里我是用的是GPU实例化
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv_layers = nn.Sequential(
# 卷积层1: 输入1通道, 输出32通道, 3x3卷积核
nn.Conv2d(1, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2), # 池化后尺寸14x14
# 卷积层2: 输入32通道, 输出64通道
nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2) # 池化后尺寸7x7
)
self.fc_layers = nn.Sequential(
nn.Linear(64 * 7 * 7, 128),
nn.ReLU(),
nn.Dropout(0.5), # 添加Dropout防止过拟合
nn.Linear(128, 10)
)
def forward(self, x):
x = self.conv_layers(x)
x = x.view(x.size(0), -1) # 展平
return self.fc_layers(x)
# 实例化CNN模型
model_cnn = CNN().to(device)
print(model_cnn)
# 使用Adam优化器
optimizer_cnn = optim.Adam(model_cnn.parameters(), lr=0.001)
四、模型训练:让AI学会识别数字
1. 训练准备
import torch.optim as optim
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# 训练函数
def train(model, train_loader, criterion, optimizer, epochs=10):
model.train()
train_losses = []
for epoch in range(epochs):
running_loss = 0.0
for images, labels in train_loader:
# 数据移至GPU
images, labels = images.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
epoch_loss = running_loss/len(train_loader)
train_losses.append(epoch_loss)
print(f"Epoch {epoch+1}/{epochs}, Loss: {epoch_loss:.4f}")
# 绘制损失曲线
plt.plot(train_losses)
plt.title('Training Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.show()
# 测试函数
def test(model, test_loader):
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()
accuracy = 100 * correct / total
print(f"测试集准确率: {accuracy:.2f}%")
return accuracy
2. 训练全连接网络
# 训练并测试
train(model, train_loader, criterion, optimizer, epochs=10)
fc_accuracy = test(model, test_loader)
3. 训练卷积神经网络
# 训练CNN模型
train(model_cnn, train_loader, criterion, optimizer_cnn, epochs=10)
cnn_accuracy = test(model_cnn, test_loader)
4. 模型对比
# 模型性能对比
print("\n=== 模型性能对比 ===")
print(f"全连接网络准确率: {fc_accuracy:.2f}%")
print(f"卷积神经网络准确率: {cnn_accuracy:.2f}%")
五、结果分析:CNN为何更强大?
性能对比
模型类型 | 测试准确率 | 训练时间 | 参数量 |
---|---|---|---|
全连接网络 | ~97% | 较短 | ~300K |
卷积神经网络 | ~99% | 较长 | ~1.2M |
CNN优势解析
-
局部感知:卷积核专注于局部特征
-
参数共享:相同卷积核检测不同位置特征
-
空间不变性:池化操作保持特征不变
-
层次结构:底层识别边缘,高层识别复杂模式
可视化预测结果
def visualize_predictions(model, test_loader, n=12):
model.eval()
images, labels = next(iter(test_loader))
images, labels = images.to(device), labels.to(device)
with torch.no_grad():
outputs = model(images[:n])
_, preds = torch.max(outputs, 1)
plt.figure(figsize=(12, 6))
for i in range(n):
plt.subplot(3, 4, i+1)
plt.imshow(images[i].cpu().squeeze(), cmap='gray')
plt.title(f"预测: {preds[i].item()}\n真实: {labels[i].item()}")
plt.axis('off')
plt.tight_layout()
plt.show()
# 可视化CNN预测结果
visualize_predictions(model_cnn, test_loader)
六、性能优化技巧
1. 学习率调度:
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)
2. 数据增强:
transform_train = transforms.Compose([
transforms.RandomRotation(10),
transforms.RandomAffine(0, scale=(0.9, 1.1)),
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
3. 早停法
best_accuracy = 0
for epoch in range(epochs):
# 训练代码...
current_accuracy = test(model, test_loader)
if current_accuracy > best_accuracy:
best_accuracy = current_accuracy
torch.save(model.state_dict(), 'best_model.pth')
七、常见问题解答
Q: 为什么我的模型准确率停滞不前?
A: 尝试:
-
增加模型复杂度
-
调整学习率(尝试0.001-0.0001)
-
增加训练轮数
-
添加更多数据增强
Q: 如何提高推理速度?
A: 可考虑:
-
量化模型:
torch.quantization.quantize_dynamic
-
使用更轻量级网络(如MobileNet)
-
启用半精度训练
Q: 遇到内存不足错误怎么办?
A:
-
减小batch size
-
使用梯度累积
-
启用混合精度训练
八、结语:从数字识别到现实应用
通过本教程,您已经实现了:
-
PyTorch环境配置
-
MNIST数据加载与预处理
-
全连接网络构建与训练
-
CNN模型实现与优化
-
模型评估与结果可视化
手写数字识别只是计算机视觉的起点,这些技术可扩展到:
-
人脸识别系统
-
医学影像分析
-
自动驾驶感知
-
工业质检
到此,整一个PyTorch手写数字识别实战:从环境配置到CNN模型实现就完成啦!!!感谢大家支持!!!ovO