pytorch模型复现踩坑记, upsample不可靠

先说结论:

pytorch的上采用模块具有随机性,为了复现模型建议使用nearest模式,不要轻易使用trilinear!

固定随机种子使模型可复现在具体实验中是非常重要的。网上提供了许多操作方法,简单粗暴就是上如下代码:

manual_seed = config.get('manual_seed', None)
        if manual_seed is not None:
            logger.info(f'Seed the RNG for all devices with {manual_seed}')
            os.environ['PYTHONHASHSEED'] = str(manual_seed)
            torch.manual_seed(manual_seed)
            torch.cuda.manual_seed(manual_seed)
            torch.cuda.manual_seed_all(manual_seed)  # if you are using multi-GPU
            random.seed(manual_seed)
            np.random.seed(manual_seed)
            torch.backends.cudnn.deterministic = True
            torch.backends.cudnn.benchmark = False
            torch.backends.cudnn.enabled = True

在主函数开头运行上述代码段,固定随机种子,能解决大部分问题

但是,仍有一部分模型在训练和测试时无法复现

为了避免重复造轮子,不可能所有模型都从0开始写,用一些public的代码是非常必要的。但不同的人习惯不一样,模型结构也不一样,不是每一个模型都能顺利的调通,特别是在遇到无法复现的时候,根本找不出问题在哪里!

例如,扒拉了一个代码,固定随机种子后,在相同的参数下重复跑两次,最初几个epoch的loss,dice都是相同的,但在某一次开始,loss的最后几位小数开始发生变化,再过几个epoch后变化越来越大,然后就变得毫无关系了。重复多次,都无法复现实验结果。

pytorch模型复现踩坑记, upsample不可靠_第1张图片

通过重复实验和测试,发现问题出在nn.upsample中

不添加upsample,使用反卷积时,模型可复现;使用upsample后,模型便出现上述不确定的情况。

也有网友指出,upsample导致模型可复现性变差,这一点在PyTorch的官方库issue#12207中有提到

原文中说you can try to make the operation deterministic ... by setting torch.backends.cudnn.deterministic = True

这里是try ***,不是you can  。

 

在我的实验中测试的公开代码中有如下模块

self.conv = UnetConv3(in_size + out_size, out_size, is_batchnorm, kernel_size=(3,3,3), padding_size=(1,1,1))
self.up = nn.Upsample(scale_factor=(2, 2, 2), mode='trilinear')

这是Unet的上采样过程,这里加入了deep supervision,所以和丐版Unet中的上采样有区别:

self.conv = UnetConv3(in_size, out_size, is_batchnorm)
self.up = nn.ConvTranspose3d(in_size, out_size, kernel_size=(4,4,1), stride=(2,2,1), padding=(1,1,0))

这两个地方都为了扩大featuremap,但使用了不同的层。同时,两个模型的其他地方也没明显的区别。

在之前我自己写的模块中,也用到了反卷积和上采样,那么问题就出在了mode上

pytorch模型复现踩坑记, upsample不可靠_第2张图片

upsample的方式有好几种,我之前可复现的模型中使用的是neareast,而这里是trilinear (处理的三维图像)

将模型改为如下:

self.conv = UnetConv3(in_size + out_size, out_size, kernel_size=(3,3,3), padding_size=(1,1,1))
self.up = nn.Upsample(scale_factor=(2, 2, 2), mode='nearest')

又经过重复实验,复现成功!

 

参考资料:

https://www.shuzhiduo.com/A/q4zVxqbx5K/

https://pytorch.org/docs/stable/nn.functional.html?highlight=upsample#torch.nn.functional.upsample

https://zhuanlan.zhihu.com/p/109166845

你可能感兴趣的:(深度学习,神经网络,pytorch,深度学习)