包头有没有专业做淘宝网站的,电子网址怎么创建,平台优化是指什么,免费培训网站#x1f368; 本文为#x1f517;365天深度学习训练营 中的学习记录博客#x1f356; 原作者#xff1a;K同学啊 | 接辅导、项目定制 文章目录 前言1 我的环境2 代码实现与执行结果2.1 前期准备2.1.1 引入库2.1.2 设置GPU#xff08;如果设备上支持GPU就使用GPU,否则使用C… 本文为365天深度学习训练营 中的学习记录博客 原作者K同学啊 | 接辅导、项目定制 文章目录 前言1 我的环境2 代码实现与执行结果2.1 前期准备2.1.1 引入库2.1.2 设置GPU如果设备上支持GPU就使用GPU,否则使用CPU2.1.3 导入数据2.1.4 查看数据2.1.5.数据可视化 2.2 构建CNN网络模型2.3 训练模型2.3.1 训练模型2.3.2 编写训练函数2.3.3 编写测试函数2.3.4 正式训练 2.4 结果可视化 3 知识点详解3.1 MNIST手写数字数据集介绍3.2 Torch.NN简介3.2.1nn.Module模块概述3.2.2 Sequential类的概述 3.3【Pytorch】model.train() 和 model.eval() 原理与用法3.3.1 两种模式3.3.2功能3.3.3 总结与对比 总结 前言
本文将采用pytorch框架创建CNN网络实现简单实现mnist手写数字识别。讲述实现代码与执行结果并浅谈涉及知识点。 关键字MNIST手写数字数据集介绍Torch.NN简介Pytorch】model.train() 和 model.eval() 原理与用法。
1 我的环境
电脑系统Windows 11语言环境python 3.8.6编译器pycharm2020.2.3深度学习环境 torch 1.9.1cu111 torchvision 0.10.1cu111显卡NVIDIA GeForce RTX 4070
2 代码实现与执行结果
2.1 前期准备
2.1.1 引入库
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
plt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签
plt.rcParams[axes.unicode_minus] False # 用来正常显示负号
plt.rcParams[figure.dpi] 100 # 分辨率
import torchvision
import numpy as np
from torchinfo import summary
import torch.nn.functional as F
import warningswarnings.filterwarnings(ignore) # 忽略一些warning内容无需打印2.1.2 设置GPU如果设备上支持GPU就使用GPU,否则使用CPU
前期准备-设置GPU-
# 如果设备上支持GPU就使用GPU,否则使用CPU
device torch.device(cuda if torch.cuda.is_available() else cpu)
print(device)输出
cuda2.1.3 导入数据
前期工作-导入数据
train_ds torchvision.datasets.MNIST(data, trainTrue, transformtorchvision.transforms.ToTensor(), # 将数据类型转化为TensordownloadTrue)test_ds torchvision.datasets.MNIST(data, trainFalse, transformtorchvision.transforms.ToTensor(), # 将数据类型转化为TensordownloadTrue)
batch_size 32train_dl torch.utils.data.DataLoader(train_ds, batch_sizebatch_size, shuffleTrue)test_dl torch.utils.data.DataLoader(test_ds, batch_sizebatch_size)2.1.4 查看数据
前期工作-查看数据
# 取一个批次查看数据格式
# 数据的shape为[batch_size, channel, height, weight]
# 其中batch_size为自己设定channelheight和weight分别是图片的通道数高度和宽度。
imgs, labels next(iter(train_dl)) # 通过 iter(train_dl) 创建一个数据迭代器然后使用 next(train_dl) 从训练数据加载一个批次的图像和对应的标签。
# images包含了一批图像labels 包含了这些图像的类别标签。
print(imgs.shape)输出
torch.Size([32, 1, 28, 28])2.1.5.数据可视化
前期工作-数据可视化
# 指定图片大小图像大小为20宽、5高的绘图(单位为英寸inch)
plt.figure(figsize(20, 5))
for i, img in enumerate(imgs[:20]):# 维度缩减去除所有维度为1的维度npimg np.squeeze(img.numpy())# 将整个figure分成2行10列绘制第i1个子图。plt.subplot(2, 10, i 1)plt.imshow(npimg, cmapplt.cm.binary) # 使用matlablib库cm子库中的binary颜色映射讲图像渲染维黑白色plt.axis(off) # 取消坐标轴显示
plt.show() # 如果你使用的是Pycharm编译器请加上这行代码2.2 构建CNN网络模型 构建CNN网络
num_classes 10 # 图片的类别数class Model(nn.Module):def __init__(self):super().__init__()# 特征提取网络self.conv1 nn.Conv2d(1, 32, kernel_size3) # 第一层卷积,卷积核大小为3*3self.pool1 nn.MaxPool2d(2) # 设置池化层池化核大小为2*2self.conv2 nn.Conv2d(32, 64, kernel_size3) # 第二层卷积,卷积核大小为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_dim1)x F.relu(self.fc1(x))x self.fc2(x)return x# 将模型转移到GPU中我们模型运行均在GPU中进行
model Model().to(device)
summary(model)输出 Layer (type:depth-idx) Param #Model --
├─Conv2d: 1-1 320
├─MaxPool2d: 1-2 --
├─Conv2d: 1-3 18,496
├─MaxPool2d: 1-4 --
├─Linear: 1-5 102,464
├─Linear: 1-6 650Total params: 121,930
Trainable params: 121,930
Non-trainable params: 02.3 训练模型
2.3.1 训练模型
训练模型--设置超参数
loss_fn nn.CrossEntropyLoss() # 创建损失函数计算实际输出和真实相差多少交叉熵损失函数事实上它就是做图片分类任务时常用的损失函数
learn_rate 1e-2 # 学习率
opt torch.optim.SGD(model.parameters(), lrlearn_rate) # 作用是定义优化器用来训练时候优化模型参数其中SGD表示随机梯度下降用于控制实际输出y与真实y之间的相差有多大
2.3.2 编写训练函数
训练模型--编写训练函数
# 训练循环
def train(dataloader, model, loss_fn, optimizer):size len(dataloader.dataset) # 训练集的大小一共60000张图片num_batches len(dataloader) # 批次数目187560000/32train_loss, train_acc 0, 0 # 初始化训练损失和正确率for X, y in dataloader: # 加载数据加载器得到里面的 X图片数据和 y真实标签X, y X.to(device), y.to(device) # 用于将数据存到显卡# 计算预测误差pred model(X) # 网络输出loss loss_fn(pred, y) # 计算网络输出和真实值之间的差距targets为真实值计算二者差值即为损失# 反向传播optimizer.zero_grad() # 清空过往梯度loss.backward() # 反向传播计算当前梯度optimizer.step() # 根据梯度更新网络参数# 记录acc与losstrain_acc (pred.argmax(1) y).type(torch.float).sum().item()train_loss loss.item()train_acc / sizetrain_loss / num_batchesreturn train_acc, train_loss2.3.3 编写测试函数
训练模型--编写测试函数
# 测试函数和训练函数大致相同但是由于不进行梯度下降对网络权重进行更新所以不需要传入优化器
def test(dataloader, model, loss_fn):size len(dataloader.dataset) # 测试集的大小一共10000张图片num_batches len(dataloader) # 批次数目31310000/32312.5向上取整test_loss, test_acc 0, 0# 当不进行训练时停止梯度更新节省计算内存消耗with torch.no_grad(): # 测试时模型参数不用更新所以 no_grad整个模型参数正向推就ok不反向更新参数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
2.3.4 正式训练
训练模型--正式训练
epochs 5
train_loss []
train_acc []
test_loss []
test_acc []for epoch in range(epochs):model.train()epoch_train_acc, epoch_train_loss train(train_dl, model, loss_fn, opt)model.eval()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)输出
Epoch: 1, Train_acc:79.5%, Train_loss:0.709, Test_acc:92.7%Test_loss:0.243
Epoch: 2, Train_acc:94.3%, Train_loss:0.188, Test_acc:96.2%Test_loss:0.125
Epoch: 3, Train_acc:96.4%, Train_loss:0.121, Test_acc:97.3%Test_loss:0.088
Epoch: 4, Train_acc:97.2%, Train_loss:0.093, Test_acc:97.6%Test_loss:0.077
Epoch: 5, Train_acc:97.6%, Train_loss:0.078, Test_acc:98.0%Test_loss:0.064
Done2.4 结果可视化
训练模型--结果可视化
epochs_range range(epochs)plt.figure(figsize(12, 3))
plt.subplot(1, 2, 1)plt.plot(epochs_range, train_acc, labelTraining Accuracy)
plt.plot(epochs_range, test_acc, labelTest Accuracy)
plt.legend(loclower right)
plt.title(Training and Validation Accuracy)plt.subplot(1, 2, 2)
plt.plot(epochs_range, train_loss, labelTraining Loss)
plt.plot(epochs_range, test_loss, labelTest Loss)
plt.legend(locupper right)
plt.title(Training and Validation Loss)
plt.show()3 知识点详解
3.1 MNIST手写数字数据集介绍
MNIST手写数字数据集来源于是美国国家标准与技术研究所是著名的公开数据集之一。数据集中的数字图片是由250个不同职业的人纯手写绘制数据集获取的网址为http://yann.lecun.com/exdb/mnist/下载后需解压。我们一般会采用(train_images, train_labels), (test_images, test_labels) datasets.mnist.load_data()这行代码直接调用这样就比较简单MNIST手写数字数据集中包含了70000张图片其中60000张为训练数据10000为测试数据70000张图片均是2828如果我们把每一张图片中的像素转换为向量则得到长度为2828784的向量。因此我们可以把训练集看成是一个[60000,784]的张量第一个维度表示图片的索引第二个维度表示每张图片中的像素点。而图片里的每个像素点的值介于0-1之间。 在pytorch下可以直接调用torchvision.datasets里面的MNIST数据集这是官方写好的数据集类
train torchvision.datasets.MNIST(root./data/,trainTrue, transform transforms.ToTensor())作用 从 torchvision 中加载 MNIST 数据集的训练集 参数
root‘./data’: 数据集将被下载并保存在当前工作目录下的 ‘data’ 子目录中trainTrue: 加载训练集downloadTrue: 如果数据集不存在则下载数据集transformtransforms.ToTensor(): #接收PIL图片并返回转换后版本图片的转换函数这里为将图像转换为 PyTorch 的 Tensor 格式 返回值为一个元组train_data,train_target)(这个类使用的时候也有坑必须用train[i]索引才能使用 transform功能)一般是与torch.utils.data.DataLoader配合使用
dataloader DataLoader(train, batch_size50,shuffleTrue, num_workers4)
for step, (x, y) in enumerate(dataloader):b_x x.shapeb_y y.shapeprint Step: , step, | train_data的维度 ,b_x,| train_target的维度,b_y作用 创建一个 DataLoader 对象用于对数据进行批量加载和处理 参数
trainset: 要加载的数据集batch_size4: 每个批次包含的图像样本数量shuffleTrue: 打乱数据以便在每个 epoch 中随机访问样本num_workers4并行处理数
3.2 Torch.NN简介
torch.nn 是 PyTorch 中用于构建神经网络的模块。它提供了一组类和函数用于定义、训练和评估神经网络模型。 torch.nn 模块的核心是 nn.Module 类它是所有神经网络模型的基类。在Containers中通过继承 nn.Module 类您可以创建自己的神经网络模型并定义模型的结构和操作。 以下是 torch.nn 模块中常用的一些类和函数
nn.Linear: 线性层用于定义全连接层可以起到特征提取器的作用最后一层的全连接层也可以认为是输出层传入参数为输入特征数和输出特征数输入特征数由特征提取网络计算得到如果不会计算可以直接运行网络报错中会提示输入特征数的大小下方网络中第一个全连接层的输入特征数为1600。nn.Conv2d: 二维卷积层用于处理图像数据。nn.ReLU: ReLU 激活函数。nn.Sigmoid: Sigmoid 激活函数。nn.Dropout: Dropout 层用于正则化和防止过拟合。nn.CrossEntropyLoss: 交叉熵损失函数通常用于多类别分类问题。nn.MSELoss: 均方误差损失函数通常用于回归问题。nn.Sequential: 顺序容器用于按顺序组合多个层在初始化阶段就设定好网络结构不需要在前向传播中重新写一遍。 使用 torch.nn 模块您可以创建自定义的神经网络模型并使用 PyTorch 提供的优化器如 torch.optim和损失函数来训练和优化模型。
3.2.1nn.Module模块概述
nn.Module类的基本定义 在定义自已的网络的时候需要继承nn.Module类并重新实现构造函数__init__()和forward这两个方法。在构造函数__init__()中使用super(Model, self).init()来调用父类的构造函数forward方法是必须要重写的它是实现模型的功能实现各个层之间的连接关系的核心。 1.一般把网络中具有可学习参数的层如全连接层、卷积层放在构造函数__init__()中。 2.一般把不具有可学习参数的层(如ReLU、dropout)可放在构造函数中也可不放在构造函数中(在forward中使用nn.functional来调用)。 示例1将具有可学习参数层和不具有可学习参数层均放在构造函数中
import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module):def __init__(self):super(Model, self).__init__() # 调用父类的构造函数self.con2v nn.Conv2d(1, 3, 3, 1)self.relu nn.ReLU()self.max_pooling nn.MaxPool2d(2, 1)def forward(self, x):x self.con2v(x)x self.relu(x)x self.max_pooling(x)return x
model Model()
print(model)可看到输出的模型结构
Model((con2v): Conv2d(1, 3, kernel_size(3, 3), stride(1, 1))(relu): ReLU()(max_pooling): MaxPool2d(kernel_size2, stride1, padding0, dilation1, ceil_modeFalse)
)示例2把不具有可学习参数的层不放在构造函数中(在forward中使用nn.functional调用
import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module):def __init__(self):super(Model, self).__init__() # 调用父类的构造函数self.con2v nn.Conv2d(1, 3, 3, 1)self.max_pooling nn.MaxPool2d(2, 1)def forward(self, x):x self.con2v(x)x F.relu(x)x self.max_pooling(x)return x
model Model()
print(model)可看到输出的模型结构
Model((con2v): Conv2d(1, 3, kernel_size(3, 3), stride(1, 1))(max_pooling): MaxPool2d(kernel_size2, stride1, padding0, dilation1, ceil_modeFalse)
)由此可看出不具有可学习参数层没有放在构造函数里面那么这些层就不会出现在model中。 也就是在构造函数__init__()中只是定义了模型的结构而在forward方法中实现了模型中的所有层的连接。 3.只要在nn.Module中定义了forward函数backward函数就会被自动实现利用Autograd)。而且一般不是显式的调用forward(layer.forward), 而是layer(input), 会自执行forward()。
3.2.2 Sequential类的概述
nn.Sequential的定义:一个有顺序容器神经网络模块将按照构造函数中传递的顺序添加到该容器中。此外也可以传入一个有序的模块字典。
Sequenrial类实现了整数索引每一个层是没有名称的默认是以0、1、2…这样的index来命名,可以使用model[index]这样的方式获取一个层并不能够通过名称(如model[“Conv2d”])来获取层。 示例如下
import torch.nn as nn
class Model(nn.Module):def __init__(self):super(Model, self).__init__() # 调用父类的构造函数self.model1 nn.Sequential(nn.Conv2d(1, 3, 3, 1),nn.ReLU(),nn.Conv2d(3, 9, 3, 1),nn.MaxPool2d(2, 1))def forward(self, x):x self.struct(x)return x
model Model()
print(model)
print(model.model1[2]) # 通过索引获取第几个层 输出结果
Model((model1): Sequential((0): Conv2d(1, 3, kernel_size(3, 3), stride(1, 1))(1): ReLU()(2): Conv2d(3, 9, kernel_size(3, 3), stride(1, 1))(3): MaxPool2d(kernel_size2, stride1, padding0, dilation1, ceil_modeFalse))
)
Conv2d(3, 9, kernel_size(3, 3), stride(1, 1))Sequential的三种包装方式 示例如下
import torch.nn as nn
from collections import OrderedDict
class Model(nn.Module):def __init__(self):super(Model, self).__init__() # 调用父类的构造函数self.model1 nn.Sequential( # 方式一nn.Conv2d(1, 3, 3, 1),nn.ReLU())self.model2 nn.Sequential( # 方式二OrderedDict([(conv1, nn.Conv2d(1, 3, 3, 1)),(relu1, nn.ReLU())]))self.model3 nn.Sequential() # 方式三self.model3.add_module(conv1, nn.Conv2d(1, 3, 3, 1)),self.model3.add_module(relu1, nn.ReLU())def forward(self, x):x self.model1(x)x self.model2(x)x self.model3(x)return x
model Model()
print(model) 输出结果
Model((model1): Sequential((0): Conv2d(1, 3, kernel_size(3, 3), stride(1, 1))(1): ReLU())(model2): Sequential((conv1): Conv2d(1, 3, kernel_size(3, 3), stride(1, 1))(relu1): ReLU())(model3): Sequential((conv1): Conv2d(1, 3, kernel_size(3, 3), stride(1, 1))(relu1): ReLU())
)参考链接 nn.Module模块概述 神经网络的基本框架的搭建-nn.Module
3.3【Pytorch】model.train() 和 model.eval() 原理与用法
3.3.1 两种模式
pytorch可以给我们提供两种方式来切换训练和评估(推断)的模式分别是model.train() 和 model.eval()。 一般用法是在训练开始之前写上 model.trian() 在测试时写上 model.eval() 。
3.3.2功能
1. model.train() 在使用 pytorch 构建神经网络的时候训练过程中会在程序上方添加一句model.train()作用是 启用 batch normalization 和 dropout 。 如果模型中有BN层Batch Normalization和 Dropout 需要在 训练时 添加 model.train()。 model.train() 是保证 BN 层能够用到 每一批数据 的均值和方差。对于 Dropoutmodel.train() 是 随机取一部分 网络连接来训练更新参数。
2. model.eval() model.eval()的作用是 不启用 Batch Normalization 和 Dropout。 如果模型中有 BN 层Batch Normalization和 Dropout在 测试时 添加 model.eval()。 model.eval() 是保证 BN 层能够用 全部训练数据 的均值和方差即测试过程中要保证 BN 层的均值和方差不变。对于 Dropoutmodel.eval() 是利用到了 所有 网络连接即不进行随机舍弃神经元。
为什么测试时要用 model.eval() 训练完 train 样本后生成的模型 model 要用来测试样本了。在 model(test) 之前需要加上model.eval()否则的话有输入数据即使不训练它也会改变权值。这是 model 中含有 BN 层和 Dropout 所带来的的性质。
eval() 时pytorch 会自动把 BN 和 DropOut 固定住不会取平均而是用训练好的值。 不然的话一旦 test 的 batch_size 过小很容易就会被 BN 层导致生成图片颜色失真极大。 eval() 在非训练的时候是需要加的没有这句代码一些网络层的值会发生变动不会固定你神经网络每一次生成的结果也是不固定的生成质量可能好也可能不好。
也就是说测试过程中使用model.eval()这时神经网络会 沿用 batch normalization 的值而并不使用 dropout。
3.3.3 总结与对比
如果模型中有 BN 层(Batch Normalization和 Dropout需要在训练时添加 model.train()在测试时添加 model.eval()。 其中 model.train() 是保证 BN 层用每一批数据的均值和方差而 model.eval() 是保证 BN 用全部训练数据的均值和方差 而对于 Dropoutmodel.train() 是随机取一部分网络连接来训练更新参数而 model.eval() 是利用到了所有网络连接。
参考链接【Pytorch】model.train() 和 model.eval() 原理与用法
总结
通过本文的学习了解了pytorch网络模型如何创建、训练与测试。