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

PyTorch 基础学习(7)- 自动微分

系列文章:
PyTorch 基础学习(1) - 快速入门
PyTorch 基础学习(2)- 张量 Tensors
PyTorch 基础学习(3) - 张量的数学操作
PyTorch 基础学习(4)- 张量的类型
PyTorch 基础学习(5)- 神经网络
PyTorch 基础学习(6)- 函数API

自动微分的作用

在深度学习和机器学习中,自动微分是用于计算梯度的核心技术。梯度在优化过程中起着至关重要的作用,它们用于调整模型参数以最小化损失函数。通过计算模型输出相对于输入参数的梯度,自动微分可以帮助我们在反向传播算法中高效地更新模型参数。

自动微分工具包的应用场景

torch.autograd 是 PyTorch 中用于自动微分的工具包,它主要应用于以下场景:

  1. 神经网络训练:在反向传播过程中自动计算损失函数相对于模型参数的梯度。
  2. 优化算法:使用梯度信息来优化模型参数,使损失函数达到极小值。
  3. 复杂计算图的求导:支持对任意复杂计算图的自动求导,方便进行自定义模型和损失函数的优化。

自动求导的基本使用

使用 torch.autograd.backward 函数
import torch
from torch.autograd import Variable# 创建一个张量并包装在Variable中
x = Variable(torch.tensor([1.0, 2.0, 3.0]), requires_grad=True)# 定义一个简单的标量函数
y = x.sum()# 计算梯度
y.backward()# 输出梯度
print(x.grad)  # 输出: tensor([1., 1., 1.])

在上面的代码中,我们定义了一个标量函数 y = x.sum(),并使用 y.backward() 计算梯度。由于 y 是一个标量,因此我们不需要为 backward() 函数提供额外的参数。

处理非标量输出

如果输出不是标量(例如一个向量),我们需要在调用 backward() 时提供 grad_variables 参数,该参数用于指定与输出同形状的梯度。

z = x * 2# 指定每个输出元素的梯度
z.backward(torch.tensor([1.0, 1.0, 1.0]))print(x.grad)  # 输出: tensor([3., 3., 3.]) (之前的梯度已累积)

在这个例子中,我们计算了 z = x * 2 的梯度,并指定了一个与 z 同形状的梯度 [1.0, 1.0, 1.0],使得每个元素都被正确求导。

使用 retain_graph 参数

当我们需要对同一个计算图多次进行求导时,可以使用 retain_graph=True 来保留中间计算结果:

y = x.sum()
y.backward(retain_graph=True)
y.backward()  # 可以多次调用

Variable 对象

VariableTensor 的一个封装,记录了对其进行的操作。对于在 Variable 上进行的每一个操作,autograd 都会记录操作历史,从而支持反向传播。

在 PyTorch 0.4 及以后的版本中,Variable 已经合并到 Tensor 中,默认的 Tensor 就支持自动求导。

钩子(Hooks)

可以在 Variable 上注册钩子函数,每次计算梯度时都会调用这些钩子。钩子不应修改输入,但可以返回新的梯度。

def hook_fn(grad):return grad * 2v = Variable(torch.tensor([0.0, 0.0, 0.0]), requires_grad=True)
h = v.register_hook(hook_fn)v.backward(torch.tensor([1.0, 1.0, 1.0]))
print(v.grad)  # 输出: tensor([2., 2., 2.])h.remove()  # 移除钩子

在这个例子中,我们注册了一个钩子函数,该函数将梯度值加倍。

强化学习中的奖励

在涉及随机操作的计算图中,必须在随机节点的输出上调用 reinforce() 方法来提供奖励值:

reward = torch.tensor([0.5, 0.5, 0.5])
v.reinforce(reward)

创建自定义 Function

自定义的 Function 可以通过子类化 torch.autograd.Function 来定义。用户需要实现 forwardbackward 方法。

class MyReLU(torch.autograd.Function):@staticmethoddef forward(ctx, input):ctx.save_for_backward(input)return input.clamp(min=0)@staticmethoddef backward(ctx, grad_output):input, = ctx.saved_tensorsgrad_input = grad_output.clone()grad_input[input < 0] = 0return grad_input

在这个自定义 ReLU 函数中,我们在 forward 方法中使用 ctx.save_for_backward() 保存输入张量,并在 backward 方法中通过 ctx.saved_tensors 获取它来计算梯度。

应用实例:多层前馈神经网络

下面是一个完整的应用实例脚本,该脚本展示了如何使用 torch.autograd 进行自动微分,并结合了教程中的多个元素,包括自定义函数、梯度计算、钩子、和使用 retain_graph 参数。这个例子中,我们将实现一个简单的多层感知器(MLP),并使用自定义激活函数进行训练。

