您现在的位置是:首页 >技术杂谈 >第P1周:Pytorch实现mnist手写数字识别网站首页技术杂谈

第P1周:Pytorch实现mnist手写数字识别

maverique 2026-07-08 12:01:05
简介第P1周:Pytorch实现mnist手写数字识别

 - **🍨 本文为[🔗365天深度学习训练营](https://mp.weixin.qq.com/s/rnFa-IeY93EpjVu0yzzjkw) 中的学习记录博客**
- **🍖 原作者:[K同学啊](https://mtyjkh.blog.csdn.net/)**

语言环境:Python 3.9

开发工具: Jupyter Lab

深度学习环境:pytorch

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import torchvision

 第一步:导入库

  • torch:PyTorch的核心库,用于张量操作和深度学习模型的实现。
  • torch.nn:提供构建神经网络的工具。
  • matplotlib.pyplot:用于绘制图形,主要用于结果的可视化。
  • torchvision:包含了常用的数据集和图像处理工具,这里用来加载MNIST数据集
device torch.device("cuda" if torch.cuda.is_available() else "cpu")
device

第二步:设置计算设备

这行代码检测是否有CUDA(即GPU)可用。如果GPU可用,则将设备设置为GPU;如果没有,则使用CPU 

train_ds = torchvision.datasets.MNIST('data', 
                                      train=True, 
                                      transform=torchvision.transforms.ToTensor(), # 将数据类型转化为Tensor
                                      download=True)

test_ds  = torchvision.datasets.MNIST('data', 
                                      train=False, 
                                      transform=torchvision.transforms.ToTensor(), # 将数据类型转化为Tensor
                                      download=True)

第三步:加载数据集

  • train_ds:加载MNIST训练数据集并将图像转换为张量。
  • test_ds:加载MNIST测试数据集,处理方式相同。
  • transform=torchvision.transforms.ToTensor():将图像数据转换为张量格式

batch_size = 32
train_dl = torch.utils.data.DataLoader(train_ds, batch_size=batch_size, shuffle=True)
test_dl  = torch.utils.data.DataLoader(test_ds, batch_size=batch_size)
torch.Size([32, 1, 28, 28])

 第四步:DataLoader设置

  • DataLoader:将数据集包装成可迭代的数据加载器,方便按批次加载和打乱数据。
  • batch_size:每个批次的数据量,设置为32。
  • shuffle=True:在训练时打乱数据顺序,避免数据顺序影响训练结果
plt.figure(figsize=(20, 5)) 
for i, imgs in enumerate(imgs[:20]):
    npimg = np.squeeze(imgs.numpy())
    plt.subplot(2, 10, i+1)
    plt.imshow(npimg, cmap=plt.cm.binary)
    plt.axis('off')

 

 第五步:可视化部分数据

这段代码将训练数据集中的前20张图像可视化,显示在一个2行10列的网格中

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3)  # 第一层卷积,卷积核大小为3x3
        self.pool1 = nn.MaxPool2d(2)                  # 设置池化层,池化核大小为2x2
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3) # 第二层卷积,卷积核大小为3x3   
        self.pool2 = nn.MaxPool2d(2) 
        self.fc1 = nn.Linear(1600, 64)                # 全连接层
        self.fc2 = nn.Linear(64, num_classes)         # 输出层

第六步:定义神经网络模型 

这里定义了一个卷积神经网络(CNN)模型:

  • Conv2d:卷积层,用于提取特征。
  • MaxPool2d:池化层,用于下采样,减少图像的空间尺寸。
  • Linear:全连接层,用于分类。
def forward(self, x):
    x = self.pool1(F.relu(self.conv1(x)))     
    x = self.pool2(F.relu(self.conv2(x)))
    x = torch.flatten(x, start_dim=1)
    x = F.relu(self.fc1(x))
    x = self.fc2(x)
    return x

 第七步:前向传播

这段代码定义了前向传播过程:

  • 每一层卷积后,应用ReLU激活函数和池化操作。
  • 将卷积后的数据展平(flatten),然后传递给全连接层
from torchinfo import summary
model = Model().to(device)
summary(model)
=================================================================
Layer (type:depth-idx)                   Param #
=================================================================
Model                                    --
├─Conv2d: 1-1                            320
├─MaxPool2d: 1-2                         --
├─Conv2d: 1-3                            18,496
├─MaxPool2d: 1-4                         --
├─Linear: 1-5                            102,464
├─Linear: 1-6                            650
=================================================================
Total params: 121,930
Trainable params: 121,930
Non-trainable params: 0
=================================================================

 

第八步:打印模型

summary(model) 打印模型的结构概况,包括每层的参数数量和输出尺寸 

loss_fn = nn.CrossEntropyLoss()
learn_rate = 1e-2
opt = torch.optim.SGD(model.parameters(), lr=learn_rate)

 第九步:损失函数和优化器

  • CrossEntropyLoss:交叉熵损失函数,常用于分类任务。
  • SGD (随机梯度下降):用于优化模型,调整权重以最小化损失
def train(dataloader, model, loss_fn, optimizer):
    train_loss, train_acc = 0, 0
    for X, y in dataloader:
        X, y = X.to(device), y.to(device)
        pred = model(X)
        loss = loss_fn(pred, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()
        train_loss += loss.item()
    return train_acc / size, train_loss / num_batches

 第十步:训练循环

  • 对每个批次的数据进行前向传播,计算损失。
  • 进行反向传播,更新模型参数。
  • 计算训练集的损失和准确率。
def test(dataloader, model, loss_fn):
    with torch.no_grad():
        for imgs, target in dataloader:
            imgs, target = imgs.to(device), target.to(device)
            target_pred = model(imgs)
            loss = loss_fn(target_pred, target)
            test_loss += loss.item()
            test_acc += (target_pred.argmax(1) == target).type(torch.float).sum().item()
    return test_acc / size, test_loss / num_batches

第十一步 :测试循环

epochs = 5
train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    model.train()
    epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, opt)
    model.eval()
    epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)
    train_acc.append(epoch_train_acc)
    train_loss.append(epoch_train_loss)
    test_acc.append(epoch_test_acc)
    test_loss.append(epoch_test_loss)
Epoch: 1, Train_acc:99.3%, Train_loss:0.022, Test_acc:98.8%,Test_loss:0.036
Epoch: 2, Train_acc:99.4%, Train_loss:0.021, Test_acc:98.8%,Test_loss:0.034
Epoch: 3, Train_acc:99.4%, Train_loss:0.021, Test_acc:98.9%,Test_loss:0.033
Epoch: 4, Train_acc:99.4%, Train_loss:0.019, Test_acc:98.8%,Test_loss:0.036
Epoch: 5, Train_acc:99.4%, Train_loss:0.018, Test_acc:98.9%,Test_loss:0.033
Done

 

第十二步:训练模型

模型训练5个周期,每个周期分别训练和测试:

  • 记录每个周期的训练和测试的损失和准确率
plt.figure(figsize=(12, 3))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, train_acc, label='Training Accuracy')
plt.plot(epochs_range, test_acc, label='Test Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, train_loss, label='Training Loss')
plt.plot(epochs_range, test_loss, label='Test Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

 

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。