当前位置: 首页 > news >正文

PyTorch实战:实现MNIST手写数字识别


前言

PyTorch可以说是三大主流框架中最适合初学者学习的了,相较于其他主流框架,PyTorch的简单易用性使其成为初学者们的首选。这样我想要强调的一点是,框架可以类比为编程语言,仅为我们实现项目效果的工具,也就是我们造车使用的轮子,我们重点需要的是理解如何使用Torch去实现功能而不要过度在意轮子是要怎么做出来的,那样会牵扯我们太多学习时间。以后就出一系列专门细解深度学习框架的文章,但是那是较后期我们对深度学习的理论知识和实践操作都比较熟悉才好开始学习,现阶段我们最需要的是学会如何使用这些工具。

深度学习的内容不是那么好掌握的,包含大量的数学理论知识以及大量的计算公式原理需要推理。且如果不进行实际操作很难够理解我们写的代码究极在神经网络计算框架中代表什么作用。不过我会尽可能将知识简化,转换为我们比较熟悉的内容,我将尽力让大家了解并熟悉神经网络框架,保证能够理解通畅以及推演顺利的条件之下,尽量不使用过多的数学公式和专业理论知识。以一篇文章快速了解并实现该算法,以效率最高的方式熟练这些知识。


博主专注数据建模四年,参与过大大小小数十来次数学建模,理解各类模型原理以及每种模型的建模流程和各类题目分析方法。此专栏的目的就是为了让零基础快速使用各类数学模型、机器学习和深度学习以及代码,每一篇文章都包含实战项目以及可运行代码。博主紧跟各类数模比赛,每场数模竞赛博主都会将最新的思路和代码写进此专栏以及详细思路和完全代码。希望有需求的小伙伴不要错过笔者精心打造的专栏。

一文速学-数学建模常用模型


一、数据集加载

MNIST(Modified National Institute of Standards and Technology)是一个手写数字数据集,通常用于训练各种图像处理系统。

它包含了大量的手写数字图像,这些数字从0到9。每个图像都是一个灰度图像,大小为28x28像素,表示了一个手写数字。

MNIST数据集分成两部分:训练集和测试集。训练集通常包含60,000张图像,用于训练模型。测试集包含10,000张图像,用于评估模型的性能。

MNIST数据集是一个非常受欢迎的数据集,被用于测试和验证各种机器学习和深度学习模型,特别是在图像识别任务中。大家可以直接访问官网下载或者是在程序中使用torchvision下载数据集。

官网:THE MNIST DATABASE

一共4个文件,训练集、训练集标签、测试集、测试集标签:

文件名称大小内容
train-labels-idx1-ubyte.gz9,681 kb55000张训练集,5000张验证集
train-labels-idx1-ubyte.gz29 kb训练集图片对应的标签
t10k-images-idx3-ubyte.gz1,611 kb10000张测试集
t10k-labels-idx1-ubyte.gz5 kb测试集图片对应的标签

 程序加载MNIST数据集:

