简要回答
PyTorch 中 optimizer.zero_grad() 或 model.zero_grad() 用于清零梯度;
原因:loss.backward() 将梯度累加到 param.grad(便于梯度累积)
标准回答
PyTorch 中 optimizer.zero_grad() 或 model.zero_grad() 用于清零梯度。
原因:loss.backward() 将梯度累加到 param.grad(便于梯度累积)。若不清零,上一 batch 的梯度残留,等价错误的大 batch 或发散训练。
标准时机——每个训练 step 开始前:
for x, y in loader:
optimizer.zero_grad() # ① 清零
loss = criterion(model(x), y)
loss.backward() # ② 累加梯度
optimizer.step() # ③ 更新set_to_none=True(推荐):optimizer.zero_grad(set_to_none=True) 释放 .grad 引用,略省内存,下轮 backward 重新分配。
例外——梯度累积:每 N 步才 step(),中间步不 zero_grad,手动累积 N 个小 batch 梯度后一次更新,模拟大 batch。详见 深度学习训练技巧。
常见误区
⚠️ 常见踩坑
每 epoch 而非每 step 清零;梯度累积时误每步清零;backward 后忘记 step 只清零。
追问
追问 1:zero_grad 和 grad.zero_() 区别?
optimizer.zero_grad() 是封装好的高层接口,遍历它管理的所有参数并清零(默认 set_to_none=True 把 .grad 置 None);param.grad.zero_() 是手动对单个张量的 .grad 原地清零,只在你想精细控制某些参数时用,且若 .grad 为 None 会报错。日常用前者。
追问 2:忘记 zero_grad 有什么现象?
梯度逐 step 累加越来越大,更新步长失控,表现为 loss 剧烈震荡甚至变 NaN、不收敛。它不会报错,所以很隐蔽——训练发散且找不到代码错误时,先检查是否漏了 zero_grad。
追问 3:推理需要 zero_grad 吗?
不需要。推理不做反向传播、不产生梯度,自然无需清零。正确做法是用 with torch.no_grad()(或 inference_mode)关闭梯度记录并 model.eval(),既省显存又避免 BN/Dropout 行为出错。
延伸学习
与本题相关的知识库文章、术语、工具与行业资讯。
📰 AI 资讯
🛠️ AI 工具
- Pytorch
Meta 开源的深度学习框架,100K+ stars。以动态计算图和 Pythonic 风格著称,在学术界和工业界都有广泛应用,支持分布式训练、移动端部署和 ONNX 导出
- Tensorflow
全球最流行的机器学习框架之一,195K+ stars。Google 开源的端到端 ML 平台,支持 TensorFlow、Keras 等多种 API,覆盖深度学习、强化学习、移动端部署等全场景,是 AI 工程师的必备工具