Pytorch入门实战 P1-实现手写数字识别

目录

一、前期准备(环境+数据)

1、首先查看我们电脑的配置;

2、使用datasets导入MNIST数据集

3、使用dataloader加载数据集

4、数据可视化

二、构建简单的CNN网络

三、训练模型

1、设置超参数

2、编写训练函数

3、编写测试函数

4、正式训练

四、结果可视化


  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍖 原作者:K同学啊 | 接辅导、项目定制

一、前期准备(环境+数据)

编辑器:Pycharm

环境语言:python、pytorch

1、首先查看我们电脑的配置;

即:看看我们电脑是CPU版本还是GPU的。

import torch
torch.cuda.is_available()# 返回 False,则是CPU版本;反之是GPU版本

查看自己的电脑配置后,一般写代码的时候,只需要看是CPU或GPU,然后根据不同的版本运行代码。一般我们会选择使用判断语句这样写:

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)

不懂得torch.device() 的,我把官网附在下面了。 

2、使用datasets导入MNIST数据集

本文中,我们主要用来实现手写数字的识别,因此,我们得先得到手写数字数据集,即MNIST数据集。

【MNIST数据集背景介绍】:

        手写数据集,如MNIST,是一个经典的机器学习数据集,主要用于手写数字识别。

        这个数据集包含了来自250个不同的人手写数字图片,其中50%是学生,50%来自人口普查局的工作人员。训练集一共包含了60,000张图像和标签,而测试集一共包含了10,000张图像和标签。测试集中前5000个来自最初NIST项目的训练集,后5000个来自最初MNIST项目的测试集。前5000个比后5000个要规整,这是因为前5000个数据来自于美国人口普查局的员工,他们的书写相对更标准,而后5000个来自于大学生,书写风格可能更多样。

        该数据集的收集目的是希望通过算法,实现对手写数字的识别。在手写数字识别分类中,每个样本都是一个28x28像素的灰度图像,表示手写数字0到9。

总的来说,手写数据集为机器学习领域的研究者提供了一个标准化的、大规模的、有挑战性的数据集,有助于推动手写数字识别等相关技术的发展。


【导入MNIST数据集】:

首先,使用datasets下载MNIST数据,并划分好训练集和测试集。

import torchvision # 训练集数据train_ds = torchvision.datasets.MNIST('data',train=True,transform=torchvision.transforms.ToTensor(),download=True)
# 测试集数据
test_ds = torchvisio.datasets.MNIST('data',train=False,transform=torchvision.transforms.ToTensor(),download=True)

我们先来看下原型:

torchvision.datastes.MNIST( root,train=True, transform=None, download=False)

其中:

        root是要把下载的数据集存入的文件夹的名字。

        train:True表示是训练集;False表示是测试集;

        transform: 这里的参数,选择一个你想要的数据转换函数,直接完成数据转化。

        download:True 从互联网上下载数据集,并把数据集放在root目录下。


下载完成后的目录是这样的:(如果已经下载一次了,后续就可以把download改为False,不然每次运行都会下载

3、使用dataloader加载数据集

使用dataloader加载数据集,并设置好基本的batch_size。

import torch batch_size = 32   # 每批加载样本的大小# 加载训练集数据
train_dl = torch.utils.data.DataLoader(train_ds,batch_size=batch_size,shuffle=True)   # 每个epoch重新排列数据# 加载测试集数据
test_dl = torch.utils.data.DataLoader(test_ds,batch_size=batch_size)

我们可以取一个批次查看下数据的格式:

imgs,labels = next(iter(train_dl))print(imgs.shape)   # 得到结果是   torch.Size([32,1,28,28])

其中:我们得到的数据的shape位:[batch_size , channel, height, weight]

                batch_size :是我们自己设置的(上面的代码中有设置过)

                channel: 通道数  (黑白图像一般的通道数为1;RGB格式图像的通道数为:3)

                height: 图片的高度

                weight: 图片的宽度

train_dl 就是我们上面的使用dataloader加载的训练集的数据。

iter(train_dl) 将数据加载器转换为一个迭代器(iterator),使得我们可以使用Python的next()函数来逐个访问数据加载器中的元素。

next()  函数用于获取迭代器中的下一个元素。这里,它被用来获取train_dl中的下一批量数据。


4、数据可视化

数据可视化,就是使用代码展示下,我们上面获取的数据(获取20个数字的图片)。

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.cn.binary)  # 展示图片,以cmap给的色彩展示plt.axis('off')  # 关闭坐标轴
plt.show()  # 展示图片

 运行结果展示:


