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 代码实现 实验结果 消融实验 可视化 结论 🚀🚀🚀订阅专栏,更新及时查…

PHP接口代码-在线实名认证-身份实名认证

在我国,身份证是证明身份的证件,我们在生活、工作中都会用到。一般入职一个新公司的时候人事部门的工作人员会让入职人员提供身份证,一是帮员工办理社保等业务和员工档案用,另外还可以用来验证身份。现在科技发达,不仅…

开发充电桩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 批量处理数据时…

百度智能云发布会定档3月21日,新模型ERNIE Speed已悄然上线

正文 百度智能云官微日前宣布,百度智能云千帆产品发布会(AI Cloud Day)将于2024年3月21日在北京举行,届时将揭晓千帆ModelBuilder 和 AppBuilder 的最新产品进展,并发布系列新模型及开发工具组件。 记者在百度智能云…

最新的前端开发技术(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 进去后是这样的 点击这里 下滑找到对应版本下载即可 好了就这样 别被割韭菜了

AI自然语言中默认上下文长度4K 几K是什么意思?

环境: 4K 问题描述: AI自然语言中默认上下文长度4K 几K是什么意思? 解决方案: 在自然语言处理中,“k” 表示 “千”,是一种简写方式。当我们说 “4k” 时,实际上指的是 “4,000”。在上下文…

微服务架构 | 实战常见数据

INFDEX 压测参考值(180C)线程池Qps/Tps 压测参考值(180C) 时长TPSTPS极限TP性能TP极限并发CPU负载一般接口5min500200050/100ms120ms1->10/3040%缓存接口5min5000200007/20ms10/25ms1->2/440%一般写接口关键写接口 线程池…

3月6日做题总结(C/C++真题)

星光不负赶路人,时光不负追梦人!多一份努力,多一份成功的机会! 第一题 int a, b, x, i; a 3; b 4; i 3; x a > b ? i : i--; x的值为() A---2 B---3 C---4 D---5 正确答案:B 解…

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

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

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

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

Rust 库是如何根据 features 实现相关 Trait 的?

看下面配置文件中的依赖库说明: [dependencies] serde { version "1", features ["derive"] } serde_json "1" chrono { version "0.4", features ["serde"] }serde 是如何实现 derive 相关 Trait 的&…