11,PyTorch 梯度计算与反向传播

在这里插入图片描述

11. PyTorch 梯度计算与反向传播

在 PyTorch 中,梯度计算与反向传播是自动求导机制的核心功能,它们使得我们能够高效地训练神经网络模型。通过自动求导,PyTorch 能够根据计算图自动计算出每个张量的梯度,从而为优化算法提供必要的信息。本节将详细介绍 PyTorch 中梯度计算与反向传播的工作原理、使用方法以及一些常见的问题和解决方法。

11.1 梯度计算与反向传播的工作原理

在 PyTorch 中,梯度计算与反向传播是基于计算图的。当一个张量的 requires_grad 属性被设置为 True 时,PyTorch 会自动跟踪该张量的所有操作,并构建一个动态计算图。这个计算图记录了张量之间的依赖关系以及操作的顺序。在执行反向传播时,PyTorch 会从计算图的输出节点开始,沿着计算图的反向路径,逐层计算每个张量的梯度。

例如,假设我们有一个简单的计算过程 ( y = (x + 2)^2 ),其中 ( x ) 是一个输入张量,且 ( x ) 的 requires_grad 属性被设置为 True。在这个计算过程中,PyTorch 会构建一个计算图,如下所示:

x -> (x + 2) -> (x + 2)^2 -> y

当调用 y.backward() 时,PyTorch 会从 ( y ) 开始,沿着计算图的反向路径,逐层计算每个张量的梯度。具体来说,反向传播的过程如下:

  1. 计算 ( y ) 关于 ( (x + 2)^2 ) 的梯度:
    [
    \frac{\partial y}{\partial (x + 2)^2} = 1
    ]

  2. 计算 ( (x + 2)^2 ) 关于 ( (x + 2) ) 的梯度:
    [
    \frac{\partial (x + 2)^2}{\partial (x + 2)} = 2(x + 2)
    ]

  3. 计算 ( (x + 2) ) 关于 ( x ) 的梯度:
    [
    \frac{\partial (x + 2)}{\partial x} = 1
    ]

  4. 最终,计算 ( y ) 关于 ( x ) 的梯度:
    [
    \frac{\partial y}{\partial x} = \frac{\partial y}{\partial (x + 2)^2} \cdot \frac{\partial (x + 2)^2}{\partial (x + 2)} \cdot \frac{\partial (x + 2)}{\partial x} = 1 \cdot 2(x + 2) \cdot 1 = 2(x + 2)
    ]

在实际代码中,这个过程是自动完成的:

import torch

# 定义输入张量,并设置 requires_grad=True
x = torch.tensor(2.0, requires_grad=True)

# 定义计算过程
y = (x + 2) ** 2

# 反向传播
y.backward()

# 查看梯度
print("x 的梯度:", x.grad)

输出结果为:

x 的梯度: tensor(8.)

11.2 梯度计算与反向传播的使用方法

11.2.1 调用 backward() 方法

在 PyTorch 中,梯度计算是通过调用 backward() 方法完成的。backward() 方法会从调用它的张量开始,沿着计算图的反向路径,逐层计算每个张量的梯度。默认情况下,backward() 方法会计算标量张量的梯度。如果需要计算向量张量的梯度,则需要提供一个与输出张量形状相同的张量作为参数。

例如,假设我们有一个向量张量 ( y = [y_1, y_2] ),其中 ( y_1 = x_1^2 ) 和 ( y_2 = x_2^2 ),且 ( x ) 是一个输入张量,其形状为 ([2])。为了计算 ( y ) 关于 ( x ) 的梯度,我们需要提供一个与 ( y ) 形状相同的张量作为参数:

import torch

# 定义输入张量,并设置 requires_grad=True
x = torch.tensor([2.0, 3.0], requires_grad=True)

# 定义计算过程
y = x ** 2

# 反向传播
y.backward(torch.tensor([1.0, 1.0]))

# 查看梯度
print("x 的梯度:", x.grad)

输出结果为:

x 的梯度: tensor([4., 6.])

11.2.2 梯度累加

在某些情况下,我们可能需要对多个损失函数进行反向传播,并累加梯度。PyTorch 允许我们在调用 backward() 方法时,不清空梯度信息,从而实现梯度累加。

例如,假设我们有两个损失函数 ( L_1 ) 和 ( L_2 ),它们分别依赖于同一个输入张量 ( x )。我们可以通过多次调用 backward() 方法,并将梯度累加起来:

import torch

# 定义输入张量,并设置 requires_grad=True
x = torch.tensor([2.0, 3.0], requires_grad=True)

# 定义两个损失函数
L1 = x ** 2
L2 = x ** 3

# 第一次反向传播
L1.backward(torch.tensor([1.0, 1.0]), retain_graph=True)

# 第二次反向传播
L2.backward(torch.tensor([1.0, 1.0]))

# 查看梯度
print("x 的梯度:", x.grad)

输出结果为:

x 的梯度: tensor([12., 45.])

在上述代码中,retain_graph=True 参数的作用是保留计算图,以便进行多次反向传播。

11.3 常见问题与解决方法

11.3.1 RuntimeError: element 0 of tensors does not require grad

这个错误通常发生在调用 backward() 方法时,计算图中的某些张量的 requires_grad 属性被设置为 False。为了解决这个问题,需要确保所有参与计算的张量的 requires_grad 属性都被设置为 True

例如:

import torch

# 定义输入张量,并设置 requires_grad=True
x = torch.tensor([2.0, 3.0], requires_grad=True)

# 定义计算过程
y = x ** 2

# 调用 backward() 方法
y.backward(torch.tensor([1.0, 1.0]))

# 查看梯度
print("x 的梯度:", x.grad)

如果某些张量的 requires_grad 属性被设置为 False,则会报错:

import torch

# 定义输入张量,并设置 requires_grad=True
x = torch.tensor([2.0, 3.0], requires_grad=True)

# 定义计算过程
y = x ** 2

# 将 y 的 requires_grad 属性设置为 False
y.requires_grad_(False)

# 调用 backward() 方法
y.backward(torch.tensor([1.0, 1.0]))

输出结果为:

RuntimeError: element 0 of tensors does not require grad

11.3.2 RuntimeError: one of the variables needed for gradient computation has been modified in place

这个错误通常发生在对参与计算的张量进行原地操作(in-place operation)时。PyTorch 不允许对参与计算的张量进行原地操作,因为这会破坏计算图的完整性。为了解决这个问题,需要避免对参与计算的张量进行原地操作。

例如:

import torch

# 定义输入张量,并设置 requires_grad=True
x = torch.tensor([2.0, 3.0], requires_grad=True)

# 定义计算过程
y = x ** 2

# 对 y 进行原地操作
y += 1

# 调用 backward() 方法
y.backward(torch.tensor([1.0, 1.0]))

输出结果为:

RuntimeError: one of the variables needed for gradient computation has been modified in place

为了避免这个错误,可以使用非原地操作:

import torch

# 定义输入张量,并设置 requires_grad=True
x = torch.tensor([2.0, 3.0], requires_grad=True)

# 定义计算过程
y = x ** 2
**更多技术文章见公众号:  大城市小农民**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乔丹搞IT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值