至此,我们的前期准备工作准备结束。我们即将进入第二部分!!!

二、构建简单的CNN网络

我们现在简单看下上面这个图,上图里面是一个简单的CNN网络图。

依次包括:输入层、卷积层1、池化层1、卷积层2、池化层2、全连接层1、全连接层2、全连接层3、输出层。 

对于一般的CNN网络来说,都是由【特征网络】和【分类网络】构成的。

①nn.Conv2d  为卷积层,用于提取图片的特征,传入参数为:input_channel、out_channel、kernal_size;

②nn.MaxPool2d 为池化层,进行下采样,更高层的抽象表示图像特征,传入参数为:kernal_size

③nn.ReLU 为激活函数,使得模型可以拟合非线性数据。

④nn.Squential 可以按构造顺序连接网络,在初始化阶段就设定好网络结构,不需要在前向传播中重新写一遍。


下面的代码,我们以这个图为例,两层卷积、两层池化、全连接层。

num_classes = 10   # 图片的类别数class Model(nn.Module):def __init__(self):super().__init__()# 特征提取网络self.conv1 = nn.Conv2d(1, 32, kernel_size=3)   # 输入图像的通道数、输出图像的通道数、卷积核大小  (RGB图像的输入通道数为3)self.pool1 = nn.MaxPool2d(2)                    # 设置池化层,池化核大小为2*2self.conv2 = nn.Conv2d(32, 64, kernel_size=3)   # 第二层卷积,卷积核大小为3*3self.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)
print(model)
print("查看模型信息:")
summary(model)

​​​​​​​

这个步骤很重要,这块就是我们一般修改模型的地方。如果是写论文的话,这里是很重要的。因为是刚开始学习,就先能大概了解就行,后续我还会继续学习的。也会多多更新这里的。

三、训练模型

我们现在已经构建好了CNN的网络模型,那么就开始设置一些参数训练模型吧。

1、设置超参数

loss_fn = nn.CrossEntropyLoss()  # 创建损失函数
learn_rate = 1e-1  # 学习率
opt = torch.optim.SGD(model.parameters(), lr=learn_rate)

2、编写训练函数

'''1、optimizer.zero_grad() 函数会遍历模型的所有参数,通过内置方法截断反向传播的梯度流,再将每个参数的梯度值设为0,即上次的梯度记录会被清空。2、loss.backward() Pytorch的反向传播(即:tensor.backward())是通过autograd包来实现的,autograd包会根据tensor进行过的数学运算来自动计算其对应的梯度。3、optimizer.step()  step() 函数的作用是执行一次优化步骤,通过梯度下降法来更新参数的值。因为梯度下降是基于梯度的,所以在执行optimizer.step() 函数前应先指向那个loss.backward()函数来计算梯度。
'''# 训练循环
print('准备进入----训练集里面')def train(dataloader, model, loss_fn, optimizer):size = len(dataloader.dataset)  # 训练集的大小,一共60000张图片num_batches = len(dataloader)  # 批次数目,1875(60000/32)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)  # 计算网络输出和真实值之间的差距,targets为真实值,计算二者差值,即为损失。# 反向传播   (以下三个基本上是固定的)optimizer.zero_grad()  # grade属性归零loss.backward()  # 反向传播optimizer.step()  # 每一步自动更新# 记录acc与losstrain_acc += (pred.argmax(1) == y).type(torch.float).sum().item()  # 表示计算预测正确的样本数量,并将其作为一个标量值返回。这通常用于评估分类模型的准确率或计算分类问题的正确预测数量。'''pred.argmax(1)返回数组pred在第一个轴(即行)上最大值所在的索引。这通常用于多分类问题中,其中pred是一个包含预测概率的二维数组,每行表示一个样本的预测概率分布。pred.argmax(1) == y是一个布尔值,其中等号是否成立代表对应样本的预测是否正确。(True表示正确,False表示错误).type(torch.float)是将布尔数组的数据类型转换为浮点数类型,即将True转换为1.0;将False转换为0.0.sum() 是对数组中的元素进行求和,计算出预测正确的样本数量。.item() 将求和结果转换为标量值,以便在Python中使用或打印。'''train_loss += loss.item()train_acc /= sizetrain_loss /= num_batchesreturn train_acc, train_loss

3、编写测试函数

测试函数、训练函数大致相同,但是由于不进行梯度下降对网络权重进行更新,所以不需要传入优化器。
def test(dataloader, model, loss_fn):size = len(dataloader.dataset)  # 测试集的大小,一共10000张图片num_batches = len(dataloader)  # 批次数目313 (10000/32=321.5 向上取整)test_loss, test_acc = 0, 0# 当不进行训练时,停止梯度更新,节省计算内存消耗with torch.no_grad():for imgs, target in dataloader:imgs, target = imgs.to(device), target.to(device)# 计算losstarget_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()test_acc /= sizetest_loss /= num_batchesreturn test_acc, test_loss

