当前位置: 首页 > news >正文

基于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()

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

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

相关文章:

基于pytorch的手写体识别

一、环境搭建 链接: python与深度学习——基础环境搭建 二、数据集准备 本次实验用的是MINIST数据集,利用MINIST数据集进行卷积神经网络的学习,就类似于学习单片机的点灯实验,学习一门机器语言输出hello world。MINIST数据集,可以…...

Leetcode 56. 合并区间

题目描述:以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。 示例 1: 输入&#xf…...

C++:List的使用和模拟实现

创作不易,感谢三连!! 一、List的介绍 list的文档介绍 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 2. list的底层是双向链表结构,双向链表中每个元素存储在互不…...

20个Python函数程序实例

前面介绍的函数太简单了: 以下是 20 个不同的 Python 函数实例 下面深入一点点: 以下是20个稍微深入一点的,使用Python语言定义并调用函数的示例程序: 20个函数实例 简单函数调用 def greet():print("Hello!")greet…...

Wireshark——获取捕获流量的前N个数据包

1、问题 使用Wireshark捕获了大量的消息,但是只想要前面一部分。 2、方法 使用Wireshark捕获了近18w条消息,但只需要前5w条。 选择文件,导出特定分组。 输入需要保存的消息范围。如:1-50000。 保存即可。...

006-浏览器输入域名到返回

浏览器输入域名到返回 1、URL 输入2、DNS 域名解析3、建立 TCP 连接三次握手概念三次握手理解 4、发送 HTTP/HTTPS 请求5、服务器处理,并返回响应6、浏览器解析并渲染页面7、请求结束,端口 TCP 连接四次挥手概念四次挥手理解 1、URL 输入 2、DNS 域名解析…...

【kubernetes】关于k8s集群如何将pod调度到指定node节点?

目录 一、k8s的watch机制 二、scheduler的调度策略 Predicate(预选策略) 常见算法: priorities(优选策略)常见的算法有: 三、k8s的标签管理之增删改查 四、k8s的将pod调度到指定node的方法 方案一&am…...

【框架】React和Vue的异同

1. 前言 React对于原生JS要求会高一级,国外React用的多,国内Vue用的多。 2. 共同点 组件化函数式编程 (vue3函数式编程、vue2声明式编程)单向数据流,数据驱动视图VirtualDOM Diff算法操作DOM社区成熟,…...

如何选择阅读软件技术学习书籍

如何选择阅读软件技术学习书籍 这里以软件技术学习的角度结合自身感悟谈谈,如何选择阅读书籍。 人的时间和精力都是非常有限的,软件技术学习者如何选择阅读书籍。以下是从我的经验教训总结的一些体会: 1、确定自己的兴趣领域和阅读目标 选…...

做抖店用平板能代替电脑操作吗?抖店运营相关注意事项,注意规避

我是王路飞。 之前给你们讲在抖音开店流程的时候,说过开店需要用到电脑,还需要执照、资金、时间等等。 那么做抖店用平板能代替电脑操作吗? 这个问题其实有很多新手问过我,有的甚至是想直接在手机上操作,想着能省点…...

【FastChat】用于训练、服务和评估大型语言模型的开放平台

FastChat 用于训练、服务和评估大型语言模型的开放平台。发布 Vicuna 和 Chatbot Arena 的存储库。 隆重推出 Vicuna,一款令人印象深刻的开源聊天机器人 GPT-4! 🚀 根据 GPT-4 的评估,Vicuna 达到了 ChatGPT/Bard 90%* 的质量&…...

从根到叶:深入理解二叉搜索树

我们的心永远向前憧憬 尽管活在阴沉的现在 一切都是暂时的,转瞬即逝, 而那逝去的将变为可爱 &#x1f31d;(俄) 普希金 <假如生活欺骗了你> 1.二叉搜索树的概念 概念:搜索树&#xff08;Search Tree&#xff09;是一种有序的数据结构&#xff0c;用于存储和组…...

网络信息安全:11个常见漏洞类型汇总

一、SQL注入漏洞 SQL注入攻击&#xff08;SQL Injection&#xff09;&#xff0c;简称注入攻击、SQL注入&#xff0c;被广泛用于非法获取网站控制权&#xff0c;是发生在应用程序的数据库层上的安全漏洞。 在设计程序&#xff0c;忽略了对输入字符串中夹带的SQL指令的检查&…...

阿里云服务器使用教程_2024建站教程_10分钟网站搭建流程

使用阿里云服务器快速搭建网站教程&#xff0c;先为云服务器安装宝塔面板&#xff0c;然后在宝塔面板上新建站点&#xff0c;阿里云服务器网aliyunfuwuqi.com以搭建WordPress网站博客为例&#xff0c;来详细说下从阿里云服务器CPU内存配置选择、Web环境、域名解析到网站上线全流…...

【排序算法】推排序算法解析:从原理到实现

目录 1. 引言 2. 推排序算法原理 3. 推排序的时间复杂度分析 4. 推排序的应用场景 5. 推排序的优缺点分析 5.1 优点&#xff1a; 5.2 缺点&#xff1a; 6. Java、JavaScript 和 Python 实现推排序算法 6.1 Java 实现&#xff1a; 6.2 JavaScript 实现&#xff1a; 6.…...

Python爬虫实战(基础篇)—13获取《人民网》【最新】【国内】【国际】写入Word(附完整代码)

