Pytorch实现mnist手写数字识别

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

我的环境:

python 3.9

使用jupyter

torch==1.13.0+cu116

torchvision==0.14.0+cu116

 运行代码:

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import torchvision
from torchinfo import summary
from torch.utils.data import DataLoader
import numpy as np
import os
os.environ['KMP_DUPLICATE_LIB_OK']='True'
import warnings
#导入数据
#分为训练数据集和测试数据集
#读取
train_ds = torchvision.datasets.MNIST('data',train=True,
                                      transform=torchvision.transforms.ToTensor(),
                                      download=True)
test_ds = torchvision.datasets.MNIST('data',train=False,
                                     transform=torchvision.transforms.ToTensor(),
                                     download=True)
batchsize = 32
train_dl = DataLoader(train_ds,batchsize,shuffle=True,num_workers=0)
test_dl = DataLoader(test_ds,batchsize,num_workers=0)
imgs ,labels = next(iter(train_dl)) # iter迭代器,相当于for imgs,labels in train_dl:,next从迭代器取下一个
# for imgs,labels in train_dl:
print(imgs.shape)

# 数据可视化
plt.figure(figsize=(20,5)) # 创建绘图窗口为20宽5长
for i,imgs in enumerate(imgs[:20]): #遍历前20个图像
    npimg = np.squeeze(imgs.numpy()) # squeeze移除单维度,使维度对应图像尺寸
    plt.subplot(2,10,i+1)# 2行10列,i+指定当前子图位置,matplotlib从1开始
    plt.imshow(npimg,cmap = plt.cm.binary)
    plt.axis('off') # 关闭坐标轴,不显示坐标轴刻度和标签
plt.show()

 

#设置硬件设备,有GPU使用GPU,没有则使用CPU
device = torch.device("cuda"if torch.cuda.is_available()else"cpu")
print(device)

import torch.nn.functional as F

num_classes = 10  # 图片的类别数

class Model(nn.Module):
     def __init__(self):
        super().__init__()
         # 特征提取网络
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3)  # 第一层卷积,卷积核大小为3*3
        self.pool1 = nn.MaxPool2d(2)                  # 设置池化层,池化核大小为2*2
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3) # 第二层卷积,卷积核大小为3*3   
        self.pool2 = nn.MaxPool2d(2) 
                                      
        # 分类网络
        self.fc1 = nn.Linear(1600, 64)          
        self.fc2 = nn.Linear(64, num_classes)
     # 前向传播
     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

#打印加载模型
model = Model().to(device) # 到GPU中运行

summary(model)

 

# 训练模型
# 设置超参数
loss_fn = nn.CrossEntropyLoss()
learn_rate = 1e-2 # 学习率 = 0.01
opt = torch.optim.SGD(model.parameters(),lr = learn_rate)

# 训练循环
def train(dataloader,model,loss_fn,optimizer):
    size = len(dataloader.dataset) # 训练集大小,60000
    num_batches = len(dataloader)  # 批次数目,60000/32 = 1875

    train_loss, train_acc = 0,0 # 初始化训练误差和精度

    for data in dataloader:
        X,y = data  # 图片和标签
        X,y = X.to(device),y.to(device)

        #计算训练误差
        pred = model(X)  # 网络输出,预测值
        loss = loss_fn(pred,y)  # 计算差距

        # 反向传播
        optimizer.zero_grad() # grad属性归零
        loss.backward()  # 反向传播
        optimizer.step()  # 自动更新

        # 记录acc和loss
        # argmax(1) 函数会找出每一行(每个样本)中最大值的索引,这个索引代表了模型预测的类别。
        # .item()将求和结果转换为标量值,以便在 Python 中使用或打印。
        train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()  #  样本预测正确的数量
        train_loss += loss.item()

    train_acc /=size
    train_loss /= num_batches # 平均loss

    return  train_acc,train_loss

 #测试函数
def test(dataloader,model,loss_fn):
    size = len(dataloader.dataset) # 训练集大小,60000
    num_batches = len(dataloader)  # 批次数目,60000/32 = 1875
    test_loss, test_acc = 0,0 # 初始化测试误差和精度

    with torch.no_grad():   # 阻止追踪梯度
        for data in dataloader:
            X, y = data  # 图片和标签
            X, y = X.to(device), y.to(device)

            # 计算测试误差
            pred = model(X)  # 网络输出,预测值
            loss = loss_fn(pred, y)  # 计算差距

            # 记录acc和loss
            # argmax(1) 函数会找出每一行(每个样本)中最大值的索引,这个索引代表了模型预测的类别。
            # .item()将求和结果转换为标量值,以便在 Python 中使用或打印。
            test_acc += (pred.argmax(1) == y).type(torch.float).sum().item()  # 样本预测正确的数量
            test_loss += loss.item()

    test_acc /= size
    test_loss /= num_batches  # 平均loss

    return test_acc, test_loss
# 正式训练
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,optimizer=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)

    template = ('Epoch:{:2d},Train_acc:{:.1f}%,Train_loss:{:.3f},Test_acc:{:.1f}%,Test_loss:{:.3f}')
    print(template.format(epoch+1,epoch_train_acc*100,epoch_train_loss,epoch_test_acc*100,epoch_test_loss))

print('Done')

 

# 结果可视化
#隐藏警告
warnings.filterwarnings("ignore")

# plt.reParams['font.sana-serif'] = ['SimHei']  # 正常显示中文标签
# plt.reParams['axe.unicode_minus'] = False  # 正常显示负号
# plt.reParams['figure.dpi'] = 100  # 分辨率

epoche_range = range(epochs)

plt.figure(figsize=(12,3))

plt.subplot(1,2,1) # 行数,列数,第几个
plt.plot(epoche_range,train_acc,label = 'Training Accuracy') #横坐标,竖坐标,标题
plt.plot(epoche_range,test_acc,label = 'Testing Accuracy')
plt.legend(loc = 'lower right')  # 图例位置
plt.title('Training and Validation Accuracy')  #大标题

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

plt.show()

学习总结:

 MNIST数据集包括了70000张手写数字的灰度图像,其中60000张用于训练,10000张用于测试。每张图像是28x28像素的大小,图像中的数字介于0到9之间。学习数据预处理和一个完整的训练和测试代码结构,模型在测试集上达到了约97%的准确率。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值