基于pytorch的手写体识别

一、环境搭建
链接: python与深度学习——基础环境搭建

二、数据集准备
本次实验用的是MINIST数据集,利用MINIST数据集进行卷积神经网络的学习,就类似于学习单片机的点灯实验,学习一门机器语言输出hello world。MINIST数据集,可以调用torchvision里面的模块进行下载。

三、导入模块.
1.导入模块的代码

import torch
import torchvision
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

2.每个模块的作用
torch:导入pytorch的库
torchvision:导入torchvision,它PyTorch中的一个库,它提供了一些计算机视觉任务的工具和预训练模型。
from torch.utils.data import DataLoader:关于DataLoader,从PyTorch的torch.utils.data模块中导入DataLoader类。DataLoader类是PyTorch中用于数据加载的实用工具,它提供了对数据集的批量加载和并行处理的功能。通过使用DataLoader,可以方便地将数据集划分为小批量(batch)进行训练, 同时还可以利用多线程进行数据加载和预处理,以加快训练过程。
matplotlib .pyplot:主要适用于绘图,待会我们会用它查看数据集里面的图片,以及绘制训练损失和测试损失的曲线。
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

导入torch中的一些模块用于构建神经和优化网络的参数。

四、设置卷积神经网络的超参数
这些超参数都是全局变量,调整超参数也是优化神经网络的一个重要的手段

n_epochs = 3

epoch的数量定义了循环整个数据集的次数。也就是训练和测试的次数。

batch_size_train = 64
batch_size_test = 1000

这里是批处理,批处理的好处是可以大幅缩短每张图像的处理时间。batch_size表示批量大小,指每次模型更新时所使用的样本数。其中较大的批量大小可以提高训练速度,但可能降低模型的泛化能力;较小的批量大小可能导致训练过程更加噪声,并且需要更多的训练迭代次数。这里我们用batch_size=64进行训练,利用batch_size=1000进行测试。

learning_rata = 0.01

learning_rate表示学习率。用于控制每次参数更新的步长。较小的学习率可以使训练更稳定,但可能需要更多的训练迭代次数;较大的学习率可能导致训练不稳定或无法收敛。

momentum = 0.5

动量是一种在优化算法中使用的技术,用于加速梯度下降的收敛过程。它通过在更新时引入之前的更新方向,帮助模型跳出局部极小值。

log_interval = 10

这行代码将日志间隔(log interval)设置为10。在训练过程中,每隔10个批次(batch)将打印一次训练日志,用于跟踪训练的进度和性能。

random_seed = 1
torch.manual_seed(random_seed)

将随机种子(random seed)设置为1,并将其应用于PyTorch的随机数生成器。通过设置随机种子,可以使得每次运行代码时的随机过程可复现,即获得相同的随机结果。这在实验和调试中很有用,可以确保实验结果的一致性。

设置超参数部分的完整代码

n_epochs = 3
batch_size_train = 64
batch_size_test = 1000
learning_rate = 0.01
momentum = 0.5
log_interval = 10
random_seed = 1
torch.manual_seed(random_seed)

五、加载训练数据集和测试数据集

train_loader = torch.utils.data.DataLoader

torch.utils.data.DataLoader是PyTorch提供的用于数据加载的实用工具。

torchvision.datasets.MNIST('./data/', train=False, download=True,                              

torchvision.datasets.MNIST是用来加载MNIST数据集的函数,其中train=True表示加载训练集,download=True表示如果数据集不存在时会从互联网上下载。

 transform=torchvision.transforms.Compose([torchvision.transforms.ToTensor(),torchvision.transforms.Normalize((0.1307,), (0.3081,))])),

transform=torchvision.transforms.Compose([…])定义了一系列的数据转换操作,用于对数据进行预处理。torchvision.transforms.ToTensor()将数据转换为Tensor对象,将图像数据从PIL Image对象转换为Tensor对象。
torchvision.transforms.Normalize((0.1307,), (0.3081,))对图像数据进行归一化处理,使其均值为0.1307,标准差为0.3081。这是针对MNIST数据集的归一化处理,目的是将数据转换为均值为0、方差为1的分布。

  batch_size=batch_size_train,shuffle=True

规定了每个批次加载的数量,shuffle=True表示要对数据进行随机洗牌,在每个周期中随机选择样本

上述代码是加载训练数据集,完整代码如下。

train_loader = torch.utils.data.DataLoader(torchvision.datasets.MNIST('./data/', train=True, download=True,transform=torchvision.transforms.Compose([torchvision.transforms.ToTensor(),torchvision.transforms.Normalize((0.1307,), (0.3081,))])),batch_size=batch_size_train, shuffle=True)

