Pytorch|mnist手写数字识别

server/2024/11/25 11:02:43/
  • 🍨 本文为🔗365天深度学习训练营中的学习记录博客
  • 🍖 原作者:K同学啊

一、 前期准备

1. 设置GPU

如果设备上支持GPU就使用GPU,否则使用CPU

python">import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import torchvision# 设置硬件设备,如果有GPU则使用,没有则使用cpu
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
device(type='cpu')

2. 导入数据

使用dataset下载MNIST数据集,并划分好训练集与测试集

使用dataloader加载数据,并设置好基本的batch_size

torchvision.datasets.MNIST详解

torchvision.datasets是Pytorch自带的一个数据库,我们可以通过代码在线下载数据,这里使用的是torchvision.datasets中的MNIST数据集。

函数原型:

torchvision.datasets.MNIST(root, train=True, transform=None, target_transform=None, download=False)

参数说明:

  • root (string) :数据地址
  • train (string) :True-训练集,False-测试集
  • download (bool,optional) : 如果为True,从互联网上下载数据集,并把数据集放在root目录下。
  • transform (callable, optional ):这里的参数选择一个你想要的数据转化函数,直接完成数据转化
  • target_transform (callable,optional) :接受目标并对其进行转换的函数/转换。
python">train_ds = torchvision.datasets.MNIST('data', train=True, transform=torchvision.transforms.ToTensor(), # 将数据类型转化为Tensordownload=True)test_ds  = torchvision.datasets.MNIST('data', train=False, transform=torchvision.transforms.ToTensor(), # 将数据类型转化为Tensordownload=True)

你可能会遇到RuntimeError: Error downloading train-images-idx3-ubyte.gz报错

这是由于无法连接下载数据导致的,你可以把下面的数据集放到代码文件同一个目录下,直接从本地加载数据集,避免下载了。

torch.utils.data.DataLoader详解

torch.utils.data.DataLoader是Pytorch自带的一个数据加载器,结合了数据集和取样器,并且可以提供多个线程处理数据集

函数原型:

torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=None, sampler=None, batch_sampler=None, num_workers=0, collate_fn=None, pin_memory=False, drop_last=False, timeout=0, worker_init_fn=None, multiprocessing_context=None, generator=None, *, prefetch_factor=2, persistent_workers=False, pin_memory_device='')

参数说明:

  • dataset (string) :加载的数据集
  • batch_size (int,optional) :每批加载的样本大小(默认值:1)
  • shuffle (bool,optional) : 如果为True,每个epoch重新排列数据。
  • sampler (Sampler or iterable, optional) : 定义从数据集中抽取样本的策略。 可以是任何实现了 __len__ 的 Iterable。 如果指定,则不得指定 shuffle 。
  • batch_sampler (Sampler or iterable, optional) : 类似于sampler,但一次返回一批索引。与 batch_size、shuffle、sampler 和 drop_last 互斥。
  • num_workers (int,optional) : 用于数据加载的子进程数。 0 表示数据将在主进程中加载(默认值:0)。
  • pin_memory (bool,optional) : 如果为 True,数据加载器将在返回之前将张量复制到设备/CUDA 固定内存中。 如果数据元素是自定义类型,或者collate_fn返回一个自定义类型的批次。
  • drop_last (bool,optional) : 如果数据集大小不能被批次大小整除,则设置为 True 以删除最后一个不完整的批次。 如果 False 并且数据集的大小不能被批大小整除,则最后一批将保留。 (默认值:False)
  • timeout (numeric,optional) : 设置数据读取的超时时间 , 超过这个时间还没读取到数据的话就会报错。(默认值:0)
  • worker_init_fn (callable,optional) : 如果不是 None,这将在步长之后和数据加载之前在每个工作子进程上调用,并使用工作 id([0,num_workers - 1] 中的一个 int)的顺序逐个导入。(默认:None)

python">batch_size = 32train_dl = torch.utils.data.DataLoader(train_ds, batch_size=batch_size, shuffle=True)test_dl  = torch.utils.data.DataLoader(test_ds, batch_size=batch_size)

