由于在模型训练的过程中存在大量的随机操作,使得对于同一份代码,重复运行后得到的结果不一致。
因此,为了得到可重复的实验结果,我们需要对随机数生成器设置一个固定的种子。
CUDNN
cudnn中对卷积操作进行了优化,牺牲了精度来换取计算效率。如果需要保证可重复性,可以使用如下设置:
1
2
3
|
from torch.backends import cudnn
cudnn.benchmark = False # if benchmark=True, deterministic will be False
cudnn.deterministic = True
|
不过实际上这个设置对精度影响不大,仅仅是小数点后几位的差别。所以如果不是对精度要求极高,其实不太建议修改,因为会使计算效率降低。
Pytorch
1
2
3
|
torch.manual_seed(seed) # 为CPU设置随机种子
torch.cuda.manual_seed(seed) # 为当前GPU设置随机种子
torch.cuda.manual_seed_all(seed) # 为所有GPU设置随机种子
|
Python & Numpy
如果读取数据的过程采用了随机预处理(如RandomCrop、RandomHorizontalFlip等),那么对python、numpy的随机数生成器也需要设置种子。
1
2
3
4
|
import random
import numpy as np
random.seed(seed)
np.random.seed(seed)
|
Dataloader
如果dataloader采用了多线程(num_workers > 1), 那么由于读取数据的顺序不同,最终运行结果也会有差异。
也就是说,改变num_workers参数,也会对实验结果产生影响。
目前暂时没有发现解决这个问题的方法,但是只要固定num_workers数目(线程数)不变,基本上也能够重复实验结果。
补充:pytorch 固定随机数种子踩过的坑
1.初步固定
1
2
3
4
5
6
7
8
9
10
11
|
def setup_seed(seed):
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.cuda.manual_seed(seed)
np.random.seed(seed)
random.seed(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.enabled = False
torch.backends.cudnn.benchmark = False
#torch.backends.cudnn.benchmark = True #for accelerating the running
setup_seed( 2019 )
|
2.继续添加如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
|
tensor_dataset = ImageList(opt.training_list,transform)
def _init_fn(worker_id):
random.seed( 10 + worker_id)
np.random.seed( 10 + worker_id)
torch.manual_seed( 10 + worker_id)
torch.cuda.manual_seed( 10 + worker_id)
torch.cuda.manual_seed_all( 10 + worker_id)
dataloader = DataLoader(tensor_dataset,
batch_size = opt.batchSize,
shuffle = True ,
num_workers = opt.workers,
worker_init_fn = _init_fn)
|
3.在上面的操作之后发现加载的数据多次试验大部分一致了
但是仍然有些数据是不一致的,后来发现是pytorch版本的问题,将原先的0.3.1版本升级到1.1.0版本,问题解决
4.按照上面的操作后虽然解决了问题
但是由于将cudnn.benchmark设置为False,运行速度降低到原来的1/3,所以继续探索,最终解决方案是把第1步变为如下,同时将该部分代码尽可能放在主程序最开始的部分,例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import torch
import torch.nn as nn
from torch.nn import init
import pdb
import torch.nn.parallel
import torch.nn.functional as F
import torch.backends.cudnn as cudnn
import torch.optim as optim
import torch.utils.data
from torch.utils.data import DataLoader, Dataset
import sys
gpu_id = "3,2"
os.environ[ "CUDA_VISIBLE_DEVICES" ] = gpu_id
print ( 'GPU: ' ,gpu_id)
def setup_seed(seed):
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.cuda.manual_seed(seed)
np.random.seed(seed)
random.seed(seed)
cudnn.deterministic = True
#cudnn.benchmark = False
#cudnn.enabled = False
setup_seed( 2019 )
|
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。如有错误或未考虑完全的地方,望不吝赐教。
原文链接:https://zhengyujie.cn/2291.html