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

 更新时间:2024年06月25日 16:52:47   作者:什么都不太会的研究生  
这篇文章主要介绍了深度学习的MNIST手写数字数据集识别方式(准确率99%,附代码),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

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)代码导入

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

在这里插入图片描述

# 下载数据集
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))

7)自己手写数字图片识别函数(可选用)

这部分主要是加载训练好的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()

8)MNIST中的数据识别测试数据

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

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

9)测试自己的手写数字图片(可选)

这部分主要是与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()

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • python中的decimal类型转换实例详解

    python中的decimal类型转换实例详解

    decimal 模块实现了定点和浮点算术运算符,使用的是大多数人所熟悉的模型,而不是程序员熟悉的模型,即大多数计算机硬件实现的 IEEE 浮点数运算。这篇文章主要介绍了python里的decimal类型转换,需要的朋友可以参考下
    2019-06-06
  • 详解python 一维、二维列表的初始化问题

    详解python 一维、二维列表的初始化问题

    这篇文章主要介绍了python 一维、二维列表的初始化,本文通过两种方式给大家详细讲解,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2022-06-06
  • Python爬虫之网页图片抓取的方法

    Python爬虫之网页图片抓取的方法

    最近小编一直在学习python的东西,今天小编给大家分享基于python写的一个爬虫程序,能实现简单的网页图片下载,具体实例代码大家参考下本文
    2018-07-07
  • Python实现全角半角字符互转的方法

    Python实现全角半角字符互转的方法

    大家都知道在自然语言处理过程中,全角、半角的的不一致会导致信息抽取不一致,因此需要统一。这篇文章通过示例代码给大家详细的介绍了Python实现全角半角字符互转的方法,有需要的朋友们可以参考借鉴,下面跟着小编一起学习学习吧。
    2016-11-11
  • Python企业编码生成系统之系统主要函数设计详解

    Python企业编码生成系统之系统主要函数设计详解

    这篇文章主要介绍了Python企业编码生成系统之系统主要函数设计,涉及目录操作、文件读写、验证判断、编码输出等功能实现技巧,需要的朋友可以参考下
    2019-07-07
  • Python函数的作用域及内置函数详解

    Python函数的作用域及内置函数详解

    这篇文章主要介绍了python函数的作用域及内置函数详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2021-09-09
  • 详解python Todo清单实战

    详解python Todo清单实战

    这篇文章主要介绍了详解python Todo清单实战,需要实现的功能有添加任务、删除任务、编辑任务,操作要关联数据库,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-11-11
  • Flask交互基础(GET、 POST 、PUT、 DELETE)的使用

    Flask交互基础(GET、 POST 、PUT、 DELETE)的使用

    这篇文章主要介绍了Flask交互基础(GET、 POST 、PUT、 DELETE)的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • opencv检测动态物体的实现

    opencv检测动态物体的实现

    本文主要介绍了opencv检测动态物体的实现,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2021-07-07
  • Python中可以用三种方法判断文件是否存在

    Python中可以用三种方法判断文件是否存在

    本文主要介绍了Python中可以用三种方法判断文件是否存在,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06

最新评论