torch.Size([32, 1, 28, 28])

  1. train_dl 是一个 PyTorch 数据加载器(DataLoader),用于加载训练数据集。通常情况下,数据加载器会将数据集分成小批量(batches)进行处理。
  2. iter(train_dl) 将数据加载器转换为一个迭代器(iterator),使得我们可以使用 Python 的 next() 函数来逐个访问数据加载器中的元素。
  3. next() 函数用于获取迭代器中的下一个元素。在这里,它被用来获取 train_dl 中的下一个批量数据。
  4. imgs, labels = ... 这行代码是 Python 的解构赋值语法。它将从 next() 函数返回的元素中提取出两个变量:imgslabels
  5. imgs 变量将包含一个批量的图像数据,而 labels 变量将包含相应的标签数据。这些图像和标签是从训练数据集中提取的。

3. 数据可视化

squeeze()函数的功能是从矩阵shape中,去掉维度为1的。例如一个矩阵是的shape是(5, 1),使用过这个函数后,结果为(5, )。

python">import numpy as np# 指定图片大小,图像大小为20宽、5高的绘图(单位为英寸inch)
plt.figure(figsize=(20, 5)) 
for i, imgs in enumerate(imgs[:20]):# 维度缩减npimg = np.squeeze(imgs.numpy())# 将整个figure分成2行10列,绘制第i+1个子图。plt.subplot(2, 10, i+1)plt.imshow(npimg, cmap=plt.cm.binary)plt.axis('off')#plt.show()  如果你使用的是Pycharm编译器,请加上这行代码

这段代码的目的是在一个图形窗口中显示多张图像。具体来说,它绘制了前20张图像,并将其显示在一个2行10列的网格中。以下是对每部分代码的详细解释:

import numpy as np

这行代码导入了 numpy 库,它是Python中用于处理数值计算和数组操作的库。

plt.figure(figsize=(20, 5))

plt.figure() 创建一个新的绘图窗口,并指定图像的大小为 20 英寸宽,5 英寸高。这个窗口将用于显示所有子图。

for i, imgs in enumerate(imgs[:20]):

这一行启动了一个循环,遍历 imgs 中的前20个图像。imgs 是一个图像数组,enumerate() 会返回图像的索引 i 和对应的图像 imgsimgs[:20] 表示只取 imgs 中的前20张图像。

npimg = np.squeeze(imgs.numpy())

imgs.numpy() 将图像从Tensor转换为 NumPy 数组,np.squeeze() 用于去除数组中维度为 1 的多余轴,确保图像是一个二维或三维数组(根据具体图像的通道数,如RGB三通道图像是三维的)。

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

plt.subplot(2, 10, i+1) 将整个绘图区域分成 2 行 10 列的网格,并指定当前绘制的子图位置为 (i+1),即第 i+1 个位置(i 从 0 开始)。例如,当 i=0 时,它会将第一张图像绘制在第一个位置。

plt.imshow(npimg, cmap=plt.cm.binary)

plt.imshow(npimg, cmap=plt.cm.binary) 在当前子图上显示图像 npimgcmap=plt.cm.binary 表示使用二进制(黑白)颜色映射来显示图像,这通常用于灰度图像。

plt.axis('off')

plt.axis('off') 禁用当前子图的坐标轴显示,因为通常在图像展示中不需要显示坐标轴。

# plt.show() 如果你使用的是Pycharm编译器,请加上这行代码

注释中的 plt.show() 用于显示图像。如果在 PyCharm 中运行代码,你需要取消注释这一行才能看到绘制的图像。plt.show() 会弹出一个图形窗口,显示所有的子图。

总结

这段代码的主要功能是将 imgs 中的前20张图像绘制到一个 2x10 的网格中,每张图像占用一个子图,并使用黑白色调显示图像。

二、构建简单的CNN网络

对于一般的CNN网络来说,都是由特征提取网络和分类网络构成,其中特征提取网络用于提取图片的特征,分类网络用于将图片进行分类。

  • nn.Conv2d为卷积层,用于提取图片的特征,传入参数为输入channel,输出channel,池化核大小
  • nn.MaxPool2d为池化层,进行下采样,用更高层的抽象表示图像特征,传入参数为池化核大小
  • nn.ReLU为激活函数,使模型可以拟合非线性数据
  • nn.Linear为全连接层,可以起到特征提取器的作用,最后一层的全连接层也可以认为是输出层,传入参数为输入特征数和输出特征数(输入特征数由特征提取网络计算得到,如果不会计算可以直接运行网络,报错中会提示输入特征数的大小,下方网络中第一个全连接层的输入特征数为1600)
  • nn.Sequential可以按构造顺序连接网络,在初始化阶段就设定好网络结构,不需要在前向传播中重新写一遍