4、正式训练

epochs = 5
train_loss = []
train_acc = []
test_loss = []
test_acc = []for epoch in range(epochs):  # epoch 索引值model.train()  # 启用Batch Normalization和Dropout'''如果模型中有BN(Batch Normalization)和Dropout ,需要在训练时添加model.train() 。 model.train() 是保证BN层能够用到每一批数据的均值和方差。对于Dropout ,model.train() 是随机取一部分网络连接来训练更新参数。'''epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, opt)model.eval()  # 不启用Batch Normalization 和Dropout'''如果模型中有BN(Batch Normalization)和Dropout ,需要在测试时添加model.eval() . model.eval() 是保证BN层能够用全部训练数据的均值和方差,即:测试过程中要保证BN层的均值和方差不变。对于Dropout, model.eval() 是利用到了所有网络连接,即:不进行随机舍弃神经元。训练完train样本后,生成的模型model要用来测试样本。在model(test)之前,需要加上model.eval(),否则的话,有输入数据,即使不训练,它也会改变权值。这是model中还有BN层和Dropout所带来的性质。'''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')

四、结果可视化

结果可视化,主要使用的是import matplotlib.pyplot as plt 的绘图。

warnings.filterwarnings('ignore')  # 忽略警告信息
# plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rc('font', family='PingFang HK')
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
plt.rcParams['figure.dpi'] = 100  # 分辨率epochs_range = range(epochs)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='Train Loss')
plt.plot(epochs_range, test_loss, label="Test Loss")
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

上述我们已经先开始训练模型了,正式训练模型,我们会得到很多数据,因此,我们要用一些可视化工具来清晰的展示,我们得到的数据,看看训练数据和测试数据会有哪些差异呢。

由于我本地电脑跑起来,风扇呼呼响。这里我用的是谷歌提供的免费的 工具跑的代码,训练数据共花费3分钟左右。


至此,我们使用Pytorch完成了手写数字识别,也算是一个简单的基础入门实战啦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/727206.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

子事务的应用

子事务的应用 1. 为什么要使用子事务? 为了防止接口执行失败时,导致事务回滚,接口日志记录不到日志表里面,因而将记录日志表的方法写成子事务的方法。 2. 怎么使用子事务? 在方法名后面加上“_RequiresNew”&#xff…

文物藏品信息管理系统的优势

本系统支持一普标准所有管理信息,包括保管信息、基本情况、鉴定信息、考古发掘信息、来源信息、流传经历、损坏记录、移动记录、修复记录、展览信息、著录信息、收藏单位信息等的管理和维护。 能够实现对藏品信息进行动态管理,提供藏品信息管理指标的维护…

《人工智能怎么学》荣获2023年吴文俊人工智能科学技术奖及赠书活动

中国人工智能学会官网(www.caai.cn)近日正式公布了2023年吴文俊科学技术奖获奖名单,图书《人工智能怎么学》项目被授予2023年吴文俊人工智能科学技术奖科技进步奖(科普项目)。2023年吴文俊科学技术奖完整获奖名单见htt…

YOLOv8官方仓库更新,添加YOLOv9模型

目录 🚀🚀🚀订阅专栏,更新及时查看不迷路🚀🚀🚀 摘要 PGI&GELAN 代码实现 实验结果 消融实验 可视化 结论 🚀🚀🚀订阅专栏,更新及时查…

开发充电桩APP提高管理效能

随着社会的发展,电动车已经成为城市交通的重要组成部分,用户所下载的充电类的APP也非常大,而充电桩的建设和利用效率成为了一个亟待解决的问题。在这个背景下,物联网技术的应用成为了提高充电桩效能的关键。虎克技术公司在此领域提…

CyberChef加密解密RSA、AES中文乱码问题有效解决办法

一、AES加密 AES的ECB模式加密,秘钥:1234567812345678 加密效果与utf-8本地加密一致 二、AES解密 AES的ECB模式解密,秘钥:1234567812345678 同理RSA加密设置一样

[C语言]——分支和循环(4)

目录 一.随机数生成 1.rand 2.srand 3.time 4.设置随机数的范围 猜数字游戏实现 写⼀个猜数字游戏 游戏要求: (1)电脑自动生成1~100的随机数 (2)玩家猜数字,猜数字的过程中,根据猜测数据的⼤…