加载测试数据集的方式和加载训练数据集的方式一样,不同的是要把train=True改为train=False,

加载测试数据集的代码如下:

test_loader = torch.utils.data.DataLoader(torchvision.datasets.MNIST('./data/', train=False, download=True,transform=torchvision.transforms.Compose([torchvision.transforms.ToTensor(),torchvision.transforms.Normalize((0.1307,), (0.3081,))])),batch_size=batch_size_test, shuffle=True)

六、查看数据,确定数据的维度
所谓数据的维度,就是数据的数量,通道数,高度和宽度等信息。

examples = enumerate(test_loader)

使用enumerate函数对test_loader进行枚举,返回一个枚举对象examples。枚举对象可以用于迭代加载test_loader中的批次数据。

batch_idx, (example_data, example_targets) = next(examples)

通过next函数从examples枚举对象中获取下一个批次的数据。batch_idx表示批次的索引,(example_data, example_targets)表示批次中的示例数据和对应的标签。

print(example_targets)

打印出示例数据的标签,就是图片实际对应的数字标签。 这里的example_targets是一个张量,包含了当前批次中每个样本的标签。

print(example_data.shape)

打印出示例数据的形状,example_data是一个张量,表示当前批次中每个样本的图像数据,通过shape属性,可以查看数据的维度信息,如通道数、高度和宽度。

以上代码的功能是查看部分测试数据,并查看示例数据的标签和查看示例数据的形状,这部分的完整代码如下。

examples = enumerate(test_loader)
batch_idx, (example_data, example_targets) = next(examples)
print(example_targets)
print(example_data.shape)

运行结果
在这里插入图片描述
这里显示,示例数据的尺寸是torch.Size([1000, 1, 28, 28]),表示的是1000张测试数据,黑白图像,通道为1,像素为28*28。

七、查看示例数据
这里我们要用到之前导入的matplotlib.pyplot模块。这里有点类似于MATLAB的绘图

fig = plt.figure()

创建一个新的图形对象。

for i in range(6):

循环6次,用于遍历6个子图的位置。

plt.subplot(2,3,i+1)

在图形中创建一个2行3列的子图,并选择第i + 1个子图位置。

plt.tight_layout()

调整子图的布局,使其更加紧凑

 plt.imshow(example_data[i][0], cmap='gray', interpolation='none')

使用imshow函数显示第i个示例数据的图像。example_data[i][0],表示第i个示例数据的图像张量;cmap = ‘gray’,表示使用灰度颜色映射;interpolation = ‘none’, 表示不使用插值来显示图像。

 plt.title("Ground Truth:{}".format(example_targets[i]))

设置当前子图的标题,包括示例数据的标签信息。

 plt.xticks([])plt.yticks([])

隐藏子图的横纵刻度标签。

plt.show()

进行图形的绘制。

此部分的完整代码为:

fig = plt.figure()
for i in range(6):plt.subplot(2, 3, i + 1)plt.tight_layout()plt.imshow(example_data[i][0], cmap='gray', interpolation='none')plt.title("Ground Truth: {}".format(example_targets[i]))plt.xticks([])plt.yticks([])
plt.show()

