基于深度学习的MNIST手写数字数据集识别(准确率99%,附代码)

本文详细介绍了如何使用PyTorch对MNIST数据集进行预处理、下载,以及构建和训练卷积神经网络模型。通过14轮训练,模型达到了99%以上的识别准确率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文章已经生成可运行项目,

1.Mnist数据集介绍

1.1 基本介绍

Mnist数据集可以算是学习深度学习最常用到的了。这个数据集包含70000张手写数字图片,分别是60000张训练图片和10000张测试图片,训练集由来自250个不同人手写的数字构成,一般来自高中生,一半来自工作人员,测试集(test set)也是同样比例的手写数字数据,并且保证了测试集和训练集的作者不同。每个图片都是2828个像素点,数据集会把一张图片的数据转成一个2828=784的一维向量存储起来。
里面的图片数据如下所示,每张图是0-9的手写数字黑底白字的图片,存储时,黑色用0表示,白色用0-1的浮点数表示。
在这里插入图片描述

1.2 数据集下载

1)官网下载

Mnist数据集的下载地址如下:http://yann.lecun.com/exdb/mnist/
打开后会有四个文件:
在这里插入图片描述

  • 训练数据集:train-images-idx3-ubyte.gz
  • 训练数据集标签:train-labels-idx1-ubyte.gz
  • 测试数据集:t10k-images-idx3-ubyte.gz
  • 测试数据集标签:t10k-labels-idx1-ubyte.gz

将这四个文件下载后放置到需要用的文件夹下即可不要解压!下载后是什么就怎么放!

2)直接下载数据集

许多人反映官网不能直接下载数据集了,为方便大家,这里直接给出压缩包大家自行下载,获取去别的播客找MINIST数据集也是一样的。
链接里的文件,下载之后解压,直接放入自己建的命名为data的数据集下就行

链接:https://pan.baidu.com/s/1OkKedNCacsUWGMN7tL9Pcw
提取码:u81h

3)代码导入

文件夹下运行下面的代码,即可自动检测数据集是否存在,若没有会自动进行下载,下载后在这一路径:
在这里插入图片描述

# 下载数据集
from torchvision import datasets, transforms

train_set = datasets.MNIST("data",train=True,download=True, transform=transforms.ToTensor(),)
test_set = datasets.MNIST("data",train=False,download=True, transform=transforms.ToTensor(),)

参数解释:

  • datasets.MNIST:是Pytorch的内置函数torchvision.datasets.MNIST,可以导入数据集
  • train=True :读入的数据作为训练集
  • transform:读入我们自己定义的数据预处理操作
  • download=True:当我们的根目录(root)下没有数据集时,便自动下载

如果这时候我们通过联网自动下载方式download我们的数据后,它的文件路径是以下形式:原文件夹/data/MNIST/raw

2.代码部分

2.1文件夹目录:

在这里插入图片描述

  • test:自己写的测试图片
  • main:主函数
  • model:训练的模型参数,会自动生成
  • data:数据集文件夹

2.2 运行结果

14轮左右,模型识别准确率达到99%以上
在这里插入图片描述

2.3代码

1) 导入必要的包及预处理,本人学习时做了较多注释,且用的是下载好的文件,如果是自己的请更改对应的文件目录哦。

import os
import matplotlib.pyplot as plt
import torch
from PIL import Image
from torch import nn
from torch.nn import Conv2d, Linear, ReLU
from torch.nn import MaxPool2d
from torchvision import transforms
from torchvision.datasets import MNIST
from torch.utils.data import DataLoader


# Dataset:创建数据集的函数;__init__:初始化数据内容和标签
# __geyitem:获取数据内容和标签
# __len__:获取数据集大小
# daataloader:数据加载类,接受来自dataset已经加载好的数据集
# torchbision:图形库,包含预训练模型,加载数据的函数、图片变换,裁剪、旋转等
# torchtext:处理文本的工具包,将不同类型的额文件转换为datasets

# 预处理:将两个步骤整合在一起
transform = transforms.Compose({
    transforms.ToTensor(),  # 将灰度图片像素值(0~255)转为Tensor(0~1),方便后续处理
    # transforms.Normalize((0.1307,),(0.3081)),    # 归一化,均值0,方差1;mean:各通道的均值std:各通道的标准差inplace:是否原地操作
})

2)加载数据集

# 加载数据集
# 训练数据集
train_data = MNIST(root='./data', train=True, transform=transform, download=True)
train_loader = DataLoader(dataset=train_data, batch_size=64, shuffle=True)
# transform:指示加载的数据集应用的数据预处理的规则,shuffle:洗牌,是否打乱输入数据顺序
# 测试数据集
test_data = MNIST(root="./data", train=False, transform=transform, download=True)
test_loader = DataLoader(dataset=test_data, batch_size=64, shuffle=True)

