当我想在验证集上评估我的模型的性能时,是首选使用with torch.no_grad:
还是model.eval()
?
3 回答
TL;博士:
with torch.no_grad
- 禁用梯度跟踪autograd
。model.eval()
改变forward()
调用它的模块的行为- 例如,它禁用 dropout 并使用整个人口统计数据进行批量标准化
with torch.no_grad
禁用 [原文如此] 梯度计算的上下文管理器。
当您确定不会调用
Tensor.backward()
. 它将减少计算的内存消耗,否则会有requires_grad=True
. 在这种模式下,每次计算的结果都会有requires_grad=False
,即使输入有requires_grad=True
。
model.eval()
将模块设置为评估模式。
这仅对某些模块有任何影响。如果它们受到影响,请参阅特定模块的文档以了解其在训练/评估模式下的行为的详细信息,例如
Dropout
、BatchNorm
等。
with torch.no_grad:
禁用后向传递的梯度计算。由于这些计算在推理过程中是不必要的,并且会增加非平凡的计算开销,因此在评估模型的速度时使用此上下文是必不可少的。但不会影响结果。
model.eval()
确保某些在训练与推理中表现不同的模块(例如 Dropout 和 BatchNorm)在推理的前向传递期间被适当地定义。因此,如果您的模型包含此类模块,则必须启用此功能。
由于上述原因,在推理过程中同时使用两者是一种很好的做法。
如果您阅读这篇文章是因为您遇到过RuntimeError: CUDA out of memory
,那么with torch.no grad():
可能会有助于节省内存。仅使用model.eval()
不太可能有助于解决 OOM 错误。
这样做的原因是torch.no grad()
完全禁用 autograd(您不能再反向传播),减少内存消耗并加快计算速度。
但是,您仍然可以在使用时调用 gardients model.eval()
。就个人而言,我觉得这个设计决定很有趣。那么,这样做的目的是.eval()
什么?它的主要功能似乎是在评估期间停用 Dropout。
总而言之,如果您使用torch.no grad()
,则不会保存中间张量,并且您可能会增加推理中的批量大小。