应通过调用model.eval()
将模型设置为评估模式以进行推理。
如果不这样做,那么训练时期的前向传递的输出可能会受到 dropout 随机性的影响?
许多示例代码都没有这样做,常见的方法是:
for t in range(num_epochs):
# forward pass
yhat = model(x)
# get the loss
loss = criterion(yhat , y)
# backward pass, optimizer step
optimizer.zero_grad()
loss.backward()
optimizer.step()
例如,这里有一个示例代码:卷积神经网络/main.py
这应该是吗?
for t in range(num_epochs):
# forward pass
model.eval() # disable dropout etc
yhat = model(x)
# get the loss
loss = criterion(yhat , y)
# backward pass, optimizer step
model.train()
optimizer.zero_grad()
loss.backward()
optimizer.step()
TLDR:
这应该是吗?
不!
为什么?
更多说明:
不同的模块根据是否处于训练模式或评估/测试模式而表现不同。
BatchNorm
和Dropout
只是此类模块的两个示例,基本上任何具有训练阶段的模块都遵循此规则。.eval()
时,您就向模型中的所有模块发出信号以相应地转移操作。
更新
答案是在训练期间你不应该使用
eval
模式,是的,只要你没有设置 eval 模式,dropout 就会处于活动状态并在每次前向传递中随机动作。同样,具有两个阶段的所有其他模块也将相应地执行。也就是说,BN 总是会更新每次传递的平均值/var,而且如果您使用的 batch_size 为 1,则会出错,因为它无法使用 1 的批次执行 BN
正如评论中指出的那样,应该注意的是,在训练期间,您不应该在
forward pass之前执行
eval()
,因为它会有效地禁用具有不同阶段的训练/测试模式的所有模块,例如BN和Dropout(基本上任何具有可更新/可学习参数或影响网络拓扑(如 Dropout)的模块)将被禁用,您将不会看到它们对您的网络学习做出贡献。所以不要这样编码!
让我解释一下训练期间发生的事情:
当您处于训练模式时,构成模型的所有模块可能有两种模式:训练模式和测试模式。这些模块要么具有需要在训练期间更新的可学习参数,例如 BN,要么在某种意义上影响网络拓扑,例如 Dropout(通过在前向传递期间禁用某些功能)。有些模块(例如 ReLU())仅在一种模式下运行,因此当模式改变时不会有任何变化。
当您处于训练模式时,您输入图像,它通过槽层直到面临丢失,在这里,某些功能被禁用,因此省略了对下一层的响应,输出进入其他层直到到达结束网络,您就可以得到预测。
网络可能有正确或错误的预测,从而相应地更新权重。如果答案是正确的,则导致正确答案的特征/特征组合将受到积极影响,反之亦然。 因此,在训练期间,您不需要也不应该禁用 dropout,因为它会影响输出并且应该影响输出,以便模型学习一组更好的特征。