import torch
from torch.autograd import Function# 自定义激活函数ReLU
class MyReLU(Function):@staticmethoddef forward(ctx, input):ctx.save_for_backward(input)return input.clamp(min=0)@staticmethoddef backward(ctx, grad_output):input, = ctx.saved_tensorsgrad_input = grad_output.clone()grad_input[input < 0] = 0return grad_input# 定义模型
class SimpleMLP(torch.nn.Module):def __init__(self):super(SimpleMLP, self).__init__()self.linear1 = torch.nn.Linear(2, 4)self.linear2 = torch.nn.Linear(4, 1)def forward(self, x):relu = MyReLU.applyx = relu(self.linear1(x))x = torch.sigmoid(self.linear2(x))return x# 生成简单的数据集
torch.manual_seed(0)
x_data = torch.tensor([[0.0, 0.0],[0.0, 1.0],[1.0, 0.0],[1.0, 1.0]], requires_grad=True)
y_data = torch.tensor([[0.0], [1.0], [1.0], [0.0]], requires_grad=False)# 初始化模型和优化器
model = SimpleMLP()
criterion = torch.nn.BCELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)# 训练模型
for epoch in range(1000):# 前向传播y_pred = model(x_data)# 计算损失loss = criterion(y_pred, y_data)# 反向传播optimizer.zero_grad()loss.backward(retain_graph=True)optimizer.step()# 打印损失if epoch % 100 == 0:print(f'Epoch {epoch}, Loss: {loss.item()}')# 注册钩子,修改梯度
def hook_fn(grad):print('Gradient before modification:', grad)return grad * 0.5  # 将梯度值减半# 选择一个参数进行钩子注册
handle = model.linear1.weight.register_hook(hook_fn)# 进行一次前向和后向传播以触发钩子
y_pred = model(x_data)
loss = criterion(y_pred, y_data)
optimizer.zero_grad()
loss.backward()# 移除钩子
handle.remove()# 再次输出模型参数的梯度以检查修改效果
print('Model parameters after training:')
for param in model.parameters():print(param.grad)# 测试模型
with torch.no_grad():print('Testing the model:')test_data = torch.tensor([[0.0, 0.0],[0.0, 1.0],[1.0, 0.0],[1.0, 1.0]])predictions = model(test_data)print(predictions)

代码说明

  1. 自定义激活函数 MyReLU:使用 torch.autograd.Function 创建了一个自定义的 ReLU 激活函数,该函数在反向传播中实现了梯度的自定义计算。

  2. 定义模型 SimpleMLP:使用两层线性层实现一个简单的多层感知器(MLP)。

  3. 数据集:创建了一个简单的 XOR 数据集作为训练和测试数据。

  4. 训练循环:在训练过程中,通过调用 loss.backward() 来计算梯度,并使用优化器 optimizer.step() 更新模型参数。

  5. 注册钩子:在模型参数上注册一个钩子函数,用于修改反向传播过程中计算得到的梯度。

  6. 测试模型:在训练完成后,用测试数据集评估模型的输出。

这个例子展示了如何在 PyTorch 中使用自动微分进行模型训练,并通过钩子和自定义函数增强梯度计算的灵活性。

总结

torch.autograd 提供了灵活而强大的自动微分功能,通过简单地封装张量,并使用 backward() 方法,可以很方便地进行梯度计算。掌握这些技巧可以帮助我们更高效地进行深度学习模型的训练和优化。无论是自定义的损失函数还是特殊的网络结构,自动微分都能帮助我们轻松计算梯度,推动模型的优化和提升。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【计算机人接私活】手把手教你上手挖到第一个漏洞,从底薪3k到月入过万,只有一步之遥!
  • C语言 ——— 枚举类型的定义及其优点
  • Qt-多种方式实现helloworld(6)
  • 技术周总结08.12-08.18周日(C#开发环境搭建 Linux命令)
  • 蓝图中结构体改变后,要重新创建widget
  • 系统开发之禁止卸载应用名单
  • 图卷积(GCN)
  • 第一章——数组基础(概念篇python版)
  • Android+Jacoco+code-diff全量、增量覆盖率生成实战
  • 共享经济背景下校园、办公闲置物品交易平台-计算机毕设Java|springboot实战项目
  • 系统架构设计师 - 软件工程(2)
  • Mysql面试一
  • 【数据结构算法经典题目刨析(c语言)】使用栈实现队列(图文详解)
  • javaEE中自定义注解以及注解的解析
  • CSP部分模拟题题解
  • 〔开发系列〕一次关于小程序开发的深度总结
  • docker python 配置
  • ES6 学习笔记(一)let,const和解构赋值
  • java正则表式的使用
  • mac修复ab及siege安装
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • Sass Day-01
  • Selenium实战教程系列(二)---元素定位
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • 从PHP迁移至Golang - 基础篇
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 构建二叉树进行数值数组的去重及优化
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 入口文件开始,分析Vue源码实现
  • 微服务框架lagom
  • nb
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • ​学习笔记——动态路由——IS-IS中间系统到中间系统(报文/TLV)​
  • #pragam once 和 #ifndef 预编译头
  • #window11设置系统变量#
  • $refs 、$nextTic、动态组件、name的使用
  • (02)vite环境变量配置
  • (14)Hive调优——合并小文件
  • (9)目标检测_SSD的原理
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (附源码)计算机毕业设计高校学生选课系统
  • (六)Flink 窗口计算
  • (每日一问)设计模式:设计模式的原则与分类——如何提升代码质量?
  • (南京观海微电子)——示波器使用介绍
  • (七)理解angular中的module和injector,即依赖注入
  • (三) diretfbrc详解
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .NET Core 2.1路线图
  • .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)...
  • .Net的C#语言取月份数值对应的MonthName值
  • .NET开源项目介绍及资源推荐:数据持久层 (微软MVP写作)
  • .Net下使用 Geb.Video.FFMPEG 操作视频文件
  • .NET应用架构设计:原则、模式与实践 目录预览
  • @ModelAttribute注解使用
  • @RequestMapping-占位符映射