作用
在 PyTorch 中,.backward() 是张量(Tensor)的一个方法,用于自动计算梯度(求导)。
PyTorch 会通过构建计算图(Computational Graph)记录张量的运算过程,调用 .backward() 时,会从当前张量(通常是标量损失值)出发,沿着计算图 反向传播,计算出图中所有依赖张量的梯度,并将梯度存储到对应张量的 .grad 属性中。
前提
只有设置了 requires_grad=True 的张量,才会被追踪运算并计算梯度(默认是 False)。
例子
1. 对标量张量调用 .backward()(最常用场景)
这是训练模型时的核心场景(损失函数输出是标量),无需传入参数:
import torch
# 1. 定义需要求导的张量
x = torch.tensor([2.0], requires_grad=True)
y = torch.tensor([3.0], requires_grad=True)
# 2. 构建计算图:z = x² + y³
z = x**2 + y**3
# 3. 反向传播,计算梯度
z.backward()
# 4. 查看梯度(dz/dx = 2x, dz/dy = 3y²)
print("dz/dx =", x.grad) # 输出:tensor([4.])
print("dz/dy =", y.grad) # 输出:tensor([27.])
2. 对矩阵张量调用 .backward()
如果要对向量/矩阵调用 .backward(),必须传入一个与当前张量形状相同的 gradient 参数(相当于“梯度的权重”),本质是计算“当前张量 × 传入梯度”的标量对各参数的梯度:
import torch
# 定义张量
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
# 非标量输出:y = 2x
y = 2 * x
# 对y反向传播,需传入gradient参数(比如全1向量)
y.backward(gradient=torch.ones_like(y))
# 查看梯度(dy/dx = 2)
print("dy/dx =", x.grad) # 输出:tensor([2., 2., 2.])
注意事项
梯度累加问题
PyTorch 不会自动清空 .grad 属性,多次调用 .backward() 会导致梯度累加。因此在训练模型时,每次反向传播前需要用 optimizer.zero_grad() 清空梯度:
# 示例:模拟训练循环中的梯度清空
x = torch.tensor([2.0], requires_grad=True)
for _ in range(2):
y = x**2
y.backward()
print(x.grad) # 第一次输出tensor([4.]), 第二次输出tensor([8.])
# 正确做法:清空梯度
x.grad.zero_() # 或 optimizer.zero_grad()
y = x**2
y.backward()
print(x.grad) # 输出tensor([4.])
计算图的保留与释放
默认情况下,调用 .backward() 后,计算图会被销毁(节省内存)。如果需要多次反向传播(如RNN训练),需设置 retain_graph=True:
x = torch.tensor([2.0], requires_grad=True)
y = x**2
y.backward(retain_graph=True) # 保留计算图
print(x.grad) # tensor([4.])
y.backward() # 可再次调用,计算图最终销毁
print(x.grad) # tensor([8.])
禁止梯度计算
如果不需要计算梯度(如验证/测试阶段),可以用 torch.no_grad() 上下文管理器,避免构建计算图,提升效率:
x = torch.tensor([2.0], requires_grad=True)
with torch.no_grad():
y = x**2
# y.backward() # 此处调用会报错,因为no_grad下不追踪梯度
print(y.requires_grad) # 输出:False
总结
.backward()的核心作用是反向传播计算梯度,梯度会存储在张量的.grad属性中,仅对requires_grad=True的张量有效。- 标量张量调用
.backward()无需传参,非标量需传入同形状的gradient参数。 - 关键注意点:训练时需用
zero_grad()清空梯度,多次反向传播需设置retain_graph=True,无需梯度时用torch.no_grad()提升效率。