网络结构图:

python">import torch.nn.functional as Fnum_classes = 10  # 图片的类别数class Model(nn.Module):def __init__(self):super().__init__()# 特征提取网络self.conv1 = nn.Conv2d(1, 32, kernel_size=3)  # 第一层卷积,卷积核大小为3*3self.pool1 = nn.MaxPool2d(2)                  # 设置池化层,池化核大小为2*2self.conv2 = nn.Conv2d(32, 64, kernel_size=3) # 第二层卷积,卷积核大小为3*3   self.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

这段代码定义了一个用于分类任务的神经网络模型。它使用了卷积神经网络(CNN)的经典结构,通过卷积层提取特征,并使用全连接层进行分类。以下是每一部分的详细解析:

1. 导入必要的库

import torch.nn.functional as F

这里导入了 torch.nn.functional,它包含了许多常用的神经网络操作函数,如激活函数、损失函数等。这里主要使用了其中的 relu 激活函数。

2. 定义类和初始化方法

num_classes = 10

# 图片的类别数

class Model(nn.Module):

   def __init__(self):

    super().__init__()

  • num_classes = 10:设定了分类任务的类别数为 10,通常用于数字分类(如 MNIST 数据集,0-9 的数字分类)。
  • class Model(nn.Module):继承了 nn.Module 类,表示这是一个 PyTorch 的神经网络模型。
  • super().__init__():调用父类 nn.Module 的初始化方法,确保模型的基本结构被正确初始化。

3. 特征提取网络

self.conv1 = nn.Conv2d(1, 32, kernel_size=3) # 第一层卷积,卷积核大小为3*3 self.pool1 = nn.MaxPool2d(2) # 设置池化层,池化核大小为2*2

self.conv2 = nn.Conv2d(32, 64, kernel_size=3) # 第二层卷积,卷积核大小为3*3 self.pool2 = nn.MaxPool2d(2)

  • self.conv1 = nn.Conv2d(1, 32, kernel_size=3):定义了第一层卷积层。输入的图像是单通道(灰度图),输出是 32 个通道,卷积核大小为 3x3。
  • self.pool1 = nn.MaxPool2d(2):定义了最大池化层,池化窗口大小为 2x2。最大池化用于减少空间维度(降维),保留重要特征。
  • self.conv2 = nn.Conv2d(32, 64, kernel_size=3):定义了第二层卷积层,输入是 32 个通道,输出是 64 个通道,卷积核大小为 3x3。
  • self.pool2 = nn.MaxPool2d(2):定义了第二个最大池化层,池化窗口大小同样为 2x2。

4. 分类网络

self.fc1 = nn.Linear(1600, 64)

self.fc2 = nn.Linear(64, num_classes)

  • self.fc1 = nn.Linear(1600, 64):定义了一个全连接层,输入大小为 1600(假设卷积和池化后的特征图大小是 1600),输出大小为 64。这个层将提取到的特征映射到 64 维空间。
  • self.fc2 = nn.Linear(64, num_classes):定义了第二个全连接层,输入大小为 64,输出大小为 num_classes,即 10(根据设定的分类类别数)。

5. 前向传播

def forward(self, x):

x = self.pool1(F.relu(self.conv1(x))) # 卷积层1 -> ReLU 激活 -> 池化层1

x = self.pool2(F.relu(self.conv2(x))) # 卷积层2 -> ReLU 激活 -> 池化层2

x = torch.flatten(x, start_dim=1) # 将多维张量展平成一维,开始维度为1

x = F.relu(self.fc1(x)) # 全连接层1 -> ReLU 激活