train_data_size = len(train_data)
test_data_size = len(test_data)
print("训练数据集的长度:{}".format(train_data_size))
print("测试数据集的长度:{}".format(test_data_size))

3)构建模型

成功运行的话请给个免费的赞吧!(调试不易)

模型主要由两个卷积层,两个池化层,以及三个全连接层构成,激活函数使用relu.

class MnistModel(nn.Module):
    def __init__(self):
        super(MnistModel, self).__init__()
        self.conv1 = Conv2d(in_channels=1, out_channels=10, kernel_size=5, stride=1, padding=0)
        self.maxpool1 = MaxPool2d(2)
        self.conv2 = Conv2d(in_channels=10, out_channels=20, kernel_size=5, stride=1, padding=0)
        self.maxpool2 = MaxPool2d(2)
        self.linear1 = Linear(320, 128)
        self.linear2 = Linear(128, 64)
        self.linear3 = Linear(64, 10)
        self.relu = ReLU()

    def forward(self, x):
        x = self.relu(self.maxpool1(self.conv1(x)))
        x = self.relu(self.maxpool2(self.conv2(x)))
        x = x.view(x.size(0), -1)
        x = self.linear1(x)
        x = self.linear2(x)
        x = self.linear3(x)

        return x

# 损失函数CrossentropyLoss
model = MnistModel()#实例化
criterion = nn.CrossEntropyLoss()   # 交叉熵损失,相当于Softmax+Log+NllLoss
# 线性多分类模型Softmax,给出最终预测值对于10个类别出现的概率,Log:将乘法转换为加法,减少计算量,保证函数的单调性
# NLLLoss:计算损失,此过程不需要手动one-hot编码,NLLLoss会自动完成

# SGD,优化器,梯度下降算法e
optimizer = torch.optim.SGD(model.parameters(), lr=0.14)#lr:学习率

4)模型训练
每次训练完成后会自动保存参数到pkl模型中,如果路径中有Pkl文件,下次运行会自动加载上一次的模型参数,在这个基础上继续训练,第一次运行时没有模型参数,结束后会自动生成。

# 模型训练
def train():
    # index = 0
    for index, data in enumerate(train_loader):#获取训练数据以及对应标签
        # for data in train_loader:
       input, target = data   # input为输入数据,target为标签
       y_predict = model(input) #模型预测
       loss = criterion(y_predict, target)
       optimizer.zero_grad() #梯度清零
       loss.backward()#loss值反向传播
       optimizer.step()#更新参数
       # index += 1
       if index % 100 == 0: # 每一百次保存一次模型,打印损失
           torch.save(model.state_dict(), "./model/model.pkl")   # 保存模型
           torch.save(optimizer.state_dict(), "./model/optimizer.pkl")
           print("训练次数为:{},损失值为:{}".format(index, loss.item() ))


5)加载模型
第一次运行这里需要一个空的model文件夹

# 加载模型
if os.path.exists('./model/model.pkl'):
   model.load_state_dict(torch.load("./model/model.pkl"))#加载保存模型的参数

6)模型测试

# 模型测试
def test():
    correct = 0     # 正确预测的个数
    total = 0   # 总数
    with torch.no_grad():   # 测试不用计算梯度
        for data in test_loader:
            input, target = data
            output = model(input)   # output输出10个预测取值,概率最大的为预测数
            probability, predict = torch.max(input=output.data, dim=1)    # 返回一个元祖,第一个为最大概率值,第二个为最大概率值的下标
            # loss = criterion(output, target)
            total += target.size(0)  # target是形状为(batch_size,1)的矩阵,使用size(0)取出该批的大小
            correct += (predict == target).sum().item()  # predict 和target均为(batch_size,1)的矩阵,sum求出相等的个数
        print("测试准确率为:%.6f" %(correct / total))

6)自己手写数字图片识别函数(可选用)
这部分主要是加载训练好的pkl模型测试自己的数据,因此在进行自己手写图的测试时,需要有训练好的pkl文件,并且就不要调用train()函数和test()函数啦注意:这个图片像素也要说黑底白字,28*28像素,否则无法识别

def test_mydata():
    image = Image.open('./test/test_two.png')   #读取自定义手写图片
    image = image.resize((28, 28))   # 裁剪尺寸为28*28
    image = image.convert('L')  # 转换为灰度图像
    transform = transforms.ToTensor()
    image = transform(image)
    image = image.resize(1, 1, 28, 28)
    output = model(image)
    probability, predict = torch.max(output.data, dim=1)
    print("此手写图片值为:%d,其最大概率为:%.2f " % (predict[0], probability))
    plt.title("此手写图片值为:{}".format((int(predict))), fontname='SimHei')
    plt.imshow(image.squeeze())
    plt.show()

