Pytorch03-BuildModel&Autograd&Optimization&Save&Load Model

生成模型层

神经网络是按层连接的神经元的集合。 每个神经元都是一个小的计算单元,执行简单的计算来共同解决问题。
神经元分为 3 种类型的层:输入层、隐藏层和输出层。
隐藏层和输出层包含许多神经元。
神经网络模仿人脑处理信息的方式。

  • 神经网络的组成部分

    • 激活函数决定神经元是否应该被激活。
      神经网络中发生的计算包括应用激活函数。
      如果神经元激活,则意味着输入很重要。
      有不同种类的激活函数。 选择使用哪个激活函数取决于您想要的输出。
      激活函数的另一个重要作用是为模型添加非线性。
    • 权重影响我们网络的输出与预期输出值的接近程度。
      当输入进入神经元时,它会乘以权重值,所得输出要么被观察,要么被传递到神经网络中的下一层。
      一层中所有神经元的权重被组织成一个张量。
    • 偏差弥补了激活函数的输出与其预期输出之间的差异。
      低偏差值表明网络对输出形式做出更多假设,而高偏差值对输出形式做出更少假设。
  • 构建神经网络
    神经网络由对数据执行操作的层和模块组成。
    torch.nn 命名空间提供了构建您自己的神经网络所需的所有构建块。
    PyTorch 中的每个模块都是 nn.Module 的子类。 神经网络本身就是一个由其他模块(层)组成的模块。 这种嵌套结构允许轻松构建和管理复杂的架构。

构建一个神经网络来FashionMNIST 数据集中的图像进行分类。

import os
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
  • 获取训练设备
    1

  • 定义类
    我们通过子类化 nn.Module 来定义神经网络,并在__init__ 中初始化神经网络层。
    每个 nn.Module 子类都在 forward 方法中实现对输入数据的操作。
    2

  • 我们创建一个 NeuralNetwork 实例
    将其移动到设备上并打印其结构。
    3

  • 权重与偏差
    nn.Linear 模块随机初始化每层的权重和偏差,并在内部将值存储在张量中。

  • nn.Flatten
    我们初始化 nn.Flatten 层,将每个 2D 28x28 图像转换为 784 个像素值的连续数组,即维持小批量维度(dim=0 时)。 每个像素都被传递到神经网络的输入层。
    1

  • nn.Sequential 是模块的有序容器。 数据按照定义的顺序通过所有模块。 您可以使用顺序容器来组合一个快速网络,例如 seq_modules。
    2

使用 torch.autograd 自动微分

在训练神经网络时,最常用的算法是反向传播。
在该算法中,根据损失函数相对于给定参数的梯度来调整参数(模型权重)。
损失函数计算神经网络产生的预期输出和实际输出之间的差异。 目标是使损失函数的结果尽可能接近于零。
该算法通过神经网络向后遍历来调整权重和偏差来重新训练模型。 这就是为什么它被称为反向传播。
随着时间的推移重新训练模型以将损失减少到 0 的这种前后过程称为梯度下降。

为了计算这些梯度,PyTorch 有一个内置的微分引擎,称为 torch.autograd。 它支持任何计算图的梯度自动计算。

考虑最简单的一层神经网络,具有输入 x、参数 w 和 b 以及一些损失函数。 它可以通过以下方式在 PyTorch 中定义:
3
我们应用于张量来构造计算图的函数是 Function 类的对象。 该对象知道如何向前计算函数,以及如何在向后传播步骤中计算其导数。 对反向传播函数的引用存储在张量的 grad_fn 属性中。
4

  • 计算梯度
    5

我们只能获取将requires_grad属性设置为True的计算图的叶节点的grad属性。 对于我们图中的所有其他节点,梯度将不可用。 此外,出于性能原因,我们只能在给定的图上使用一次后向来执行梯度计算。 如果我们需要在同一个图上进行多次向后调用,我们需要将retain_graph=True传递给向后调用。

  • 禁用梯度跟踪

您可能想要禁用梯度跟踪的原因有:
将神经网络中的某些参数标记为冻结参数。 这是微调预训练网络的非常常见的场景。
当您仅进行前向传递时加快计算速度,因为对不跟踪梯度的张量的计算效率更高。

默认情况下,所有 require_grad=True 的张量都会跟踪其计算历史并支持梯度计算。 然而,有些情况下我们不需要这样做,例如,当我们训练完模型而只想将其应用到一些输入数据时,即我们只想通过网络进行前向计算。

我们可以通过用 torch.no_grad() 块包围我们的计算代码来停止跟踪计算:

6
实现相同结果的另一种方法是在张量上使用 detach() 方法:
7

  • 有关计算图的更多信息

从概念上讲, 在这个 DAG 中,叶子是输入张量,根是输出张量。 通过从根到叶追踪该图,您可以使用链式法则自动计算梯度。

前向传递中,autograd 同时执行两件事:
运行请求的操作来计算结果张量,
并且在 DAG 中维护操作的梯度函数。

当在 DAG 根上调用 .backward() 时,向后传递开始。 然后Autograd
计算每个 .grad_fn 的梯度,
将它们累积到各自张量的 .grad 属性中
使用链式法则,一直传播到叶张量。

PyTorch 中的 DAG 是动态的

需要注意的重要一点是,该图是从头开始重新创建的; 每次 .backward() 调用后,autograd 开始填充新图表。 这正是允许您在模型中使用控制流语句的原因; 如果需要,您可以在每次迭代时更改形状、大小和操作。

优化

  • 优化模型参数
    现在我们有了模型和数据,是时候通过优化数据参数来训练、验证和测试我们的模型了。
    训练模型是一个迭代的过程;在每一次迭代中,模型都会对输出进行猜测,计算猜测的误差(损失),收集误差相对于其参数的导数,并使用梯度下降法优化这些参数。

    • 为训练定义了以下超参数:
      1. Number of Epochs - 在数据集上迭代的次数
      2. Batch Size - 参数更新前通过网络传播的数据样本数量
      3. Learning Rate - 每个batch/epoch更新模型参数的数量。数值越小,学习速度越慢,而数值过大则可能导致训练过程中出现不可预测的行为。
  • 优化循环

设置好超参数后,我们就可以通过优化循环来训练和优化模型。优化循环的每次迭代称为一个epoch。

每个epoch由两个主要部分组成:

  • 训练循环(Train Loop)-- 迭代训练数据集,并尝试收敛到最佳参数。

    • 在训练循环中,优化分三步进行:
    1. 调用 optimizer.zero_grad() 重置模型参数的梯度。梯度默认是累加的;为了防止重复计算,我们在每次迭代时都会明确地将梯度清零。
    2. 调用 loss.backward() 反向传播预测损失。PyTorch 会存入每个参数的损失梯度。
    3. 获得梯度后,我们调用 optimizer.step() 根据后向传递中收集的梯度调整参数。
  • 验证/测试循环(Validation/Test Loop)-- 迭代测试数据集,检查模型性能是否在提高。

  • 损失函数
    常见的损失函数包括用于回归任务的 nn.MSELoss(均方误差)和用于分类的 nn.NLLLoss(负对数似然)。

  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值