核心要点

  • .grad 存的是 ∂loss/∂tensor,由 loss.backward() 填充,optimizer.step() 读它来更新参数

  • 只有 requires_grad=True 且是叶子节点(用户创建或 nn.Parameter)的张量才默认保留 .grad

  • 梯度是累加而非覆盖,所以每个 step 前要 zero_grad,否则上一批梯度残留

  • 改值用 .detach() 取无梯度副本,别直接动 .data——后者绕过版本计数会破坏 Autograd 正确性

简要回答

PyTorch 中,.grad 是张量的梯度缓冲区,存储 ∂loss/∂tensor;

要点

  • requires_grad=True 且为叶子节点(用户创建或 nn.Parameter)的张量默认保留 .grad
  • 调用 loss.backward() 后,梯度累加.grad(同 shape、同 dtype)
  • optimizer.step() 读取 .grad 更新 .data
  • 非叶子节点梯度在 backward 后默认释放以省内存

标准回答

在 PyTorch 中,.grad 是张量的梯度缓冲区,存储 ∂loss/∂tensor。

要点

  • requires_grad=True 且为叶子节点(用户创建或 nn.Parameter)的张量默认保留 .grad
  • 调用 loss.backward() 后,梯度累加.grad(同 shape、同 dtype)
  • optimizer.step() 读取 .grad 更新 .data
  • 非叶子节点梯度在 backward 后默认释放以省内存;需 retain_grad() 才保留
python
w = torch.randn(3, 3, requires_grad=True)
loss = w.sum()
loss.backward()
print(w.grad)  # 全 1 矩阵

与 .data 的区别.data 直接暴露底层值、绕过 Autograd 版本检查,是旧 API、易误用;要取无梯度副本应用 .detach()。手动改 .data 不会被记录,可能让反向传播算出错误梯度。

调试:torch.nn.utils.clip_grad_norm_ 裁剪 .grad 防爆炸;param.grad is None 说明未 backward 或不是叶子。详见 反向传播原理

常见误区

⚠️ 常见踩坑

以为每次 backward 会覆盖 .grad;对非 requires_grad 张量期待 .grad;用 .data 改权重导致版本计数错误。

追问

追问 1为什么非叶子节点默认不存 .grad?

中间激活数量巨大,全保留显存爆炸。通常只需参数梯度;若需对中间层梯度(如可解释性),用 register_hook 或 retain_grad()。

追问 2backward 后 .grad 会自动清零吗?

不会。下一次 backward 会把新梯度累加到现有 .grad 上,所以每个 step 前必须手动 optimizer.zero_grad()(或 set_to_none=True)。这个累加设计正是为了支持梯度累积——分多个小 batch 反向、最后一次 step。

追问 3能对 .grad 手动赋值吗?

能。.grad 是普通张量,可在 no_grad 上下文里手动写入或缩放(如梯度裁剪、自定义优化逻辑就是这么干的),optimizer.step() 会照单全收。但要保证形状/dtype 一致,且通常应在 backward 之后、step 之前操作。

延伸学习

与本题相关的知识库文章、术语、工具与行业资讯。

🛠️ AI 工具

  • Pytorch

    Meta 开源的深度学习框架,100K+ stars。以动态计算图和 Pythonic 风格著称,在学术界和工业界都有广泛应用,支持分布式训练、移动端部署和 ONNX 导出

  • Tensorflow

    全球最流行的机器学习框架之一,195K+ stars。Google 开源的端到端 ML 平台,支持 TensorFlow、Keras 等多种 API,覆盖深度学习、强化学习、移动端部署等全场景,是 AI 工程师的必备工具