48

当我想在验证集上评估我的模型的性能时,是首选使用with torch.no_grad:还是model.eval()

4

3 回答 3

63

TL;博士:

两者都使用。他们做不同的事情,并且有不同的范围。

  • with torch.no_grad- 禁用梯度跟踪autograd
  • model.eval()改变forward()调用它的模块的行为
  • 例如,它禁用 dropout 并使用整个人口统计数据进行批量标准化

with torch.no_grad

torch.autograd.no_grad文档 说:

禁用 [原文如此] 梯度计算的上下文管理器。

当您确定不会调用Tensor.backward(). 它将减少计算的内存消耗,否则会有requires_grad=True. 在这种模式下,每次计算的结果都会有requires_grad=False,即使输入有requires_grad=True

model.eval()

nn.Module.eval文档说:

将模块设置为评估模式。

这仅对某些模块有任何影响。如果它们受到影响,请参阅特定模块的文档以了解其在训练/评估模式下的行为的详细信息,例如DropoutBatchNorm等。


pytorch 的创建者说应该更新文档以建议两者的用法,我提出了拉取请求

于 2019-04-11T08:16:55.070 回答
0

with torch.no_grad:禁用后向传递的梯度计算。由于这些计算在推理过程中是不必要的,并且会增加非平凡的计算开销,因此在评估模型的速度时使用此上下文是必不可少的。但不会影响结果。

model.eval()确保某些在训练与推理中表现不同的模块(例如 Dropout 和 BatchNorm)在推理的前向传递期间被适当地定义。因此,如果您的模型包含此类模块,则必须启用此功能。

由于上述原因,在推理过程中同时使用两者是一种很好的做法。

于 2021-03-08T21:00:53.727 回答
0

如果您阅读这篇文章是因为您遇到过RuntimeError: CUDA out of memory,那么with torch.no grad():可能会有助于节省内存。仅使用model.eval()不太可能有助于解决 OOM 错误。

这样做的原因是torch.no grad()完全禁用 autograd(您不能再反向传播),减少内存消耗并加快计算速度。

但是,您仍然可以在使用时调用 gardients model.eval()。就个人而言,我觉得这个设计决定很有趣。那么,这样做的目的是.eval()什么?它的主要功能似乎是在评估期间停用 Dropout。

总而言之,如果您使用torch.no grad(),则不会保存中间张量,并且您可能会增加推理中的批量大小。

于 2022-01-05T23:37:58.680 回答