人工智能pytorch框架的梯度计算

核心一句话

y.backward()触发自动微分反向传播的开关 ,不调用它,PyTorch 只会记录计算链路,但不会执行求导、不会计算、不会填充 x.grad

1. 分步拆解执行流程(对应你代码)

第1步:前向传播 y = x ** 2

python 复制代码
x=torch.randn(1,requires_grad=True)
y=x**2
  • requires_grad=True:PyTorch 记录运算历史,给 y 绑定梯度函数 PowBackwardUy.grad_fn);
  • 此时只存"怎么求导"的公式,还没真正计算梯度数值
  • x.grad = None,梯度是空的。

第2步:执行 y.backward()

这一行才开始反向链式求导

  1. 从输出 y 出发,初始化上游梯度 dydy=1\frac{dy}{dy}=1dydy=1;
  2. 进入 PowBackwardU 算子,套用导数公式 dydx=2x\frac{dy}{dx}=2xdxdy=2x;
  3. 梯度流入 AccumulateGrad 节点,把算出的 2x2x2x 存入 x.grad
  4. 执行完毕后,x.grad 才有具体数值。

第3步:out=y.sum() 对你这段代码无影响

你画图传的是 y,不是 out,求和操作不会出现在计算图;且 y 只有1个元素,sum 不改变梯度结果。

2. 关键原理:PyTorch 是惰性求导

PyTorch 遵循「先记录,后计算」:

  1. 前向运算:只记录计算图、保存反向求导函数(grad_fn),不做求导计算,节省算力;
  2. .backward():主动触发反向遍历整张计算图,按链式法则算出所有叶子参数的梯度,写入 .grad 属性。

对比直观理解

  • 前向传播:只是画好求导公式草稿,不算结果;
  • .backward():拿起草稿代入数值算出导数,存到参数梯度里。

3. 补充2个高频疑问

(1)为什么 y 没有 .grad

python 复制代码
print(y.grad) # 输出 None

y 是非叶子张量(中间计算结果),PyTorch 默认只保留叶子参数(x) 的梯度,中间张量梯度计算完直接释放,节约内存。

想保存中间梯度需要手动:y.retain_grad()

(2)能不能不写 .backward() 直接有梯度?

不能。没有任何自动执行反向的机制,训练网络时每一轮都必须调用一次 loss.backward(),否则参数永远无梯度、无法更新。

4. 简化代码演示前后对比

python 复制代码
import torch
x = torch.tensor(2., requires_grad=True)
y = x ** 2

print("调用backward前 x.grad:", x.grad) # None,无梯度

y.backward()
print("调用backward后 x.grad:", x.grad) # tensor(4.),算出梯度2*x=4