文章目录 专栏导读背景测试代码分析请求网址请求参数代码测试数据分析利用lxml+xpath进一步分析将获取链接再获取文章内容测试代码写入word完整代码总结专栏导读 🔥🔥本文已收录于《Python基础篇爬虫》 🉑🉑本专栏专门针对于有爬虫基础准备的一套基础教学,轻松掌握Py…...

常见控件应用

常见控件应用 1.操作Ajax选项2.滑动滑块操作 1.操作Ajax选项 Ajax即Asynchronous JavaScript and XML&#xff08;异步JavaScript和XML&#xff09;&#xff0c;是指一种创建交互式、快速动态网页应用的网页开发技术。通过在后台与服务器进行少量数据交换&#xff0c;Ajax可以…...

什么是降压恒流芯片?它有什么作用?

降压恒流芯片是一种电子元件&#xff0c;用于将高电压或高电流的输入电源转换为稳定的低电压输出电源&#xff0c;并同时保持恒定的电流输出。 降压恒流芯片的作用有以下几点&#xff1a; 将高电压降低到适合驱动车灯的工作电压&#xff0c;确保车灯亮度稳定。 在负载变化时…...

14:00面试,15:00就出来了,问的问题过于变态了。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到2月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…...

Maven的settings.xml配置

maven的两大配置文件&#xff1a;settings.xml和pom.xml。其中settings.xml是maven的全局配置文件&#xff0c;pom.xml则是文件所在项目的局部配置 标签servers&#xff1a; 一般&#xff0c;仓库的下载和部署是在pom.xml文件中的repositories和distributionManagement元素中定…...

利用redis实现秒杀功能

6、秒杀优化 这个是 图灵 的redis实战里面的一个案例 6.1 秒杀优化-异步秒杀思路 我们来回顾一下下单流程 当用户发起请求&#xff0c;此时会请求nginx&#xff0c;nginx会访问到tomcat&#xff0c;而tomcat中的程序&#xff0c;会进行串行操作&#xff0c;分成如下几个步骤…...

vscode 使用ssh进行远程开发 (remote-ssh),首次连接及后续使用,详细介绍

在vscode添加remote ssh插件 首次连接 选择左侧栏的扩展&#xff0c;并搜索remote ssh 它大概长这样&#xff0c;点击安装 安装成功后&#xff0c;在左侧栏会出现远程连接的图标&#xff0c;点击后选择ssh旁加号便可以进行连接。 安装成功后vscode左下角会有一个图标 点击图…...

rabbitmq总结

一、初次感知 https://www.cnblogs.com/zqyx/p/13170881.html 这篇文章非常好&#xff0c;讲了一些持久化的原理。 1. 第一次使用rabbitmq发信息 // 创建连接工厂ConnectionFactory connectionFactorynew ConnectionFactory();connectionFactory.setHost("192.168.88.1…...

专利预审是什么

专利预审是一种专利申请流程中的前置审查服务&#xff0c;通常由国家知识产权局设立的各地方知识产权保护中心或其他指定机构提供。在正式提交专利申请至国家知识产权局之前&#xff0c;申请人可以通过专利预审机制&#xff0c;提前向预审机构提交专利申请资料&#xff0c;由预…...

淘宝商品详情数据丨商品搬家丨商品采集丨商城建站

淘宝商品详情数据、商品搬家、商品采集以及商城建站都是电子商务领域的重要环节&#xff0c;它们共同构成了一个完整的在线销售体系。下面我将分别对这几个概念进行详细的解释。 请求示例&#xff0c;API接口接入Anzexi58 一、淘宝商品详情数据 淘宝商品详情数据指的是在淘宝…...

redis(1)-key-value-基本概念

1. 全量IO 全局遍历 2.路由、索引、映射 3.文件里都是小格子&#xff0c;4KB 硬件水平的吞吐。 数据&#xff1a;索引 100&#xff1a;1 4.Mysql qps:90000 tps:5000 事务 1个事务 18 tps*18qps 1.安全 2.事务 3.持久化 4.淘汰 5.过期 定时&#xff1a;内存-mysql 一天…...

cocos creator 3.7.2使用shader实现图片扫光特效

简介 功能&#xff1a;图片实现扫光效果 引擎&#xff1a;cocos Creator 3.7.2 开发语言&#xff1a;ts 完整版链接 链接https://lengmo714.top/284d90f4.html 效果图 shader代码 // Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd. CCEffect %{techniques:- pas…...

【C++杂货铺】详解string

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 为什么学习string &#x1f4c1; 认识string&#xff08;了解&#xff09; &#x1f4c1; string的常用接口 &#x1f4c2; 构造函数 &#x1f4c2; string类对象的容量操作 &#x1f4c2; string类对象的访问以及遍历操…...

算法刷题day20:二分

目录 引言概念一、借教室二、分巧克力三、管道四、技能升级五、冶炼金属六、数的范围七、最佳牛围栏八、套餐设计九、牛的学术圈I十、我在哪&#xff1f; 引言 这几天一直在做二分的题&#xff0c;都是上了难度的题目&#xff0c;本来以为自己的二分水平已经非常熟悉了&#x…...

【Spring云原生】Spring Batch:海量数据高并发任务处理!数据处理纵享新丝滑!事务管理机制+并行处理+实例应用讲解

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《Spring 狂野之旅&#xff1a;从入门到入魔》 &#x1f680; 本…...