浅谈PyTorch的可重复性问题(如何使实验结果可复现)

由于在模型训练的过程中存在大量的随机操作,使得对于同一份代码,重复运行后得到的结果不一致。因此,为了得到可重复的实验结果,我们需要对随机数生成器设置一个固定的种子。

许多博客都有介绍如何解决这个问题,但是很多都不够全面,往往不能保证结果精确一致。我经过许多调研和实验,总结了以下方法,记录下来。

全部设置可以分为三部分:

1. CUDNN

cudnn中对卷积操作进行了优化,牺牲了精度来换取计算效率。如果需要保证可重复性,可以使用如下设置:

from torch.backends import cudnn
cudnn.benchmark = False      # if benchmark=True, deterministic will be False
cudnn.deterministic = True

不过实际上这个设置对精度影响不大,仅仅是小数点后几位的差别。所以如果不是对精度要求极高,其实不太建议修改,因为会使计算效率降低。

2. Pytorch

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

3. Python & Numpy

如果读取数据的过程采用了随机预处理(如RandomCrop、RandomHorizontalFlip等),那么对python、numpy的随机数生成器也需要设置种子。

import random
import numpy as np
random.seed(seed)
np.random.seed(seed)

最后,关于dataloader:

注意,如果dataloader采用了多线程(num_workers > 1), 那么由于读取数据的顺序不同,最终运行结果也会有差异。也就是说,改变num_workers参数,也会对实验结果产生影响。目前暂时没有发现解决这个问题的方法,但是只要固定num_workers数目(线程数)不变,基本上也能够重复实验结果。

对于不同线程的随机数种子设置,主要通过DataLoader的worker_init_fn参数来实现。默认情况下使用线程ID作为随机数种子。如果需要自己设定,可以参考以下代码:

GLOBAL_SEED = 1

def set_seed(seed):
  random.seed(seed)
  np.random.seed(seed)
  torch.manual_seed(seed)
  torch.cuda.manual_seed(seed)
  torch.cuda.manual_seed_all(seed)

GLOBAL_WORKER_ID = None
def worker_init_fn(worker_id):
  global GLOBAL_WORKER_ID
  GLOBAL_WORKER_ID = worker_id
  set_seed(GLOBAL_SEED + worker_id)

dataloader = DataLoader(dataset, batch_size=16, shuffle=True, num_workers=2, worker_init_fn=worker_init_fn)

