600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > 不同PyTorch版本训练同一个代码结果差异巨大

不同PyTorch版本训练同一个代码结果差异巨大

时间:2023-12-15 12:45:41

相关推荐

不同PyTorch版本训练同一个代码结果差异巨大

问题描述

笔者在训练一个深度学习网络时,发现使用不同的PyTorch版本运行同一个训练代码,训练出来的网络结果差异巨大。具体来说,笔者训练得到的结果如下所示:

网络的参数以及训练的设置完全相同,但是却得到了差异巨大的结果。


原因分析

发现在Torchvision>0.6.0时,模型的训练出现了很大的问题,特别是后面两个版本的训练中,损失函数一直无法降下去,因此断定在预处理部分代码可能存在Bug。

经过检查,发现在Torchvision=0.7.0版本时出现了一个更新:

[Transforms] Usetorch.randinstead ofrandom.random()for random transforms (#2520)

而我的代码中,预训练部分只设置了random.seed(seed)np.random.seed(seed),由此导致图像和标签的预训练产生的随机不一致,故导致高版本时训练的损失函数迟迟不能下降。

Torchvision=0.7.0及以后的版本中torchvision.transforms.RandomHorizontalFlip()源码为:

class RandomHorizontalFlip(torch.nn.Module):"""Horizontally flip the given image randomly with a given probability.If the image is torch Tensor, it is expectedto have [..., H, W] shape, where ... means an arbitrary number of leadingdimensionsArgs:p (float): probability of the image being flipped. Default value is 0.5"""def __init__(self, p=0.5):super().__init__()self.p = pdef forward(self, img):"""Args:img (PIL Image or Tensor): Image to be flipped.Returns:PIL Image or Tensor: Randomly flipped image."""if torch.rand(1) < self.p:return F.hflip(img)return imgdef __repr__(self):return self.__class__.__name__ + '(p={})'.format(self.p)

Torchvision=0.6.0及以前的版本中torchvision.transforms.RandomHorizontalFlip()源码为:

class RandomHorizontalFlip(object):"""Horizontally flip the given PIL Image randomly with a given probability.Args:p (float): probability of the image being flipped. Default value is 0.5"""def __init__(self, p=0.5):self.p = pdef __call__(self, img):"""Args:img (PIL Image): Image to be flipped.Returns:PIL Image: Randomly flipped image."""if random.random() < self.p:return F.hflip(img)return imgdef __repr__(self):return self.__class__.__name__ + '(p={})'.format(self.p)

显然,它们产生随机数的函数是不同的。

Torchvision=0.6.0及以前的版本中使用torchvision.transforms下的函数时,可以只设置random函数的随机种子,但是这样不保险,程序在更高版本时则会出现Bug。


解决方案

由于在Torchvision=0.7.0及以后的版本中预处理的随机数改为torch.rand,因此需要对 PyTorch 设置随机种子:

torch.manual_seed(seed) # 为CPU设置随机种子torch.cuda.manual_seed(seed) # 为当前GPU设置随机种子torch.cuda.manual_seed_all(seed) # 为所有GPU设置随机种子

统一起来可以这样设置:

def set_seed(seed):random.seed(seed)np.random.seed(seed)torch.manual_seed(seed) # cputorch.cuda.manual_seed(seed) # gputorch.cuda.manual_seed_all(seed) # all gpus

设置完之后再次用四种版本进行训练,结果如下:


举一反三

写代码时,首先考虑同一环境下同一代码的可重复性,即让Pytorch是Deterministic(确定)的。可以参考如下文章:

PyTorch的可重复性问题 (如何使实验结果可复现)Deterministic Pytorch: pytorch如何保证可重复性

把这一个工作做踏实也避免了后续的Bug。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。