from torch.utils.data import DataLoader
import torchvision.datasets as dsetstransform = transforms.Compose([transforms.Grayscale(num_output_channels=1),  # 将图像转为灰度transforms.ToTensor(),  # 将图像转为张量transforms.Normalize((0.1307,), (0.3081,))
])#MNIST dataset
train_dataset = dsets.MNIST(root = '/ml/pymnist',  #选择数据的根目录train = True,  #选择训练集transform = transform,  #不考虑使用任何数据预处理download = True  #从网络上下载图片)
test_dataset = dsets.MNIST(root = '/ml/pymnist',#选择数据的根目录train = False,#选择测试集transform = transform, #不考虑使用任何数据预处理download = True #从网络上下载图片)
#加载数据
train_loader = torch.utils.data.DataLoader(dataset=train_dataset,batch_size = batch_size,shuffle = True #将数据打乱)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,batch_size = batch_size,shuffle = True)

图片展示:

import matplotlib.pyplot as plt
digit = train_dataset.train_data[0]
plt.imshow(digit,cmap=plt.cm.binary,interpolation='none')
plt.title("Labels: {}".format(train_dataset.train_labels[0]))
plt.show()

 之后需要切分数据集,分为训练集和测试集,MNIST数据集已经做好了直接使用就好了:

print("train_data:",train_dataset.train_data.size())
print("train_labels:",train_dataset.train_labels.size())
print("test_data:",test_dataset.test_data.size())
print("test_labels:",test_dataset.test_labels.size())

train_data: torch.Size([60000, 28, 28])
train_labels: torch.Size([60000])
test_data: torch.Size([10000, 28, 28])
test_labels: torch.Size([10000])

还需要确定批次的尺寸,在神经网络训练中,batch_size 是指每次迭代训练时,模型同时处理的样本数量。它在训练过程中起到了几个重要作用:

  • 加速训练过程:通过同时处理多个样本,利用了现代计算机的并行计算能力,可以加速训练过程,尤其在使用GPU时。
  • 减少内存消耗:一次性加载整个训练集可能会占用大量内存,而将数据分批次加载可以降低内存消耗,使得在内存受限的环境中也能进行训练。
  • 提高模型泛化能力:在训练过程中,模型会根据每个batch的数据调整权重,而不是依赖于整个训练集。这样可以提高模型对不同样本的泛化能力。
  • 避免陷入局部极小值:随机选择的小批量样本可以帮助模型避免陷入局部极小值。
  • 增加噪声鲁棒性:在每次迭代中,模型只看到了一个小样本,这可以看作一种随机噪声,有助于提高模型的鲁棒性。
  • 方便在线学习:对于在线学习任务,可以动态地加载新的数据批次,而不需要重新训练整个模型。

总的来说,合理选择合适的batch_size可以使训练过程更加高效、稳定,并且能够提高模型的泛化能力。然而,过大的batch_size可能会导致内存溢出或训练速度变慢,过小的batch_size可能会导致模型收敛困难。因此,选择合适的batch_size需要在实践中进行调试和优化。

print("批次的尺寸:",train_loader.batch_size)
print("load_train_data:",train_loader.dataset.train_data.shape)
print("load_train_labels:",train_loader.dataset.train_labels.shape)

 

批次的尺寸: 100
load_train_data: torch.Size([60000, 28, 28])
load_train_labels: torch.Size([60000])

 从输出结果中,可以看到原始数据集和数据打乱按照批次读取的数据集的总行数是一样的,实际操作中train_loader以及test_loader将作为神经网络的输入数据源。

二、定义神经网络

在前面的文章中已经带着大家搭建过好几遍神经网络了,注意初始化网络和对应的输入层,隐藏层和输出层。

import torch.nn as nn
import torchinput_size = 784 #mnist的像素为28*28
hidden_size = 500
num_classes = 10#输出为10个类别分别对应于0~9#创建神经网络模型
class Neural_net(nn.Module):
#初始化函数,接受自定义输入特征的维数,隐含层特征维数以及输出层特征维数def __init__(self,input_num,hidden_size,out_put):super(Neural_net,self).__init__()self.layer1 = nn.Linear(input_num,hidden_size) #从输入到隐藏层的线性处理self.layer2 = nn.Linear(hidden_size,out_put) #从隐藏层到输出层的线性处理def forward(self,x):x = self.layer1(x) #输入层到隐藏层的线性计算x = torch.relu(x) #隐藏层激活x = self.layer2(x) #输出层,注意,输出层直接接lossreturn xnet = Neural_net(input_size,hidden_size,num_classes)
print(net)
Neural_net((layer1): Linear(in_features=784, out_features=500, bias=True)(layer2): Linear(in_features=500, out_features=10, bias=True)
)

 super(Neural_net, self).init() 是 Python 中用于调用父类的方法或属性的一种方式。在这里,Neural_net 是你定义的神经网络模型的类名,它继承了 nn.Module 类,而 nn.Module 是 PyTorch 中用于构建神经网络模型的基类。也就是说,你的神经网络模型会继承 nn.Module 的所有属性和方法,这样你可以在 Neural_net 类中使用 nn.Module 中定义的各种功能,比如添加神经网络层、指定损失函数等。

三、训练模型

只有要注意一下Variable,之前的文章中又提到过Variable。

Variable是PyTorch早期版本(0.4版本之前)中用于构建计算图的抽象,它包含了data、grad和grad_fn等属性,可以用于构建计算图,并在反向传播时自动计算梯度。但从PyTorch 0.4版本开始,Variable被官方废弃,而Tensor直接支持了自动求导功能,不再需要显式地创建Variable。

因此,Autograd是PyTorch实现自动求导的核心机制,而Variable是早期版本中用于构建计算图的一种抽象,现在已经被Tensor所取代。 Autograd会自动追踪Tensor上的操作,并在需要时计算梯度,从而实现反向传播。

#optimization
import numpy as np
from torchvision import transformslearning_rate = 1e-3 #学习率
num_epoches = 5
criterion =nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(net.parameters(),lr = learning_rate) #随机梯度下降for epoch in range(num_epoches):print('current epoch = %d' % epoch)for i ,(images,labels) in enumerate(train_loader,0):images=images.view(-1,28*28)outputs = net(images) #将数据集传入网络做前向计算labels = torch.tensor(labels, dtype=torch.long)loss = criterion(outputs, labels) #计算lossoptimizer.zero_grad() #在做反向传播之前先清楚下网络状态loss.backward() #Loss反向传播optimizer.step() #更新参数if i % 100 == 0:print('current loss = %.5f' % loss.item())print('finished training')

 

current epoch = 1
current loss = 0.27720
current loss = 0.23612
current loss = 0.39341
current loss = 0.24683
current loss = 0.18913
current loss = 0.31647
current loss = 0.28518
current loss = 0.18053
current loss = 0.34957
current loss = 0.31319
current epoch = 2
current loss = 0.15138
current loss = 0.30887
current loss = 0.24257
current loss = 0.46326
current loss = 0.30790
current loss = 0.17516
current loss = 0.32319
current loss = 0.32325
current loss = 0.32066
current loss = 0.24271

 四、准确度测试

各层的权重通过随机梯度下降法更新Loss之后,针对测试集数字分类的准确率:

#prediction
total = 0
correct =0 
acc_list_test = []
for images,labels in test_loader:images=images.view(-1,28*28)outputs = net(images) #将数据集传入网络做前向计算_,predicts = torch.max(outputs.data,1)total += labels.size(0)correct += (predicts == labels).sum()acc_list_test.append(100 * correct / total)print('Accuracy = %.2f'%(100 * correct / total))
plt.plot(acc_list_test)
plt.xlabel('Epoch')
plt.ylabel('Accuracy On TestSet')
plt.show()

 

 

点关注,防走丢,如有纰漏之处,请留言指教,非常感谢

以上就是本期全部内容。我是fanstuck ,有问题大家随时留言讨论 ,我们下期见。


http://www.lryc.cn/news/171959.html

相关文章:

  • 【计算机网络】深入理解TCP协议二(连接管理机制、WAIT_TIME、滑动窗口、流量控制、拥塞控制)
  • springboot整合sentinel完成限流
  • signal(SIGPIPE, SIG_IGN)
  • GAN学习笔记
  • layui框架学习(45: 工具集模块)
  • 车道检测:Decoupling the Curve Modeling and Pavement Regression for Lane Detection
  • 【扩散生成模型】Diffusion Generative Models
  • 美联储加息步伐“暂停”!BTC凌晨力守27000美元!
  • 微信小程序与idea后端如何进行数据交互
  • Java 学习路线分享 maven 是什么?
  • 实战演练 | Navicat 常用功能之转储与运行 SQL 文件
  • MySQL的备份与恢复
  • Python中的函数未定义的错误
  • AG35学习笔记(二):安装编译SDK、CMakeLists编译app、Scons编译server
  • 多台服务器sessionId共享
  • 如何在Gazebo中实现多机器人编队仿真
  • 迅为iTOP-iMX6QPLUS-Android6.0下uboot添加网卡驱动
  • sql server 触发器的使用
  • 使用亚马逊云服务器在 G4 实例上运行 Android 应用程序
  • Direct3D融合技术
  • 【计算机网络】信号处理接口 Signal API(1)
  • 贝叶斯滤波计算4d毫米波聚类目标动静属性
  • 华为hcie认证考试怎么考?
  • vue +element 删除按钮操作 (删除单个数据 +删除页码处理 )
  • 更新GitLab上的项目
  • K8S群集调度
  • 完美解决Echarts X坐标轴下方文字最后一个字体加粗颜色加深的问题
  • WebGL 计算平行光、环境光下的漫反射光颜色
  • 解决SpringMVC在JSP页面取不到ModelAndView中数据
  • Spring 6.0 新特性