必须加 torch.no_grad(),否则推理时仍构建计算图、缓存中间变量,导致显存浪费和速度下降;它与 model.eval() 功能互补,前者禁用梯度记录,后者调整模型行为。

因为不加 torch.no_grad(),PyTorch 仍会默默构建计算图、保存中间变量,白占显存还拖慢速度——哪怕你根本不需要梯度。
推理时显存暴涨,大概率是忘了 torch.no_grad()
PyTorch 的自动微分机制默认全程记录所有张量操作,为可能的 backward() 做准备。但推理阶段根本不会调用 backward(),这些记录全是冗余:
- 中间激活值(如 ResNet 每层输出)会被缓存,而不是即时释放
- 每个参与运算的张量都会绑定
grad_fn,哪怕requires_grad=False,某些内部 buffer(如bn.running_mean)仍可能触发梯度追踪 - 实测:VGG16 批处理 100 张图,加
torch.no_grad()后显存从 3.2GB 降到 1.8GB
model.eval() 和 torch.no_grad() 必须配对用
二者解决的是完全不同的问题,缺一不可:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
-
model.eval()只改模型行为:关掉Dropout、让BatchNorm用移动平均统计量 -
torch.no_grad()只关计算图:禁用所有梯度记录,释放中间内存 - 只调
model.eval()不加torch.no_grad(),Dropout 虽然不随机丢神经元了,但显存照样涨、速度照样慢 - 错误写法:
model.train()放在torch.no_grad()里毫无意义,模型参数虽不更新,但训练模式本身已破坏推理语义
哪些场景必须加 torch.no_grad()?
只要不涉及参数更新或反向传播,就该加:
立即学习“Python免费学习笔记(深入)”;
- 模型部署预测(
model(input)或model.generate(...)) - 特征提取(用预训练 backbone 提取
resnet.layer3输出) - 计算评估指标(
accuracy、loss.item()等标量值) - 注意:
loss.item()本身不依赖梯度,但若loss是从带梯度的计算图中来的,不加torch.no_grad()仍会保留整条链路
容易被忽略的细节
torch.no_grad() 是上下文管理器,不是装饰器;它不改变张量的 requires_grad 属性,只临时屏蔽梯度追踪:
- 块内创建的新张量默认
requires_grad=False,但块外原有张量的requires_grad=True不变 - 它和
torch.set_grad_enabled(False)功能等价,但后者需手动恢复,风险更高 - 某些封装好的方法(如
model.generate)内部已自带@torch.no_grad(),重复包裹无害但没必要

