运行结果
在这里插入图片描述
八、构建神经网络和传播函数
现在就到了最激动人心的时刻了,构建一个卷积神经网络,并了解整个的流程。粗略看来,我们的所构建的这个网络的结构为:
在这里插入图片描述
两个卷积层,那么对应就有两个激活函数和池化层,同时还使用dropout层和全连接层。各层的作用如下。
卷积层
卷积层的主要作用是提取输入数据中的特征。卷积层通过使用一组可学习的卷积核(也称为滤波器)对输入数据进行卷积操作。卷积操作可以看作是一种窗口滑动的过程,将卷积核与输入数据的不同位置进行逐元素相乘,并求和得到输出的单个元素。通过对整个输入数据进行卷积操作,卷积层可以得到一张特征图(也称为卷积特征)。
激活函数
我们设想一下,如果使用线性函数或者是将线性函数叠加成网络,那么它始终无法解决非线性的问题,所以针对此问题,我们引入了一些非线性函数作为激活函数,为什么称之为激活函数,我们拿神经细胞来举例。
在这里插入图片描述
如图所示:神经元是由轴突和树突构成的。当轴突接收到上一个神经元传来的信号的时候,树突上会产生一个动作电压,那么这个歌神经元就会被激活,从而向后继续传导信号。同样的,有了激活函数我们深度学习中的神经元才可以被激活,神经网络才能够正常工作,解决实际问题。
在深度学习中,常见的激活函数有:sigmoid函数,Relu函数,softmax函数等。这里我们使用的是Relu函数。
池化层
池化层通常紧跟在卷积层之后。池化的主要作用是对特征图进行下采样,减少数据的空间维度,并且保留重要的特征信息。。在池化窗口内,通常选择最大值(Max Pooling)或平均值(Average Pooling)作为汇总特征。这样可以过滤掉一些噪声和不重要的细节,保留对分类或识别任务有用的特征。在此次实验中,我们采用的是最大池化的方式,池化窗口为2。
Dropout层
Dropout层是一种常用的正则化技术,在深度学习中用于减少过拟合(overfitting)问题。它的主要作用是随机地在神经网络的训练过程中将一部分神经元的输出置为零。也就是随机删除一些神经元。Dropout层通过随机地丢弃神经元的输出,可以减少过拟合、防止共适应、提高泛化能力,并且降低了模型的复杂性。它是一种简单而有效的正则化技术,因此在深度学习中被广泛应用。
全连接层
全连接层的作用是将前一层的所有神经元与当前层的所有神经元相连接,每个连接都有一个可学习的权重。全连接层通常是神经网络最后的层,用于将中间表示映射到最终的输出类别或预测值。例如,在图像分类任务中,全连接层将学习到的特征转换为类别的概率分布。在回归任务中,全连接层可以将学习到的特征映射为连续的数值输出。

代码实现以及具体参数

class Net(nn.Module):

创建神经网络的类,该类的父类是nn.Module类

def __init__(self):

初始化方法,用于初始化网络的各个层和组件

 super(Net, self).__init__()

super(Net, self).init()的作用是调用父类的构造函数,以便在子类的构造函数中执行父类的初始化逻辑。通过调用父类的构造函数,可以确保子类在创建实例时继承并初始化父类的属性和方法。

self.conv1 = nn.Conv2d(1, 10, kernel_size=5)

定义了一个卷积层conv1,输入通道数为1,输出通道数为10,卷积核大小为5x5。

self.conv2 = nn.Conv2d(10, 20, kernel_size=5)

定义了另一个卷积层conv2,输入通道数为10,输出通道数为20,卷积核大小为5x5。

 self.conv2_drop = nn.Dropout2d()

定义了一个二维Dropout层conv2_drop。

  self.fc1 = nn.Linear(320, 50)

定义了一个全连接层fc1,输入大小为320,输出大小为50。

self.fc2 = nn.Linear(50, 10)

定义了另一个全连接层fc2,输入大小为50,输出大小为10。

def forward(self,x):

Net类的前向传播函数,用于定义网络的数据流向。

x = F.relu(F.max_pool2d(self.conv1(x),2))

对输入x进行卷积、ReLU激活和最大池化操作,池化窗口大小为2,每个窗口的大小为2x2。最大池化是指特征图的每个2x2的窗口内的值取最大值,从而将特征图的尺寸减小一半。

x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)),2))

对第一个卷积层的输出进行卷积、Dropout、ReLU激活和最大池化操作。

 x = x.view(-1, 320)

将张量x进行展平,变为一维向量。

x = F.relu(self.fc1(x))

对展平后的向量进行全连接并进行ReLU激活操作。

x = F.dropout(x, training=self.training)

对第一个全连接层的输出进行Dropout操作,self.training用于指示当前是否处于训练模式。

x = self.fc2(x)

对第二个全连接层的输出进行全连接操作。

return  F.log_softmax(x)

对输出进行log_softmax操作,用于多分类问题的概率预测。

前面一段定义了网络结构,以及网络的前向传播函数,总体代码如下