7)MNIST中的数据识别测试数据
训练过程中的打印信息我进行了修改,这里设置的训练轮数是15轮,每次训练生成的pkl模型参数也是会更新的,想要更多训练信息可以查看对应的教程哦~

#测试识别函数
if __name__ == '__main__':
    #训练与测试
    for i in range(15):#训练和测试进行15轮
        print({"————————第{}轮测试开始——————".format (i + 1)})
        train()
        test(

8)测试自己的手写数字图片(可选)
这部分主要是与tset_mydata()函数结合,加载训练好的pkl模型测试自己的数据,因此在进行自己手写图的测试时,需要有训练好的pkl文件,并且就不要调用train()函数和test()函数啦。注意:这个图片像素也要说黑底白字,28*28像素,否则无法识别

# 测试主函数
if __name__ == '__main__':
    test_mydata()

将所有代码按顺序放到编辑器中,安装好对应的包,就可以顺利运行啦。

  • 如果成功运行了请给我一个免费的赞吧,这对我真的很重要!!!
  • 如果不成功请留下你的问题,我会尽量帮忙的!

完整代码放下面:

import os
import matplotlib.pyplot as plt
import torch
from PIL import Image
from torch import nn
from torch.nn import Conv2d, Linear, ReLU
from torch.nn import MaxPool2d
from torchvision import transforms
from torchvision.datasets import MNIST
from torch.utils.data import DataLoader


# Dataset:创建数据集的函数;__init__:初始化数据内容和标签
# __geyitem:获取数据内容和标签
# __len__:获取数据集大小
# daataloader:数据加载类,接受来自dataset已经加载好的数据集
# torchbision:图形库,包含预训练模型,加载数据的函数、图片变换,裁剪、旋转等
# torchtext:处理文本的工具包,将不同类型的额文件转换为datasets

# 预处理:将两个步骤整合在一起
transform = transforms.Compose({
    transforms.ToTensor(),  # 将灰度图片像素值(0~255)转为Tensor(0~1),方便后续处理
    # transforms.Normalize((0.1307,),(0.3081)),    # 归一化,均值0,方差1;mean:各通道的均值std:各通道的标准差inplace:是否原地操作
})

# normalize执行以下操作:image=(image-mean)/std?????
# input[channel] = (input[channel] - mean[channel]) / std[channel]

# 加载数据集
# 训练数据集
train_data = MNIST(root='./data', train=True, transform=transform, download=True)
train_loader = DataLoader(dataset=train_data, batch_size=64, shuffle=True)
# transform:指示加载的数据集应用的数据预处理的规则,shuffle:洗牌,是否打乱输入数据顺序
# 测试数据集
test_data = MNIST(root="./data", train=False, transform=transform, download=True)
test_loader = DataLoader(dataset=test_data, batch_size=64, shuffle=True)

train_data_size = len(train_data)
test_data_size = len(test_data)
print("训练数据集的长度:{}".format(train_data_size))
print("测试数据集的长度:{}".format(test_data_size))
# print(test_data)
# print(train_data)


class MnistModel(nn.Module):
    def __init__(self):
        super(MnistModel, self).__init__()
        self.conv1 = Conv2d(in_channels=1, out_channels=10, kernel_size=5, stride=1, padding=0)
        self.maxpool1 = MaxPool2d(2)
        self.conv2 = Conv2d(in_channels=10, out_channels=20, kernel_size=5, stride=1, padding=0)
        self.maxpool2 = MaxPool2d(2)
        self.linear1 = Linear(320, 128)
        self.linear2 = Linear(128, 64)
        self.linear3 = Linear(64, 10)
        self.relu = ReLU()

    def forward(self, x):
        x = self.relu(self.maxpool1(self.conv1(x)))
        x = self.relu(self.maxpool2(self.conv2(x)))
        x = x.view(x.size(0), -1)
        x = self.linear1(x)
        x = self.linear2(x)
        x = self.linear3(x)

        return x


# 损失函数CrossentropyLoss
model = MnistModel()#实例化
criterion = nn.CrossEntropyLoss()   # 交叉熵损失,相当于Softmax+Log+NllLoss
# 线性多分类模型Softmax,给出最终预测值对于10个类别出现的概率,Log:将乘法转换为加法,减少计算量,保证函数的单调性
# NLLLoss:计算损失,此过程不需要手动one-hot编码,NLLLoss会自动完成

# SGD,优化器,梯度下降算法e
optimizer = torch.optim.SGD(model.parameters(), lr=0.14)#lr:学习率