x = self.fc2(x) # 全连接层2,输出预测结果 return x

  • x = self.pool1(F.relu(self.conv1(x))):输入 x 经过第一层卷积层 conv1,然后使用 ReLU 激活函数(F.relu),接着通过最大池化层 pool1
  • x = self.pool2(F.relu(self.conv2(x))):同样地,输入 x 经过第二层卷积层 conv2,ReLU 激活,最后通过池化层 pool2
  • x = torch.flatten(x, start_dim=1):将卷积层和池化层的输出展平(flatten),即将多维数组转换成一维。start_dim=1 表示从维度 1 开始展平,这样保持批量维度(batch dimension)不变。
  • x = F.relu(self.fc1(x)):输入展平后的 x 经过全连接层 fc1,然后通过 ReLU 激活函数。
  • x = self.fc2(x):最后,经过第二个全连接层 fc2 输出最终的分类结果(对应每个类别的得分)。

总结

这个模型使用了两层卷积层来提取图像特征,并通过池化层减少空间维度。接着,使用全连接层进行分类,输出每个类别的得分。通过 forward() 函数定义了前向传播流程。

  • 卷积层(Conv2d):用于提取图像中的空间特征。
  • 池化层(MaxPool2d):用于降维,减少计算量,同时保留重要特征。
  • 全连接层(Linear):用于分类,输出各个类别的预测得分。

这个结构是经典的卷积神经网络架构,非常适合图像分类任务。

加载并打印模型

python">from torchinfo import summary
# 将模型转移到GPU中(我们模型运行均在GPU中进行)
model = Model().to(device)summary(model)

三、 训练模型

1. 设置超参数

python">loss_fn    = nn.CrossEntropyLoss() # 创建损失函数
learn_rate = 1e-2 # 学习率
opt        = torch.optim.SGD(model.parameters(),lr=learn_rate)

2. 编写训练函数

1. optimizer.zero_grad()

函数会遍历模型的所有参数,通过内置方法截断反向传播的梯度流,再将每个参数的梯度值设为0,即上一次的梯度记录被清空。

2. loss.backward()

PyTorch的反向传播(即tensor.backward())是通过autograd包来实现的,autograd包会根据tensor进行过的数学运算来自动计算其对应的梯度。

具体来说,torch.tensor是autograd包的基础类,如果你设置tensor的requires_grads为True,就会开始跟踪这个tensor上面的所有运算,如果你做完运算后使用tensor.backward(),所有的梯度就会自动运算,tensor的梯度将会累加到它的.grad属性里面去。

更具体地说,损失函数loss是由模型的所有权重w经过一系列运算得到的,若某个w的requires_grads为True,则w的所有上层参数(后面层的权重w)的.grad_fn属性中就保存了对应的运算,然后在使用loss.backward()后,会一层层的反向传播计算每个w的梯度值,并保存到该w的.grad属性中。

如果没有进行tensor.backward()的话,梯度值将会是None,因此loss.backward()要写在optimizer.step()之前。

3. optimizer.step()

step()函数的作用是执行一次优化步骤,通过梯度下降法来更新参数的值。因为梯度下降是基于梯度的,所以在执行optimizer.step()函数前应先执行loss.backward()函数来计算梯度。

注意:optimizer只负责通过梯度下降进行优化,而不负责产生梯度,梯度是tensor.backward()方法产生的。

python"># 训练循环
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()  # 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_loss

  • pred.argmax(1) 返回数组 pred 在第一个轴(即行)上最大值所在的索引。这通常用于多类分类问题中,其中 pred 是一个包含预测概率的二维数组,每行表示一个样本的预测概率分布。
  • (pred.argmax(1) == y)是一个布尔值,其中等号是否成立代表对应样本的预测是否正确(True 表示正确,False 表示错误)。
  • .type(torch.float)是将布尔数组的数据类型转换为浮点数类型,即将 True 转换为 1.0,将 False 转换为 0.0。
  • .sum()是对数组中的元素求和,计算出预测正确的样本数量。
  • .item()将求和结果转换为标量值,以便在 Python 中使用或打印。

(pred.argmax(1) == y).type(torch.float).sum().item()表示计算预测正确的样本数量,并将其作为一个标量值返回。这通常用于评估分类模型的准确率或计算分类问题的正确预测数量

这段代码实现了一个训练循环,通常用于深度学习模型的训练过程。代码通过循环遍历数据集,在每个批次上进行前向传播、计算损失、反向传播和参数更新。下面是对每部分代码的详细解释:

1. 函数签名和参数解释