class Net(nn.Module):# 初始化方法,用于初始化网络的各个层和组件。def __init__(self):# 继承父类的一些属性super(Net, self).__init__()# 定义了一个卷积层conv1,输入通道数为1,输出通道数为10,卷积核大小为5x5。self.conv1 = nn.Conv2d(1, 10, kernel_size=5)# 定义了另一个卷积层conv2,输入通道数为10,输出通道数为20,卷积核大小为5x5。self.conv2 = nn.Conv2d(10, 20, kernel_size=5)# 定义了一个二维Dropout层conv2_drop。self.conv2_drop = nn.Dropout2d()# 定义了一个全连接层fc1,输入大小为320,输出大小为50。self.fc1 = nn.Linear(320, 50)# 定义了另一个全连接层fc2,输入大小为50,输出大小为10。self.fc2 = nn.Linear(50, 10)# Net类的前向传播函数,用于定义网络的数据流向。def forward(self,x):# 对输入x进行卷积、ReLU激活和最大池化操作,池化窗口大小为2,每个窗口的大小为2x2# 最大池化是指特征图的每个2x2的窗口内的值取最大值,从而将特征图的尺寸减小一半。x = F.relu(F.max_pool2d(self.conv1(x),2))# 对第一个卷积层的输出进行卷积、Dropout、ReLU激活和最大池化操作。x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)),2))# 将张量x进行展平,变为一维向量。x = x.view(-1, 320)# 对展平后的向量进行全连接、ReLU激活操作。x = F.relu(self.fc1(x))# 对第一个全连接层的输出进行Dropout操作,self.training用于指示当前是否处于训练模式。x = F.dropout(x, training=self.training)# 对第二个全连接层的输出进行全连接操作。x = self.fc2(x)# 对输出进行log_softmax操作,用于多分类问题的概率预测。return  F.log_softmax(x)

如上的网络结构以及数据流向,如下图所示。
在这里插入图片描述
九、初始化网络和优化器

#实例化对象
# 创建一个Net类的实例,即创建了一个神经网络对象。
network = Net()
# 创建一个随机梯度下降(SGD)优化器对象,用于优化网络的参数。
# network.parameters()返回网络中的可学习参数,即需要进行梯度更新的参数。
optimizer = optim.SGD(network.parameters(),lr=learning_rata,momentum=momentum)

创建空列表,记录训练以及测试过程中的损失值和步数

# 用于记录训练过程中的损失值和训练步数。
train_losses = []
train_counter = []
# 创建了另外两个空列表,用于记录测试过程中的损失值和测试步数。
# 根据训练数据集的大小和训练周期数来确定测试步数的间隔。
test_losses = []
test_counter = [i*len(train_loader.dataset) for i in range(n_epochs + 1)]

这一块完整的代码为

# 初始化网络和优化器
#实例化对象
# 创建一个Net类的实例,即创建了一个神经网络对象。
network = Net()
# 创建一个随机梯度下降(SGD)优化器对象,用于优化网络的参数。
# network.parameters()返回网络中的可学习参数,即需要进行梯度更新的参数。
optimizer = optim.SGD(network.parameters(),lr=learning_rata,momentum=momentum)# 用于记录训练过程中的损失值和训练步数。
train_losses = []
train_counter = []
# 创建了另外两个空列表,用于记录测试过程中的损失值和测试步数。
# 根据训练数据集的大小和训练周期数来确定测试步数的间隔。
test_losses = []
test_counter = [i*len(train_loader.dataset) for i in range(n_epochs + 1)]

十、模型训练与测试
模型训练

def train(epoch):# 将神经网络模型设置为训练模式,这是为了确保在训练过程中启用一些特定的操作,如Dropout。network.train()

将网络模型设置为训练模式

    for batch_idx, (data, target) in enumerate(train_loader):# 在每个批次开始时,将优化器的梯度缓冲区清零,以准备计算当前批次的梯度。optimizer.zero_grad()# 通过将输入数据传递给网络模型(network),计算模型的输出output = network(data)# 使用负对数似然损失函数(F.nll_loss), 计算模型输出和目标标签之间的损失loss = F.nll_loss(output,target)# 根据损失值,执行反向传播过程,计算相对于模型参数的梯度。loss.backward()# 根据梯度更新模型的参数,使用优化器(optimizer),来执行参数更新步骤。optimizer.step()

读取训练集的数据,计算输出并计算输出和目标之间的损失,损失函数是机器学习中比较重要的一个内容,其作用是衡量输出值和目标值之间的差距,损失函数有很多种,也可以自己定义,这里我们采用的是负对数似然损失函数(F.nll_loss), 计算模型输出和目标标签之间的损失。计算完损失值之后,执行反向传播过程,并进行更新

为了更直观的了解训练的进度,在终端进行当前训练轮数、已处理的样本数量、总样本数量的百分比以及当前批次的损失值等信息的打印。

        # 如果当前批次的索引能被log_interval整除,表示达到了指定的打印间隔。if batch_idx % log_interval == 0:# 打印当前训练轮数、已处理的样本数量、总样本数量的百分比以及当前批次的损失值。print('Train Epoch: {}  [{}/{} ({:.0f}%)]\tLoss: {: .6f}'.format(epoch, batch_idx*len(data), len(train_loader.dataset),100.*batch_idx/len(train_loader), loss.item()))# append,给列表添加元素的指令# 将当前批次的损失值和对应的训练步数添加到训练损失列表(train_losses)# 和训练步数列表(train_counter)中,用于后续的可视化和分析。train_losses.append(loss.item())train_counter.append((batch_idx *64) + ((epoch -1) * len(train_loader.dataset)))
            torch.save(network.state_dict(),'./model.pth')torch.save(optimizer.state_dict(),'./optimizer.pth')