【notepad++工具使用之】批量加逗号

背景 在使用sql语句in关键字查询时,我们需要把数据用逗号进行隔开,在数据量非常少的时候(十几二十个这样),可以手动的去加逗号分隔符; 但是遇到1000个怎么弄呢? 强大的Notepad 批量处理数据时…

最新的前端开发技术(2024年)

关于作者: 还是大剑师兰特:曾是美国某知名大学计算机专业研究生,现为航空航海领域高级前端工程师;CSDN知名博主,GIS领域优质创作者,深耕openlayers、leaflet、mapbox、cesium,canvas&#xff0…

如何实现数据中心布线变更管理?

前言 随着科技的不断发展,数据中心作为企业的核心基础设施之一,承载着大量重要的业务数据。在数据中心运维过程中,变更管理流程变得尤为重要,它是确保数据中心基础设施稳定运行和保障数据安全的关键环节。变更管理的定义是指在维…

【开源】SpringBoot框架开发快乐贩卖馆管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 搞笑视频模块2.3 视频收藏模块2.4 视频评分模块2.5 视频交易模块2.6 视频好友模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 搞笑视频表3.2.2 视频收藏表3.2.3 视频评分表3.2.4 视频交易表 四、系…

ue WebUI插件下载官方Github方法

首先要先将EPIC账号绑定Github账号 这个网上有很多教程 我就不细说了 绑定以后点击这个链接 https://github.com/tracerinteractive/UnrealEngine 进去后是这样的 点击这里 下滑找到对应版本下载即可 好了就这样 别被割韭菜了

【射频连接器】SMB/SMC 同轴连接器

阻抗为 50 欧姆的 Connex SMB/SMC 超小型同轴连接器适用于 4 GHz (SMB) 或 10 GHz (SMC) 的应用。这些连接器通常比 SMA 便宜,主要用于微波电话和其他非国防电信要求的应用。 SMB 连接器具有快速连接/断开卡扣式配接功…

LoadRunner VS RunnerGo:主流性能测试工具对比谁更胜一筹?

LoadRunner作为性能测试工具的开拓者,测试人员应该都听过,可能也用过,相比较后起之秀Jmeter,使用场景更趋于企业级的性能测试,不太适合个人使用。 RunnerGo呢,是一款基于Go语言、国产自研的测试平台。它支…

宠物空气净化器值得入手吗?选购宠物空气净化器关注哪些方面?

一开始养猫时,每天看着可爱的猫咪在家里快乐奔跑,让人心情愉悦。然而,作为铲屎官都知道,猫咪会掉毛,特别是在换毛期间,地板、沙发上都会有一大堆猫毛,甚至衣服也可能沾满猫毛。养猫家庭中&#…

宠物空气净化器值得不值得买?各品牌宠物空气净化器怎么选?

随着越来越多的家庭选择养宠物,我们也面临着宠物环境卫生和家庭生活舒适度的问题。根据一项调查显示,有70%的养猫家庭中的铲屎官曾经遭受过猫藓或猫毛过敏、鼻炎等问题的困扰。尤其是对于家中有老人、小孩和孕妇等免疫力较低的人来说,他们的抵…

2024/3/7打卡公共子序列---动态规划问题

题目: 给定两个长度分别为 N 和 M 的字符串 A 和 B,求既是 A 的子序列又是 B 的子序列的字符串长度最长是多少。 输入格式 第一行包含两个整数 N 和 M。 第二行包含一个长度为 N 的字符串,表示字符串 A。 第三行包含一个长度为 M 的字符串&am…

高质量的外贸开发信标题都是怎样的?

今天在网上看到很多不错的开发信标题,觉得不错,收藏起来分享给大家学习。 标题是吸引读者打开邮件的第一印象,对于外贸销售人员来说,精心撰写开发信标题至关重要。客户收到的邮件那么多,那么在客户收件箱中的5至20个客…

几个市场主流伦敦银交易系统简介

很多人在伦敦银交易中都希望建立一个交易系统,依靠这个系统,我们在市场中能够建立稳定盈利的基础。下面我们就来简单地介绍几个市场主流的伦敦银交易系统。 均线交易系统。这是很多人使用的伦敦银交易系统,一般适用于趋势行情中。均线交易系统…

如何定期跟踪和评估OKR的进度

设定跟踪周期 根据公司的实际情况和需要,设定合适的OKR跟踪周期。这个周期可以是每周、每月或每季度,以便及时了解OKR的进展情况。 使用进度图表 利用进度图表来可视化OKR的完成情况。这可以帮助团队更直观地了解目标的进度和剩余任务量,以…