def train(dataloader, model, loss_fn, optimizer):

  • dataloader:PyTorch 的数据加载器(DataLoader),用于提供训练数据。在每次迭代中,它会返回一个批次的数据和标签。
  • model:要训练的神经网络模型。
  • loss_fn:损失函数,用于计算网络输出与真实标签之间的差距。
  • optimizer:优化器,用于更新模型的参数。

2. 训练循环初始化

size = len(dataloader.dataset) # 训练集的大小,一共60000张图片

num_batches = len(dataloader) # 批次数目,1875(60000/32)

train_loss, train_acc = 0, 0 # 初始化训练损失和正确率

  • size:数据集的大小,即训练数据中包含的样本数。
  • num_batches:批次数目。数据加载器根据 batch_size 设置将数据分为多个批次,len(dataloader) 返回批次数。
  • train_loss, train_acc:初始化训练过程中的总损失和准确率。

3. 遍历训练数据

for X, y in dataloader: # 获取图片及其标签

X, y = X.to(device), y.to(device)

  • X:输入数据(图像)。
  • y:标签(图像对应的类别)。
  • X, y = X.to(device), y.to(device):将数据和标签移动到指定的设备(如 GPU 或 CPU)。device 可能是 torch.device("cuda")(GPU)或 torch.device("cpu")

4. 计算网络输出和损失

pred = model(X) # 网络输出

loss = loss_fn(pred, y) # 计算网络输出和真实值之间的差距,targets为真实值,计算二者差值即为损失

  • pred = model(X):将输入 X 传入模型 model,得到模型的预测输出 pred
  • loss = loss_fn(pred, y):通过损失函数 loss_fn 计算模型预测输出 pred 和真实标签 y 之间的损失。常见的损失函数有交叉熵损失(CrossEntropyLoss)等。

5. 反向传播和优化

optimizer.zero_grad() # grad属性归零

loss.backward() # 反向传播

optimizer.step() # 每一步自动更新

  • optimizer.zero_grad():清零梯度,避免梯度累加。PyTorch 默认会累积梯度,所以每次更新之前都需要将梯度归零。
  • loss.backward():反向传播,通过损失函数计算梯度,并将其存储在各个模型参数的 .grad 属性中。
  • optimizer.step():根据计算得到的梯度更新模型的参数。

6. 记录准确率和损失

train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()

train_loss += loss.item()

  • (pred.argmax(1) == y)pred.argmax(1) 返回模型预测的类别索引(即每个样本的最大预测值所在的索引),与真实标签 y 比较,得到一个布尔张量。
  • .type(torch.float):将布尔值转换为浮动类型(True 转为 1.0,False 转为 0.0)。
  • .sum().item():计算该批次中的正确预测的数量,并转换为 Python 数字。
  • train_acc += ...:将正确预测的数量累加到 train_acc 中。
  • train_loss += loss.item():将该批次的损失 loss.item()(即一个标量)累加到 train_loss 中。

7. 计算平均准确率和损失

train_acc /= size # 训练准确率 train_loss /= num_batches # 训练损失

  • train_acc /= size:将总正确预测数除以训练集的大小,计算训练集的平均准确率。
  • train_loss /= num_batches:将总损失除以批次数目,计算训练集的平均损失。

8. 返回结果

return train_acc, train_loss

返回训练过程中的平均准确率和平均损失,用于监控模型训练过程的性能。

总结

这个训练循环的目标是通过以下步骤进行模型训练:

  1. 遍历数据集,获取批次数据。
  2. 将数据传入模型并进行预测。
  3. 计算损失函数,衡量预测值与真实值的差距。
  4. 反向传播梯度并更新模型参数。
  5. 记录训练过程中的损失和准确率,并计算其平均值。

这样,训练过程就能不断优化模型参数,使其在给定任务上表现得更好。

3. 编写测试函数

测试函数和训练函数大致相同,但是由于不进行梯度下降对网络权重进行更新,所以不需要传入优化器

python">def test (dataloader, model, loss_fn):size        = len(dataloader.dataset)  # 测试集的大小,一共10000张图片num_batches = len(dataloader)          # 批次数目,313(10000/32=312.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. 正式训练

1. model.train()

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()是利用到了所有网络连接,即不进行随机舍弃神经元。

训练完train样本后,生成的模型model要用来测试样本。在model(test)之前,需要加上model.eval(),否则的话,有输入数据,即使不训练,它也会改变权值。这是model中含有BN层和Dropout所带来的的性质。

