PyTorch入门实践: PyTorch自动微分与优化技术入门

部署运行你感兴趣的模型镜像

PyTorch autograd教程

学习目标

通过本课程,学员可掌握PyTorch自动微分机制的核心原理:理解requires_grad属性构建动态计算图的原理,通过grad_fn追踪梯度路径;掌握反向传播流程,学会用loss.backward()计算梯度及优化器的梯度清零操作;针对模型推理、参数冻结等场景,学习使用torch.no_grad()和detach()方法禁用梯度跟踪,有效提升计算效率与资源利用率。

相关知识点

  • 自动微分与计算图
  • 梯度计算与反向传播控制

学习内容

1 自动微分与计算图

在深度学习领域,自动微分是一项至关重要的技术,它为神经网络的训练提供了高效的梯度计算方法。在传统的神经网络训练中,反向传播算法用于计算损失函数关于模型参数(如权重和偏置)的梯度,以便通过梯度下降等优化算法来调整参数,使模型的预测结果更接近真实值。

%matplotlib inline
1.1 使用torch.autograd实现自动微分

在训练神经网络时,最常用的算法是
反向传播。在该算法中,参数(模型权重)为
根据损失函数的梯度调整
到给定参数。

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

考虑最简单的一层神经网络,输入x
参数wb,以及一些损失函数。它可以定义在
PyTorch的使用方式如下

import torch

x = torch.ones(5)  # input tensor
y = torch.zeros(3)  # expected output
w = torch.randn(5, 3, requires_grad=True)
b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w)+b
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)
1.2 张量、函数和计算图

这段代码定义了以下计算图

图1 计算图

在这个网络中,wb是参数,我们需要
因此,我们需要能够计算损失的梯度
函数关于这些变量。为了做到这一点,我们设置
这些张量的requires_grad属性。

<div style="background-color: #54c7ec; color: #fff; font-weight: 700; padding-left: 10px; padding-top: 5px; padding-bottom: 5px"><strong>NOTE:</strong></div>

<div style="background-color: #f3f4f7; padding-left: 10px; padding-top: 10px; padding-bottom: 10px; padding-right: 10px">

<p>您可以在创建张量时设置<code>requires_grad</code>的值,也可以在以后使用<code>x.requires_grad_(True)</code>方法。</p>
</div>


我们应用于张量来构造计算图的函数是
实际上是Function类的对象。这个对象知道如何计算
向前方向的函数,以及如何计算其
反向传播步骤中的导数。引用了
反向传播函数存储在的grad_fn属性中
张量。你可以在文档中找到Function

print(f"Gradient function for z = {z.grad_fn}")
print(f"Gradient function for loss = {loss.grad_fn}")
1.3 更多关于计算图的信息

从概念上讲,autograd保存了一个数据记录(张量),所有执行有向无圈中的运算(以及生成的新张量)图形(DAG)由
函数
对象。在这个DAG中,叶子是输入张量,根是输出张量。通过从根到叶跟踪此图,可以使用链式法则自动计算梯度。

在正向传递中,autograd同时做两件事:

  • 运行请求的操作以计算生成的张量。
  • 在DAG中维护操作的梯度函数

当在DAG上调用.backward()时,向后传递开始
根。autograd然后:

  • 计算每个.grad_fn的梯度。
  • 将它们累加到相应张量的.grad属性中。
  • 使用链式法则,一直传播到叶张量。
NOTE:

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

2 梯度计算与反向传播控制

为了优化神经网络中参数的权重,我们需要计算损失函数相对于参数的导数,即,我们需要 ∂ l o s s ∂ w \frac{\partial loss}{\partial w} wloss ∂ l o s s ∂ b \frac{\partial loss}{\partial b} blossx的一些固定值下“y”。为了计算这些导数,我们调用“loss.backward()”,然后从w.gradb.grad中检索值:

loss.backward()
print(w.grad)
print(b.grad)
NOTE:
  • 我们只能获得计算图的叶子节点的grad属性,这些叶子节点的requires_grad属性设置为True。对于我们图中的所有其他节点,梯度将不可用。-出于性能原因,我们只能在给定图中使用backward执行一次梯度计算。如果我们需要在同一个图上执行多个backward调用,我们需要将retain_graph=True传递给back调用。
2.1 张量梯度和雅可比积(可选)