# 模型训练
def train():
    # index = 0
    for index, data in enumerate(train_loader):#获取训练数据以及对应标签
        # for data in train_loader:
       input, target = data   # input为输入数据,target为标签
       y_predict = model(input) #模型预测
       loss = criterion(y_predict, target)
       optimizer.zero_grad() #梯度清零
       loss.backward()#loss值反向传播
       optimizer.step()#更新参数
       # index += 1
       if index % 100 == 0: # 每一百次保存一次模型,打印损失
           torch.save(model.state_dict(), "./model/model.pkl")   # 保存模型
           torch.save(optimizer.state_dict(), "./model/optimizer.pkl")
           print("训练次数为:{},损失值为:{}".format(index, loss.item() ))

# 加载模型
if os.path.exists('./model/model.pkl'):
   model.load_state_dict(torch.load("./model/model.pkl"))#加载保存模型的参数


# 模型测试
def test():
    correct = 0     # 正确预测的个数
    total = 0   # 总数
    with torch.no_grad():   # 测试不用计算梯度
        for data in test_loader:
            input, target = data
            output = model(input)   # output输出10个预测取值,概率最大的为预测数
            probability, predict = torch.max(input=output.data, dim=1)    # 返回一个元祖,第一个为最大概率值,第二个为最大概率值的下标
            # loss = criterion(output, target)
            total += target.size(0)  # target是形状为(batch_size,1)的矩阵,使用size(0)取出该批的大小
            correct += (predict == target).sum().item()  # predict 和target均为(batch_size,1)的矩阵,sum求出相等的个数
        print("测试准确率为:%.6f" %(correct / total))


#测试识别函数
if __name__ == '__main__':
    #训练与测试
    for i in range(15):#训练和测试进行5轮
        print({"————————第{}轮测试开始——————".format (i + 1)})
        train()
        test()


def test_mydata():
    image = Image.open('./test/test_two.png')   #读取自定义手写图片
    image = image.resize((28, 28))   # 裁剪尺寸为28*28
    image = image.convert('L')  # 转换为灰度图像
    transform = transforms.ToTensor()
    image = transform(image)
    image = image.resize(1, 1, 28, 28)
    output = model(image)
    probability, predict = torch.max(output.data, dim=1)
    print("此手写图片值为:%d,其最大概率为:%.2f " % (predict[0], probability))
    plt.title("此手写图片值为:{}".format((int(predict))), fontname='SimHei')
    plt.imshow(image.squeeze())
    plt.show()

# 测试主函数
# if __name__ == '__main__':
#     test_mydata()
本文章已经生成可运行项目
03-08
### 关于MNIST数据集的相关资源 #### 使用教程 对于希望了解如何使用MNIST数据集进行图像分类的任务,可以参考官方文档说明。TensorFlow和Keras提供了便捷的方法来加载该数据集。仅需几行代码即可完成导入工作: ```python import tensorflow as tf (x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data() ``` 这段简洁的Python脚本能够快速获取训练与测试样本集合[^1]。 #### 下载途径 除了通过API直接调用外,还可以访问其他平台上的版本。例如,在线教育资料中提及的一个具体案例展示了从百度网盘下载相关教学材料的可能性[^2];而像Kaggle这样的竞赛网站也提供有经过整理后的MNIST数据集文件可供研究者利用[^4]。 #### 官方文档 为了更深入地理解这些工具的功能特性及其最佳实践方式,则应查阅框架本身的指南文档。Matplotlib等可视化库同样拥有详尽的帮助手册,有助于开发者更好地呈现分析成果[^5]。 #### 示例代码 下面给出一段完整的基于Keras构建简单神经网络模型并应用到MNIST手写数字识别任务上的例子: ```python from keras.models import Sequential from keras.layers import Dense, Flatten from keras.utils import to_categorical # 加载数据集 (x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data() # 预处理输入特征 x_train = x_train / 255.0 x_test = x_test / 255.0 # 将标签转换成one-hot编码形式 y_train = to_categorical(y_train, num_classes=10) y_test = to_categorical(y_test, num_classes=10) # 构建模型结构 model = Sequential([ Flatten(input_shape=(28, 28)), Dense(128, activation='relu'), Dense(10, activation='softmax') ]) # 编译配置优化器、损失函数及评估指标 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) # 开始训练过程 history = model.fit(x_train, y_train, epochs=5, batch_size=32, validation_split=0.2) # 测试性能表现 test_loss, test_acc = model.evaluate(x_test, y_test) print(f'Test accuracy: {test_acc}') ``` 此段程序演示了怎样创建一个多层感知机来进行基本的手写字体辨识操作,并包含了必要的预处理步骤以及最终的效果评测部分。
评论 118
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值