以上这篇浅谈PyTorch的可重复性问题(如何使实验结果可复现)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • pytorch数据预处理错误的解决

    出错: Traceback (most recent call last): File "train.py", line 305, in <module> train_model(model_conv, criterion, optimizer_conv, exp_lr_scheduler) File "train.py", line 145, in train_model for inputs, age_labels, gender_labels in

  • pytorch实现保证每次运行使用的随机数都相同

    其实在代码的开头添加下面几句话即可: # 保证训练时获取的随机数都是一样的 init_seed = 1 torch.manual_seed(init_seed) torch.cuda.manual_seed(init_seed) np.random.seed(init_seed) # 用于numpy的随机数 torch.manual_seed(seed) 为了生成随机数设置种子.返回一个torch.Generator对象 参数: seed (int) – 期望的种子数 torch.cuda.ma

  • pytorch中的inference使用实例

    这里inference两个程序的连接,如目标检测,可以利用一个程序提取候选框,然后把候选框输入到分类cnn网络中. 这里常需要进行一定的连接. #加载训练好的分类CNN网络 model=torch.load('model.pkl') #假设proposal_img是我们提取的候选框,是需要输入到CNN网络的数据 #先定义transforms对输入cnn的网络数据进行处理,常包括resize.totensor等操作 data_transforms=transforms.Compose([trans

  • pytorch模型存储的2种实现方法

    1.保存整个网络结构信息和模型参数信息: torch.save(model_object, './model.pth') 直接加载即可使用: model = torch.load('./model.pth') 2.只保存网络的模型参数-推荐使用 torch.save(model_object.state_dict(), './params.pth') 加载则要先从本地网络模块导入网络,然后再加载参数: from models import AgeModel model = AgeModel()

  • 浅谈PyTorch的可重复性问题(如何使实验结果可复现)

    由于在模型训练的过程中存在大量的随机操作,使得对于同一份代码,重复运行后得到的结果不一致.因此,为了得到可重复的实验结果,我们需要对随机数生成器设置一个固定的种子. 许多博客都有介绍如何解决这个问题,但是很多都不够全面,往往不能保证结果精确一致.我经过许多调研和实验,总结了以下方法,记录下来. 全部设置可以分为三部分: 1. CUDNN cudnn中对卷积操作进行了优化,牺牲了精度来换取计算效率.如果需要保证可重复性,可以使用如下设置: from torch.backends import cu

  • 浅谈pytorch grad_fn以及权重梯度不更新的问题

    前提:我训练的是二分类网络,使用语言为pytorch Varibale包含三个属性: data:存储了Tensor,是本体的数据 grad:保存了data的梯度,本事是个Variable而非Tensor,与data形状一致 grad_fn:指向Function对象,用于反向传播的梯度计算之用 在构建网络时,刚开始的错误为:没有可以grad_fn属性的变量. 百度后得知要对需要进行迭代更新的变量设置requires_grad=True ,操作如下: train_pred = Variable(tr

  • 浅谈pytorch卷积核大小的设置对全连接神经元的影响

    3*3卷积核与2*5卷积核对神经元大小的设置 #这里kerner_size = 2*5 class CONV_NET(torch.nn.Module): #CONV_NET类继承nn.Module类 def __init__(self): super(CONV_NET, self).__init__() #使CONV_NET类包含父类nn.Module的所有属性 # super()需要两个实参,子类名和对象self self.conv1 = nn.Conv2d(1, 32, (2, 5), 1,

  • 浅谈Pytorch torch.optim优化器个性化的使用

    一.简化前馈网络LeNet import torch as t class LeNet(t.nn.Module): def __init__(self): super(LeNet, self).__init__() self.features = t.nn.Sequential( t.nn.Conv2d(3, 6, 5), t.nn.ReLU(), t.nn.MaxPool2d(2, 2), t.nn.Conv2d(6, 16, 5), t.nn.ReLU(), t.nn.MaxPool2d(2

  • 浅谈pytorch中的BN层的注意事项

    最近修改一个代码的时候,当使用网络进行推理的时候,发现每次更改测试集的batch size大小竟然会导致推理结果不同,甚至产生错误结果,后来发现在网络中定义了BN层,BN层在训练过程中,会将一个Batch的中的数据转变成正太分布,在推理过程中使用训练过程中的参数对数据进行处理,然而网络并不知道你是在训练还是测试阶段,因此,需要手动的加上,需要在测试和训练阶段使用如下函数. model.train() or model.eval() BN类的定义见pytorch中文参考文档 补充知识:关于pyto

  • 浅谈pytorch和Numpy的区别以及相互转换方法

    如下所示: # -*- coding: utf-8 -*- # @Time : 2018/1/17 16:37 # @Author : Zhiwei Zhong # @Site : # @File : Numpy_Pytorch.py # @Software: PyCharm import torch import numpy as np np_data = np.arange(6).reshape((2, 3)) # numpy 转为 pytorch格式 torch_data = torch.

  • 浅谈Pytorch中的torch.gather函数的含义

    pytorch中的gather函数 pytorch比tensorflow更加编程友好,所以准备用pytorch试着做最近要做的一些实验. 立个flag开始学习pytorch,新开一个分类整理学习pytorch中的一些踩到的泥坑. 今天刚开始接触,读了一下documentation,写一个一开始每太搞懂的函数gather b = torch.Tensor([[1,2,3],[4,5,6]]) print b index_1 = torch.LongTensor([[0,1],[2,0]]) ind

  • 浅谈pytorch、cuda、python的版本对齐问题

    在使用深度学习模型训练的过程中,工具的准备也算是一个良好的开端吧.熟话说完事开头难,磨刀不误砍柴工,先把前期的问题搞通了,能为后期节省不少精力. 以pytorch工具为例: pytorch版本为1.0.1,自带python版本为3.6.2 服务器上GPU的CUDA_VERSION=9000 注意:由于GPU上的CUDA_VERSION为9000,所以至少要安装cuda版本>=9.0,虽然cuda=7.0~8.0也能跑,但是一开始可能会遇到各种各样的问题,本人cuda版本为10.0,安装cuda的

  • 浅谈pytorch池化maxpool2D注意事项

    注意: 在搭建网络的时候用carpool2D的时候,让高度和宽度方向不同池化时, 用如下: nn.MaxPool2d(kernel_size=2, stride=(2, 1), padding=(0, 1)) 千万不要用: nn.MaxPool2d(kernel_size=2, stride=(2, 1), padding=(0, 0)), 这样在用交叉熵做损失函数的时候,有时候会出现loss为nan的情况,检查的时候发现,某些样本的提取出来的feature全为nan. 以上这篇浅谈pytorc

  • 浅谈pytorch torch.backends.cudnn设置作用

    cuDNN使用非确定性算法,并且可以使用torch.backends.cudnn.enabled = False来进行禁用 如果设置为torch.backends.cudnn.enabled =True,说明设置为使用使用非确定性算法 然后再设置: torch.backends.cudnn.benchmark = true 那么cuDNN使用的非确定性算法就会自动寻找最适合当前配置的高效算法,来达到优化运行效率的问题 一般来讲,应该遵循以下准则: 如果网络的输入数据维度或类型上变化不大,设置 

随机推荐