python">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')

四、 结果可视化

python">import matplotlib.pyplot as plt
#隐藏警告
import warnings
warnings.filterwarnings("ignore")               #忽略警告信息
plt.rcParams['font.sans-serif']    = ['SimHei'] # 用来正常显示中文标签
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='Training Loss')
plt.plot(epochs_range, test_loss, label='Test Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

五、知识点详解

本文使用的是最简单的CNN模型,如果是第一次接触深度学习的话,可以先试着把代码跑通,然后再尝试去理解其中的代码。

1. MNIST手写数字数据集介绍

MNIST手写数字数据集来源于是美国国家标准与技术研究所,是著名的公开数据集之一。数据集中的数字图片是由250个不同职业的人纯手写绘制,数据集获取的网址为:MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges(下载后需解压)。我们一般会采用(train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data()这行代码直接调用,这样就比较简单

MNIST手写数字数据集中包含了70000张图片,其中60000张为训练数据,10000为测试数据,70000张图片均是28*28,数据集样本如下:

如果我们把每一张图片中的像素转换为向量,则得到长度为28*28=784的向量。因此我们可以把训练集看成是一个[60000,784]的张量,第一个维度表示图片的索引,第二个维度表示每张图片中的像素点。而图片里的每个像素点的值介于0-1之间。

2. 神经网络程序说明

神经网络程序可以简单概括如下


http://www.ppmy.cn/server/144773.html

相关文章

【vim】使用 gn 组合命令实现搜索选中功能

gn是Vim 7.4新增的一个操作(motion),作用是跳到并选中下一个搜索匹配项。 具体说,Vim里执行搜索后,执行n操作只会跳转到下一个匹配项,而不选中它。但是我们往往需要对匹配项执行一些修改操作,例…

【优选算法】KMP模式匹配算法 {算法介绍;算法原理:核心原理,如何求next数组;代码实现}

一、算法介绍 KMP算法,全称Knuth-Morris-Pratt算法,是一种线性时间复杂度的字符串匹配算法。该算法由D.E.Knuth、J.H.Morris和V.R.Pratt提出,因此也称为克努特—莫里斯—普拉特操作。它主要用于在一个较长的字符串(称为主串或目标…

前端入门之VUE--基础与核心

前言 VUE是前端用的最多的框架;这篇文章是本人大一上学习前端的笔记;欢迎点赞 收藏 关注,本人将会持续更新。 Vue学习笔记 用于构建用户界面的渐进式框架 构建用户界面:基于数据动态渲染页面渐进式:循序渐近的学…

JavaScript 不常用方法总结(选中高亮/元素定位应用等)

文章目录 getBoundingClientRect实例应用contenteditablecontenteditable 属性介绍内部文本选中高亮实例,3秒后高亮消失 父元素定位特定子元素内容定位效果方式一:使用JavaScript,在页面加载完成后设置滚动位置(适用于大多数现代浏…

利用Prompt工程为LLM提升推理能力

利用Prompt工程为LLM提升推理能力 基于策略的推理详解ReAct: 推理与行动思维链:逐步解决问题反思:深入分析和自我审查与代理架构的集成实际应用代码附录 众所周知,一个精心设计的Prompt能够显著增强大型语言模型(LLMs)…

1+X应急响应(网络)常见网络攻击-SQL注入:

常见网络攻击-SQL注入: SQL注入概述: 动态网站的工作流程: SQL注入的起源: SQL典型的攻击手段: SQL注入的危害: SQL注入的函数: SQL注入类型: 提交方式分类: Get注入&am…

docker搭建私有仓库,实现镜像的推送和拉取

1.拉取docker仓库镜像 docker pull registry 2.启动registry容器 docker run -d registry 3.查看当前仓库中存在的镜像(一) curl -XGET http://192.168.111.162: 5000/v2/_catalog 192.168.111.162 部署docker仓库宿主机的ip 5000 部署docker仓库映射到宿…

SQL注入--文件读写注入--理论

什么是文件读写注入? MySQL中有 读取文件的函数:load_file() 写入文件的函数:Into outfile(能写入多行,按格式输出)和 into dumpfile(只能写入一行且没有输出格式) 利用这些函数在S…