核心要点
.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() 才保留
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 改权重导致版本计数错误。
追问
追问 2:backward 后 .grad 会自动清零吗?
不会。下一次 backward 会把新梯度累加到现有 .grad 上,所以每个 step 前必须手动 optimizer.zero_grad()(或 set_to_none=True)。这个累加设计正是为了支持梯度累积——分多个小 batch 反向、最后一次 step。
追问 3:能对 .grad 手动赋值吗?
能。.grad 是普通张量,可在 no_grad 上下文里手动写入或缩放(如梯度裁剪、自定义优化逻辑就是这么干的),optimizer.step() 会照单全收。但要保证形状/dtype 一致,且通常应在 backward 之后、step 之前操作。
延伸学习
与本题相关的知识库文章、术语、工具与行业资讯。
📰 AI 资讯
🛠️ AI 工具
- Pytorch
Meta 开源的深度学习框架,100K+ stars。以动态计算图和 Pythonic 风格著称,在学术界和工业界都有广泛应用,支持分布式训练、移动端部署和 ONNX 导出
- Tensorflow
全球最流行的机器学习框架之一,195K+ stars。Google 开源的端到端 ML 平台,支持 TensorFlow、Keras 等多种 API,覆盖深度学习、强化学习、移动端部署等全场景,是 AI 工程师的必备工具