在训练结束后,要对模型参数以及优化器状态进行保存,以便于之后可以接着上一次的训练结果接着训练

# 调用训练的函数,次数为1
train(1)

其中1就是epoch,即训练轮数,可以根据实际情况进行调整

测试
和上面的训练过程基本类似,遍历测试集,计算模型输出,并且计算损失

def test():# 将神经网络模型设置为评估模式,这是为了确保在评估过程中不启用一些特定的操作,如Dropout。network.eval()# test_loss,用于累积测试损失test_loss = 0# correct用于累积预测正确的样本数量。correct = 0# 使用torch.no_grad()# 上下文管理器,表示在评估过程中不进行梯度计算,以减少内存消耗和加快计算速度。with torch.no_grad():# 遍历测试数据集(test_loader),其中data是输入数据的批量,target是对应的标签。for data, target in test_loader:# 通过将输入数据传递给网络模型(network),计算模型的输出。output = network(data)# 使用负对数似然损失函数(F.nll_loss),计算模型输出和目标标签之间的损失,并累积到test_loss中。test_loss = test_loss + F.nll_loss(output, target, size_average=False).item()# 获取模型输出中概率最高的类别预测,即预测值。pred = output.data.max(1, keepdim=True)[1]# 计算预测值与目标标签相等的样本数量,并累积到correct中correct = correct + pred.eq(target.data.view_as(pred)).sum()# 计算平均测试损失,将累积的测试损失值除以测试数据集的样本数量。test_loss = test_loss / len(test_loader.dataset)# 将平均测试损失值添加到测试损失列表(test_losses)中,test_losses.append(test_loss)

同样我们在控制台对结果进行打印

    # 打印评估结果,包括平均测试损失和测试数据集上的准确率。print('\nTest set: Avg. loss: {: .4f},Accuracy : {}/{} ({: .0f}%)\n'.format(test_loss, correct, len(test_loader.dataset),100.* correct / len(test_loader.dataset)))

下面一段代码是用于进行训练和测试的主要循环,在开始训练之前,首先调用test()函数对当前的模型在测试数据集上进行评估, 以了解初始模型在未经训练的情况下的性能。

test()
# 从1到n_epochs(训练轮数+1)进行循环,表示训练过程中的每个训练轮次(epoch)。
for epoch in range(1, n_epochs + 1):# 调用train(epoch)函数,进行一次完整的训练轮次。# 在train()函数中,会遍历训练数据集,并执行前向传播、计算损失、反向传播和参数更新等步骤。train(epoch)# 在完成一次训练轮次后,调用test()函数对当前模型在测试数据集上进行评估,# 以了解训练过程中模型的性能变化。test()

通过这样的循环,每个训练轮次都会进行一次完整的训练和评估, 以不断优化模型的参数,并监测训练的进展。这样的循环将重复多次,直到达到指定的训练轮数(n_epochs)为止。

以上是模型训练和测试的内容,这一部分完整代码如下:

#模型训练
#尝试一次循环,看看精度与损失,准确度
# epoch遍历数据集的次数,即训练轮数
def train(epoch):# 将神经网络模型设置为训练模式,这是为了确保在训练过程中启用一些特定的操作,如Dropout。network.train()# 使用enumerate函数遍历训练数据集(train_loader)# batch_idx表示当前批次的索引,data是输入数据的批量,target是对应的标签。for batch_idx, (data, target) in enumerate(train_loader):# 在每个批次开始时,将优化器的梯度缓冲区清零,以准备计算当前批次的梯度。optimizer.zero_grad()# 通过将输入数据传递给网络模型(network),计算模型的输出output = network(data)# 使用负对数似然损失函数(F.nll_loss), 计算模型输出和目标标签之间的损失loss = F.nll_loss(output,target)# 根据损失值,执行反向传播过程,计算相对于模型参数的梯度。loss.backward()# 根据梯度更新模型的参数,使用优化器(optimizer),来执行参数更新步骤。optimizer.step()# 如果当前批次的索引能被log_interval整除,表示达到了指定的打印间隔。if batch_idx % log_interval == 0:# 打印当前训练轮数、已处理的样本数量、总样本数量的百分比以及当前批次的损失值。print('Train Epoch: {}  [{}/{} ({:.0f}%)]\tLoss: {: .6f}'.format(epoch, batch_idx*len(data), len(train_loader.dataset),100.*batch_idx/len(train_loader), loss.item()))# append,给列表添加元素的指令# 将当前批次的损失值和对应的训练步数添加到训练损失列表(train_losses)# 和训练步数列表(train_counter)中,用于后续的可视化和分析。train_losses.append(loss.item())train_counter.append((batch_idx *64) + ((epoch -1) * len(train_loader.dataset)))# 保存当前的网络模型参数和优化器状态,以便在需要时恢复和继续训练。# 训练结束后都要保存网络torch.save(network.state_dict(),'./model.pth')torch.save(optimizer.state_dict(),'./optimizer.pth')# 调用训练的函数,次数为1
train(1)# 进行测试
def test():# 将神经网络模型设置为评估模式,这是为了确保在评估过程中不启用一些特定的操作,如Dropout。network.eval()# test_loss,用于累积测试损失test_loss = 0# correct用于累积预测正确的样本数量。correct = 0# 使用torch.no_grad()# 上下文管理器,表示在评估过程中不进行梯度计算,以减少内存消耗和加快计算速度。with torch.no_grad():# 遍历测试数据集(test_loader),其中data是输入数据的批量,target是对应的标签。for data, target in test_loader:# 通过将输入数据传递给网络模型(network),计算模型的输出。output = network(data)# 使用负对数似然损失函数(F.nll_loss),计算模型输出和目标标签之间的损失,并累积到test_loss中。test_loss = test_loss + F.nll_loss(output, target, size_average=False).item()# 获取模型输出中概率最高的类别预测,即预测值。pred = output.data.max(1, keepdim=True)[1]# 计算预测值与目标标签相等的样本数量,并累积到correct中correct = correct + pred.eq(target.data.view_as(pred)).sum()# 计算平均测试损失,将累积的测试损失值除以测试数据集的样本数量。test_loss = test_loss / len(test_loader.dataset)# 将平均测试损失值添加到测试损失列表(test_losses)中,test_losses.append(test_loss)# 打印评估结果,包括平均测试损失和测试数据集上的准确率。print('\nTest set: Avg. loss: {: .4f},Accuracy : {}/{} ({: .0f}%)\n'.format(test_loss, correct, len(test_loader.dataset),100.* correct / len(test_loader.dataset)))# 下面一段代码是用于进行训练和测试的主要循环
# 在开始训练之前,首先调用test()函数对当前的模型在测试数据集上进行评估,
# 以了解初始模型在未经训练的情况下的性能。
test()
# 从1到n_epochs(训练轮数+1)进行循环,表示训练过程中的每个训练轮次(epoch)。
for epoch in range(1, n_epochs + 1):# 调用train(epoch)函数,进行一次完整的训练轮次。# 在train()函数中,会遍历训练数据集,并执行前向传播、计算损失、反向传播和参数更新等步骤。train(epoch)# 在完成一次训练轮次后,调用test()函数对当前模型在测试数据集上进行评估,# 以了解训练过程中模型的性能变化。test()# 通过这样的循环,每个训练轮次都会进行一次完整的训练和评估,
# 以不断优化模型的参数,并监测训练的进展。
# 这样的循环将重复多次,直到达到指定的训练轮数(n_epochs)为止。

十一、评估模型的性能,并进行可视化展示

# 创建一个新的图形窗口。
fig = plt.figure()
# 绘制训练损失曲线。train_counter是训练步数的列表,train_losses是对应的训练损失值的列表。
# 通过plt.plot函数将训练步数和训练损失连接起来,形成一条蓝色曲线。
plt.plot(train_counter, train_losses, color='blue')
# 绘制测试损失数据点。test_counter是测试步数的列表,test_losses是对应的测试损失值的列表。
# 通过plt.scatter函数将测试步数和测试损失以红色的散点图形式展示。
plt.scatter(test_counter, test_losses, color='red')
# 添加图例,标明蓝色曲线表示训练损失,红色散点表示测试损失。图例显示在图的右上方。
plt.legend(['Train Loss', 'Test Loss'],loc='upper right')
# 设置横轴和纵轴的标签,分别表示训练步数和损失值
# 横轴上标上,所看到的训练样本的数量
plt.xlabel('number of training examples seen')
# 纵轴上标上负对数似然损失
plt.ylabel('negative log likelihood loss')# 比较模型的输出,并输出相应的预测值
# 使用enumerate函数遍历测试数据集(test_loader),获取每个样本的索引和数据。
examples = enumerate(test_loader)
# 调用next函数获取下一个样本的索引和数据。
# batch_idx表示当前样本在批次中的索引,
# example_data和example_targets分别表示输入数据和对应的目标标签。
batch_idx,(example_data,example_targets) = next(examples)
# 使用torch.no_grad()上下文管理器,表示在计算模型输出时不进行梯度计算
with torch.no_grad():# 通过将example_data输入到网络模型(network),计算模型的输出。output = network(example_data)

