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.hqwc.cn/news/518948.html

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

相关文章

网络原理初识(2)

目录 一、协议分层 1、分层的作用 2、OSI七层模型 3、TCP / IP五层(或四层)模型 4、网络设备所在分层 5、网络分层对应 二、封装和分用 发送过程(封装) 1、应用层(应用程序) QQ 2、输入层 3、网络层 4、数据链路层 5、物理…

riscv 栈空间静态分析

分析riscv架构的裸机代码中最大栈空间 riscv的基本过程调用标准 1.函数前8个参数用a0~a7传输 2.超过8个的参数使用栈传递 3.函数返回参数到a0,a1寄存器中,返回值保存在ra寄存器中 4.如果子函数有使用s0-s11寄存器,那么在使用前需要将这些寄存器的内…

python并发编程:阻塞IO

阻塞IO(blocking IO) 在Linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样: 当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据。对于…

在多文件编译时,如果模板类的成员函数的定义和模板类不在一个文件下会怎么样?

编译器将找不到成员函数的定义,哪怕你将存放成员函数定义的test.cpp一块编译,编译器也无法找到该模板类的成员函数的定义。 正确的做法是: 将模板类的声明和成员函数定义都定义在.h文件下

如何在Linux中安装ARM交叉环境编译链

安装ARM交叉环境编译链过程如下: 首先创建一个文件夹如下: mkdir -p Linux_ALPHA/toolcahin然后将arm交叉编译工具链安装包拖到Linux中如下: 先输入mv 拖入的安装包即可 mv /var/run/vmblock-fuse/blockdir/pXeysK/gcc-4.6.4.tar.xz .直接…

linux命令行或桌面 显卡压力测试

windows下的压力测试非常简单,有很多图形化的测试工具 在github上找到一个项目:github链接 1.下载工具 cd /usr/localgit clone https://github.com/wilicc/gpu-burn如果没有安装git,则先安装 apt-get install git2.安装 cd /usr/local/…

1. Gin框架入门

文章目录 一、Gin框架介绍二、RESTful API三、Gin渲染1. HTML渲染2. 自定义模板函数3. 静态文件处理4. 使用模板继承5. 补充文件路径处理6. JSON渲染7. XML渲染8. YMAL渲染9. protobuf渲染 四、Gin获取各种方式传递过来的参数1、获取querystring参数2、获取form参数3、获取path…

网络学习:Vlan基础知识、划分思路及其优越性

目录 一、VLAN基础知识 二、VLAN的划分方法 1. 基于端口划分的VLAN 2. 基于MAC地址划分VLAN 3. 基于网络层协议划分VLAN 4. 根据IP组播划分VLAN 5. 按策略划分VLAN 6. 按用户定义、非用户授权划分VLAN 三、VLAN的优越性 1. 增加了网络连接的灵活性 2. 控制网络上的广…

老杜Mybatis笔记

https://www.yuque.com/zuihoudewu/java_note/mt2812?singleDoc#《老杜MyBatis--原版》

redis缓存更新策略

更新缓存策略: 对于低一致性需求的业务:使用redis自带的内存淘汰机制就行了,自动失效,等查询时再更新。 对于高一致性需求的业务:推荐主动更新,由缓存的调用者更新数据库的同时更新缓存(删除缓存)。 这里的…

K倍区间 刷题笔记

法一 前缀和暴力搜索 &#xff08;数据大会超时&#xff09; #include<iostream> #include<cstring> #include<algorithm> #include<cstdio> using namespace std; const int N100010; int a[N],s[N]; int n,k; int main(){ cin>>n>>…

Python算法题集_搜索插入位置

Python算法题集_搜索插入位置 题51&#xff1a;搜索插入位置1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【二分法查找】2) 改进版一【二分法查找终止条件判断】3) 改进版二【第三方模块】 4. 最优算法5. 相关资源 本文为Python算法题集之一的…