PyTorch 中的 torch.no

PyTorch 中的 torch.no

PyTorch 中的 torch.no_grad(): 用途、常见问题与替代方案

2025-11-23

我会使用友好的简体中文来为您详细说明。

torch.no_grad() 是一个用于禁用梯度计算(Gradient Calculation)的上下文管理器(Context Manager)。在 PyTorch 中,梯度计算是自动微分系统(Autograd)的核心功能,主要用于训练神经网络。

当您在 with torch.no_grad(): 块内执行前向传播(Forward Pass)时,PyTorch 会做两件主要的事情

停止跟踪历史记录 对于在该块内创建的或操作后产生的 Tensors,Autograd 不会记录它们的操作历史,这使得它们不会参与后续的反向传播(Backward Pass)。

减少内存消耗 由于不需要存储中间激活值和计算图信息用于反向传播,可以显著节省内存。

加快计算速度 禁用梯度计算也能稍微提高执行速度。

您应该在不需要进行学习和权重更新的阶段使用它

模型推断/预测(Inference) 对新数据进行预测。

模型评估/验证(Evaluation/Validation) 计算模型在验证集或测试集上的性能指标。

权重初始化 在不希望影响梯度历史记录的情况下对权重进行操作。

torch.no_grad() 只禁用梯度计算,但它不会改变模型中特定层(如 Dropout 或 BatchNorm)的行为。

问题 在评估时只使用了 torch.no_grad(),但忘记调用 model.eval()。

结果 像 Dropout 这样的层会继续随机丢弃神经元,而 BatchNorm 层会使用当前批次的统计信息(均值和方差)而不是全局统计信息,导致评估结果不稳定或不准确。

# 错误的示例

model.train() # 假设模型当前处于训练模式

# ... 加载数据

with torch.no_grad():

output = model(data)

# 此时,Dropout仍然是激活的,BatchNorm仍然在更新/使用批次统计

# 正确的做法

model.eval() # 切换到评估模式,禁用Dropout,使用BatchNorm的全局统计

# ... 加载数据

with torch.no_grad():

output = model(data)

# 记得在继续训练前切换回去

# model.train()

问题 意外地将需要计算梯度的代码(例如,在自定义损失函数中)放到了 torch.no_grad() 块内。

结果 块内的 Tensors 的 .grad 属性将是 None,导致后续的 loss.backward() 无法正确计算梯度,模型参数也就无法更新。

问题 在 torch.no_grad() 块内创建了一个需要梯度的张量,然后将其传递给 Autograd 期望张量具有梯度的函数。这通常不是直接的错误,但会让人困惑。

这是 torch.no_grad() 的底层实现,它提供了一个更灵活的控制方式。

torch.no_grad() 相当于 with torch.set_grad_enabled(False):

如果您需要在不同模式之间动态切换,或者需要函数级别的控制,可以使用这个。

## 示例:使用 set_grad_enabled

is_training = False # 假设我们正在进行评估

# 方法 A: 上下文管理器 (与 no_grad 类似)

with torch.set_grad_enabled(is_training):

# 如果 is_training 为 True,则启用梯度;如果为 False (评估),则禁用

y = model(x)

# 方法 B: 针对单个操作的检查

if torch.is_grad_enabled():

# 只有在梯度启用时才执行梯度相关的操作

print("梯度已启用")

如果您只需要对某个特定的张量禁用梯度跟踪,而不是整个代码块,可以使用 .detach()。这常用于需要从计算图中“取出”一个张量作为常数使用。

作用 返回一个与原张量共享底层数据的新张量,但从当前的计算图分离。返回的张量不再需要梯度。

## 示例:使用 .detach()

a = torch.tensor([1.0], requires_grad=True)

b = a * 2

# 从计算图中分离 b,得到 c

# c 不会跟踪历史记录,也不会参与 a 的梯度计算

c = b.detach()

d = c + 3 # d 的操作也不会被跟踪

e = d * 4 # e 的操作也不会被跟踪

print(f"b 是否需要梯度: {b.requires_grad}") # True

print(f"c 是否需要梯度: {c.requires_grad}") # False

# 如果执行 e.backward(),只有 b 和 a 会有梯度(通过 a * 2 -> b 这条路径)

总结

功能torch.no_grad()Tensor.detach()粒度代码块(全局禁用)单个张量(局部禁用)使用场景模型评估/推断将一个张量作为常数使用返回值无(上下文管理器)一个新张量希望这个解释对您有所帮助!如果您还有其他关于 PyTorch 或深度学习的问题,请随时告诉我。

相关推荐

《天天飞车》介绍:天天飞车有哪些人物角色?
精神疾病全疗程治疗要多久?如何判断“治好了”
手机软件服务器请求超时怎么解决
手机怎么修改宽带密码
《英雄联盟》2024创建账号方法
GQ怎么样,GQ好不好