这里也对预测图像可视化展示

# 创建一个新的图形窗口。
fig = plt.figure()
# 使用循环遍历前6个样本,绘制子图并显示样本图像
for i in range(6):# 创建2x3的子图网格,并在当前子图中显示第i + 1个样本图像。plt.subplot(2,3,i+1)# 使得子图在图形窗口中紧凑且不重叠plt.tight_layout()# example_data[i][0],表示第i个样本的图像数据。# plt.imshow函数用于显示图像,# cmap = 'gray',表示使用灰度颜色映射,# interpolation = 'none',表示不进行插值。plt.imshow(example_data[i][0],cmap='gray', interpolation='none')# 显示预测结果。output.data.max(1, keepdim=True)[1][i].item()# 表示对于第i个样本,获取预测概率最高的类别,并将其作为预测结果。plt.title("Prediction: {}".format(output.data.max(1, keepdim=True)[1][i].item()))# 不添加横纵坐标plt.xticks([])plt.yticks([])
plt.show()

由于前面设置的超参数中训练轮数为3,所以这里运行了三轮
在这里插入图片描述
绘制的训练损失曲线和测试损失曲线如下
在这里插入图片描述
预测结果如下
在这里插入图片描述
绘制曲线的完整代码如下

十二、继续训练
我们这里重复上面的过程,接着第三轮之后继续进行训练(因为前面有对前三轮运行之后的模型参数等进行保存),并再次绘制曲线,对训练损失和测试损失进行可视化展示。

# 手动添加计数器进行训练
for i in  range(4,9):test_counter.append(i*len(train_loader.dataset))train(i)test()#使用图像检查训练结果
fig = plt.figure()
plt.plot(train_counter, train_losses, color='blue')
plt.scatter(test_counter, test_losses, color='red')
plt.legend(['Train Loss', 'Test Loss'], loc='upper right')
plt.xlabel('number of training examples seen')
plt.ylabel('negative log likelihood loss')
plt.show()

接着前面的三轮,我们一共训练了八轮,所得到的曲线如下
在这里插入图片描述
在这里插入图片描述

至此,一个简单的机器学习实例已经完成,当然也可以调整超参数,以达到更高的准确率和更小的损失。

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

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

相关文章

【go从入门到精通】go环境安装和第一个经典程序

go下载和环境变量配置 下载地址 Go官网下载地址:https://golang.org/dl/All releases - The Go Programming Languagehttps://golang.org/dl/ 然后根据自己的系统环境来选择不同的安装包下载,下面我分别针对不同环境进行说明(大家可以根据自…

Platformview在iOS与Android上的实现方式对比

Android中早期版本Platformview的实现基于Virtual Display。VirtualDisplay方案的原理是,先将Native View绘制到虚显,然后Flutter通过从虚显输出中获取纹理并将其与自己内部的widget树进行合成,最后作为Flutter在 Android 上更大的纹理输出的…

Unity2023.1.19_ECS_DOTS

Unity2023.1.19_ECS_DOTS 盲学-盲目的学习: 懒着自己整理就看看别人整理的吧,整合一下逻辑通了不少: DOTS/data oriented technology stack-面向数据的技术栈 ECS/Entities-Component-System Unity-Entities包 Entities提供ECS架构面向数…

BUUCTF---[ACTF2020 新生赛]BackupFile1

1.题目描述 2.题目提示backup file ,是备份文件的意思。点开链接,页面提示 3.查看源码没有什么有用信息,也没有登录界面,所以也不会用到蚁剑链接来找备份文件,所以大概率就是通过构造playload来查找备份文件。 4.备份…

新手想玩硬件,买单片机还是树莓派好?

新手想玩硬件,买单片机还是树莓派好? 在开始前我有一些资料,是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家&#x…

Springboot+vue的船舶监造系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频: Springbootvue的船舶监造系统(有报告)。Javaee项目,springboot vue前后端分离项目。 项目介绍: 本文设计了一个基于Springbootvue的船舶监造系统,采用M(model)V&#xff…

二百二十六、Linux——shell脚本查看今天日期、昨天日期、30天前日期、1月前日期

