3.2 练习

在使用torch.autograd.grad计算二阶导数时,可以仅设置create_graph=True而无需设置retain_graph=True。以下是关键点总结:
-
create_graph的作用:
当设置为True时,会保留梯度计算图,使得后续能对梯度再次求导(如计算二阶导数)。这是高阶导数计算的关键参数。 -
retain_graph的作用:
控制是否在反向传播后保留整个计算图。默认False会释放计算图以节省内存,但在多次调用backward()或grad()时需设置为True以避免图被提前释放。 -
二阶导数的场景:
- 计算一阶导数时,需设置
create_graph=True,以便保留梯度计算图用于二阶导数。 - 此时即使
retain_graph=False,PyTorch仍会保留一阶导数的计算图(因create_graph=True),故无需额外设置retain_graph=True。
- 计算一阶导数时,需设置
-
示例验证:
import torch x = torch.tensor([2.0], requires_grad=True) y = x ** 3 # 一阶导数:create_graph=True,retain_graph=False dy_dx = torch.autograd.grad(y, x, create_graph=True, retain_graph=False)[0] print("一阶导数:", dy_dx) # tensor([12.]) # 二阶导数:直接使用一阶导数的计算图 d2y_dx2 = torch.autograd.grad(dy_dx, x, retain_graph=False)[0] print("二阶导数:", d2y_dx2) # tensor([12.])此代码能正确运行,证明即使
retain_graph=False,二阶导数仍可计算。
结论:
在计算二阶导数时,仅需在一阶导数计算中设置create_graph=True,无需额外设置retain_graph=True。PyTorch会自动保留必要的计算图部分,而释放无关部分以优化内存。
在 PyTorch 中,torch.autograd.grad 的行为与数学中的向量对向量导数略有不同,其设计更贴合深度学习中的实际需求(如反向传播的链式法则)。以下是详细解释:
1. 向量对向量导数的数学定义
数学中,若 y = f(x) 是向量函数(x 和 y 均为向量),则导数是一个雅可比矩阵 (Jacobian Matrix),其维度为 (dim_y, dim_x),每个元素为:
例如,若 x 和 y 均为 2 维向量:
则雅可比矩阵为:
2. PyTorch 的 torch.autograd.grad 行为
PyTorch 的自动微分机制默认设计用于标量对张量的导数(如损失函数对参数的梯度)。当输入和输出均为向量时,torch.autograd.grad 不会直接返回雅可比矩阵,而是通过 grad_outputs 参数实现更灵活的梯度传播。
关键参数 grad_outputs
- 作用:指定一个与
y同形状的“权重向量”,用于计算加权和的梯度。 - 数学意义:计算的是雅可比矩阵与
grad_outputs的乘积:\[\text{result} = J^T \cdot \text{grad\_outputs} \]其中 \(J\) 是雅可比矩阵,grad_outputs是外部梯度。
你的代码分析
x = torch.randn((2), requires_grad=True)
y = x ** 3
dy = torch.autograd.grad(
outputs=y,
inputs=x,
grad_outputs=torch.ones(x.shape), # 关键参数
retain_graph=True,
create_graph=True
)
grad_outputs=torch.ones(x.shape):
等价于对y的每个分量赋予权重 1,计算的是雅可比矩阵与全 1 向量的乘积:\[\text{dy} = J^T \cdot [1, 1] = \begin{bmatrix} 3x_1^2 \cdot 1 + 0 \cdot 1 \\ 0 \cdot 1 + 3x_2^2 \cdot 1 \end{bmatrix} = \begin{bmatrix} 3x_1^2 \\ 3x_2^2 \end{bmatrix} \]因此dy是一个与x同形状的向量,而非雅可比矩阵。
3. 如何获取完整的雅可比矩阵?
若需要显式计算雅可比矩阵,有以下两种方法:
方法 1:逐分量计算梯度
jacobian = []
for i in range(len(y)):
# 对 y[i] 求梯度,grad_outputs 中仅第 i 个位置为 1
dy_i = torch.autograd.grad(
outputs=y[i],
inputs=x,
grad_outputs=torch.tensor(1.0),
retain_graph=True
)[0]
jacobian.append(dy_i)
jacobian = torch.stack(jacobian)
print(jacobian) # 形状为 (2, 2)
方法 2:使用 torch.autograd.functional.jacobian
PyTorch 提供了直接计算雅可比矩阵的工具:
from torch.autograd.functional import jacobian
x = torch.randn(2, requires_grad=True)
y = x ** 3
J = jacobian(func=lambda x: x**3, inputs=x)
print(J) # 形状为 (2, 2)
4. 参数 retain_graph 和 create_graph 的作用
-
retain_graph=True:
保留计算图,允许后续多次调用backward()或grad()。若不设置,计算图会在第一次求导后被释放。 -
create_graph=True:
保留梯度计算图,使得可以对梯度再次求导(如计算二阶导数)。
在你的代码中,设置 create_graph=True 是为了后续可能的高阶导数计算(如对 dy 再求导),而 retain_graph=True 确保计算图不被释放。
5. 总结
- 向量对向量导数在数学中是雅可比矩阵,但
torch.autograd.grad默认返回的是 雅可比矩阵与grad_outputs的乘积(结果为向量)。 - 若需完整雅可比矩阵,需显式逐分量计算或使用
jacobian()函数。 - 参数
grad_outputs决定了梯度传播的权重,是理解grad()行为的关键。

浙公网安备 33010602011771号