使用 pytorch 训练和测试 CNN。有和没有 model.eval()

Posted

技术标签:

【中文标题】使用 pytorch 训练和测试 CNN。有和没有 model.eval()【英文标题】:Training and testing CNN with pytorch. With and without model.eval() 【发布时间】:2019-09-20 17:53:38 【问题描述】:

我有两个问题:-

    我正在尝试训练一个用一些预先训练的权重初始化的卷积神经网络(Netwrok 也包含批量归一化层)(参考here)。在训练之前,我想使用loss_fn = torch.nn.MSELoss().cuda() 计算验证错误。 在参考文献中,作者在计算验证错误之前使用了model.eval()。但是有了这个结果,CNN 模型偏离了它应该是的状态,但是当我注释掉 model.eval() 时,输出很好(预训练的权重应该是什么)。这背后的原因是什么,正如我在许多帖子中看到的那样,在测试模型之前应该使用model.eval,在训练模型之前应该使用model.train()

    在使用预先训练的权重和上述损失函数计算验证误差时,批量大小应该是多少。它不应该是 1,因为我想在每个输入上输出,用基本事实计算误差,最后取所有结果的平均值。如果我使用更高的批量大小错误会增加。所以问题是我可以使用更高的批量大小,如果是的话应该是正确的方法。在给定的代码中,我给出了err = float(loss_local) / num_samples,但我观察到没有平均,即err = float(loss_local)。不同批次大小的误差是不同的。我现在在没有model.eval 的情况下这样做。

    batch_size = 1
    data_path = 'path_to_data'
    dtype = torch.FloatTensor
    weight_file = 'path_to_weight_file'
    val_loader = torch.utils.data.DataLoader(NyuDepthLoader(data_path, val_lists),batch_size=batch_size, shuffle=True, drop_last=True)
    model = Model(batch_size)
    model.load_state_dict(load_weights(model, weight_file, dtype))
    loss_fn = torch.nn.MSELoss().cuda()
    # model.eval()

    with torch.no_grad():
        for input, depth in val_loader:
            input_var = Variable(input.type(dtype))
            depth_var = Variable(depth.type(dtype))

            output = model(input_var)

            input_rgb_image = input_var[0].data.permute(1, 2, 0).cpu().numpy().astype(np.uint8)
            input_gt_depth_image = depth_var[0][0].data.cpu().numpy().astype(np.float32)
            pred_depth_image = output[0].data.squeeze().cpu().numpy().astype(np.float32)
            print (format(type(depth_var)))
            pred_depth_image_resize = cv2.resize(pred_depth_image, dsize=(608, 456), interpolation=cv2.INTER_LINEAR)
            target_depth_transform = transforms.Compose([flow_transforms.ArrayToTensor()])
            pred_depth_image_tensor = target_depth_transform(pred_depth_image_resize)
            #both inputs to loss_fn are 'torch.Tensor'
            loss_local += loss_fn(pred_depth_image_tensor, depth_var)

            num_samples += 1
            print ('num_samples '.format(num_samples))

    err = float(loss_local) / num_samples
    print('val_error before train:', err)

【问题讨论】:

请为问题单独发帖以缩小范围,并与How to Ask保持一致。此外,对于您的第一个问题,PyTorch 参考资料对此主题进行了大量讨论。 【参考方案1】:

这可能是什么原因,正如我在许多帖子中所读到的那样,在测试模型之前应该使用 model.eval,在训练之前应该使用 model.train()。

注意:测试模型称为推理。

如官方documentation解释:

请记住,在运行推理之前,您必须调用 model.eval() 将 dropout 和批量归一化层设置为评估模式。不这样做会产生不一致的推理结果。

因此,一旦您从文件加载模型并进行推理,此代码必须存在。

# Model class must be defined somewhere
model = torch.load(PATH)
model.eval()

这是因为 dropout 在训练过程中用作防止过拟合的正则化,推理不需要它。批次规范也是如此。 当您使用eval() 时,这只会将模块序列标签设置为False,并且仅影响某些类型的模块,尤其是DropoutBatchNorm

【讨论】:

以上是关于使用 pytorch 训练和测试 CNN。有和没有 model.eval()的主要内容,如果未能解决你的问题,请参考以下文章

AI常用框架和工具丨13. PyTorch实现基于CNN的手写数字识别

AI常用框架和工具丨13. PyTorch实现基于CNN的手写数字识别

AI常用框架和工具丨13. PyTorch实现基于CNN的手写数字识别

PyTorch从头搭建并训练一个神经网络模型(图像分类CNN)

PyTorch从头搭建并训练一个神经网络模型(图像分类CNN)

3. 使用PyTorch深度学习库训练第一个卷积神经网络CNN