一、目的 由于磁盘资源有限,因为对原始数据的保存有事件限制,因为对于超过一定期限的数据文件则需要删除,要实现定期删除则第一步就是查看日期时间 二、在Linux中创建shell脚本 #! /bin/bash source /etc/profile nowdatedate --date0 da…

Linux 学习笔记(11)

十一、 资源监控 1 、 free 内存监控 语 法&#xff1a; free [-bkmotV][-s < 间隔秒数 >] 补充说明&#xff1a; free 指令会显示内存的使用情况&#xff0c;包括实体内存&#xff0c;虚拟的交换文件内存&#xff0c;共享内存区段&#xff0c;以 及系统核心使用的…

[计算机网络]:流量控制

一、流量控制简介 一条TCP连接的每一侧主机都为其设置了接收缓存&#xff0c;当TCP成功连接后&#xff0c;它发送的数据会放入接受缓存中。相关联的进程会从缓存中读取数据。但是存在一个问题&#xff0c;当某应用程序读取数据速率太慢&#xff0c;而发送数据一方不停的发送数…

【数据结构】复杂度详解

目录 &#xff08;一&#xff09;算法的复杂度 &#xff08;二&#xff09;时间复杂度 &#xff08;1&#xff09;练笔解释&#xff1a; i&#xff0c;示例1 ii&#xff0c;示例2 iii&#xff0c;二分查找 iv&#xff0c;斐波那契 &#xff08;三&#xff09;空间复杂度…

英福康INFICON真空计MPG400MPG401使用说明PPT讲解课件

英福康INFICON真空计MPG400MPG401使用说明PPT讲解课件

Java解决杨辉三角

Java解决杨辉三角 01 题目 给定一个非负整数 *numRows&#xff0c;*生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]示例 2: 输入: numRo…

计网面试题整理下

1. HTTP常见的状态码有哪些&#xff1f; 常见状态码&#xff1a; 200&#xff1a;服务器已成功处理了请求。 通常&#xff0c;这表示服务器提供了请求的网页。301 &#xff1a; (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时&am…

前端面试 跨域理解

2 实现 2-1 JSONP 实现 2-2 nginx 配置 2-2 vue 开发中 webpack自带跨域 2 -3 下载CORS 插件 或 chrome浏览器配置跨域 2-4 通过iframe 如&#xff1a;aaa.com 中读取bbb.com的localStorage 1)在aaa.com的页面中&#xff0c;在页面中嵌入一个src为bbb.com的iframe&#x…

在全志V853平台上成功部署深度学习步态识别算法

北理工通信课题组辛喆同学在本科毕业设计《基于嵌入式系统的步态识别的研究》中&#xff0c;成功将深度步态识别算法GaitSet移植到全志V853开发板上。本研究在CASIA-B数据集上进行测试&#xff0c;正常行走状态下该系统的步态识别准确率达到了94.9%&#xff0c;背包行走和穿外套…

C++基于多设计模式下的同步异步日志系统day5

C基于多设计模式下的同步&异步日志系统day5 &#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C基于多设计模式下的同步&异步日志系统 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&am…

C++:Vector的模拟实现

创作不易&#xff0c;感谢三连 &#xff01;&#xff01; 一&#xff0c;前言 在学习string类的时候&#xff0c;我们可能会发现遍历的话下标访问特别香&#xff0c;比迭代器用的舒服&#xff0c;但是下标其实只能是支持连续的空间&#xff0c;他的使用是非常具有局限性的&am…

第 125 场 LeetCode 双周赛题解

A 超过阈值的最少操作数 I 排序然后查找第一个大于等于 k 的元素所在的位置 class Solution { public:int minOperations(vector<int> &nums, int k) {sort(nums.begin(), nums.end());return lower_bound(nums.begin(), nums.end(), k) - nums.begin();} };B 超过阈…

C++ 位运算OJ

目录 1、 191. 位1的个数 2、 338. 比特位计数 3、 461. 汉明距离 4、136. 只出现一次的数字 5、 260. 只出现一次的数字 III 6、面试题 01.01. 判定字符是否唯一 7、 268. 丢失的数字 8、 371. 两整数之和 9、 137. 只出现一次的数字 II 10、面试题 17.19. 消失的两个…

【C++】二叉树进阶面试题(上)

目录 1. 二叉树创建字符串 题目 分析 代码 2. 二叉树的分层遍历1 题目 分析 代码 3. 二叉树的分层遍历2 题目 分析 代码 4. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先 题目 分析 代码 5. 二叉树搜索树转换成排序双向链表 题目 分析 代码 1. …