在很多情况下,我们有一个标量损失函数,我们需要计算
相对于某些参数的梯度。然而,也有一些案例
当输出函数是任意张量时。在这种情况下,PyTorch
允许您计算所谓的雅可比乘积,而不是实际的
梯度。

对于向量函数 y ⃗ = f ( x ⃗ ) \vec{y}=f(\vec{x}) y =f(x ),其中
x ⃗ = ⟨ x 1 , … , x n ⟩ \vec{x}=\langle x_1,\dots,x_n\rangle x =x1,,xn
y ⃗ = ⟨ y 1 , … , y m ⟩ \vec{y}=\langle y_1,\dots,y_m\rangle y =y1,,ym,一个梯度 y ⃗ \vec{y} y
关于 x ⃗ \vec{x} x 雅可比矩阵给出:

J = ( ∂ y 1 ∂ x 1 ⋯ ∂ y 1 ∂ x n ⋮ ⋱ ⋮ ∂ y m ∂ x 1 ⋯ ∂ y m ∂ x n ) \begin{aligned} J=\left(\begin{array}{ccc} \frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{1}}{\partial x_{n}}\\ \vdots & \ddots & \vdots\\ \frac{\partial y_{m}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}} \end{array}\right) \end{aligned} J= x1y1x1ymxny1xnym

而不是计算Jacobian矩阵本身,PyTorch允许你
对给定的输入向量计算Jacobian积 v T ⋅ J v^T\cdot J vTJ
v = ( v 1 … v m ) v=(v_1 \dots v_m) v=(v1vm)这是通过使用 v v v作为调用backward来实现的
的争论。 v v v的大小应该与
原始张量,我们要计算其乘积:

inp = torch.eye(4, 5, requires_grad=True)
out = (inp+1).pow(2).t()
out.backward(torch.ones_like(out), retain_graph=True)
print(f"First call\n{inp.grad}")
out.backward(torch.ones_like(out), retain_graph=True)
print(f"\nSecond call\n{inp.grad}")
inp.grad.zero_()
out.backward(torch.ones_like(out), retain_graph=True)
print(f"\nCall after zeroing gradients\n{inp.grad}")
注意,当我们第二次调用`backward`时,同样
参数,梯度的值是不同的。发生这种情况是因为
在进行`backward`传播时,PyTorch **会累积
Grads**,即将计算的梯度值添加到`grad`
计算图的所有叶子节点的属性。如果你想
计算适当的梯度,需要将`grad`属性归零
在实际训练中,*优化器*帮助我们做到这一点。

NOTE:

之前我们调用的是不带参数的backward()函数。这本质上等同于调用backward(torch.tensor(1.0)),这是在标量值函数的情况下(例如神经网络训练期间的损失)计算梯度的有用方法。

2.2 禁用梯度跟踪

在深度学习模型的训练和推理过程中,有时我们并不需要跟踪所有张量的梯度信息。例如,当模型训练完成后,我们只想将其应用于新的输入数据进行推理,此时只需要进行前向传播计算,不需要计算梯度,跟踪梯度信息反而会消耗额外的内存和计算资源。另外,在某些情况下,我们可能希望将神经网络中的某些参数标记为冻结参数,即不希望这些参数在训练过程中更新,这也需要禁用这些参数的梯度跟踪。

默认情况下,所有具有requires_grad=True的张量都在跟踪它们的
计算历史,并支持梯度计算。然而,有
在某些情况下,我们不需要这样做,例如,当我们
训练了模型,只是想将其应用于一些输入数据,即我们
只希望通过网络进行转发计算。我们可以停止
通过将我们的计算代码包围为
torch.no_grad()块:

z = torch.matmul(x, w)+b
print(z.requires_grad)

with torch.no_grad():
    z = torch.matmul(x, w)+b
print(z.requires_grad)

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

z = torch.matmul(x, w)+b
z_det = z.detach()
print(z_det.requires_grad)

您可能需要禁用梯度跟踪的原因如下:

  • 将神经网络中的某些参数标记为冻结参数
  • 当您只执行前向传递时,可以加快计算速度,因为在不跟踪梯度的张量上进行计算会更高效。

您可能感兴趣的与本文相关的镜像

GPT-oss:20b

GPT-oss:20b

图文对话
Gpt-oss

GPT OSS 是OpenAI 推出的重量级开放模型,面向强推理、智能体任务以及多样化开发场景

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值