代码
在深度学习训练中,为什么使用同样的代码,与和作者/别人得到的结果不一样,或者每次跑同一个实验得到的结果都不一样。
上述问题主要涉及到 随机数/随机种子 的设定,当我们 设置了具体的随机种子 之后,每次实验所使用的随机数将是一致的,进而得到的实验结果也会保持一致。
可以将这段代码添加到 PyCharm 的 活动模板(Live Template) 中
import numpy as np
import torch
import random
import os
seed_value = 2020 # 设定随机数种子
np.random.seed(seed_value) # Numpy 的随机种子
random.seed(seed_value) # random 库的随机种子
os.environ['PYTHONHASHSEED'] = str(seed_value) # 为了禁止 hash 随机化,使得实验可复现
torch.manual_seed(seed_value) # 为 CPU 设置随机种子
torch.cuda.manual_seed(seed_value) # 为当前 GPU 设置随机种子(只用一块 GPU)
torch.cuda.manual_seed_all(seed_value) # 为所有 GPU 设置随机种子(多块 GPU)
torch.backends.cudnn.deterministic = True
喜欢省流的读者可以就此打住。
下面对上述代码进行更一步的说明,主要包括三个方面:
Python 和 Numpy 的随机数
PyTorch 的随机数
cuDNN 的随机数
Python 和 Numpy 的随机数
如果读取数据的过程采用了 随机预处理(如 RandomCrop
、RandomHorizontalFlip
等),那么对 python、numpy 的随机数生成器也需要设置种子。
np.random.seed(seed_value) # Numpy 的随机种子
random.seed(seed_value) # random 库的随机种子
os.environ['PYTHONHASHSEED'] = str(seed_value) # 为了禁止 hash 随机化,使得实验可复现
关于 os.environ['PYTHONHASHSEED']
的详细描述,参见 Python 3.5 文档:Environment variables:PYTHONHASHSEED
PyTorch 的随机数
在 PyTorch 中,会对 模型的权重 等进行初始化,因此也要设定随机数种子。
torch.manual_seed(seed_value) # 为 CPU 设置随机种子
torch.cuda.manual_seed(seed_value) # 为当前 GPU 设置随机种子(只用一块 GPU)
torch.cuda.manual_seed_all(seed_value) # 为所有 GPU 设置随机种子(多块 GPU)
另外,也有人提到说 dataloder 中,可能由于 读取顺序不同,也会造成结果的差异。
这主要是由于 dataloader 采用了 多线程,即 num_workers > 1
。目前暂时没有发现解决这个问题的方法,但是只要 固定 num_workers
数目(线程数)不变,基本上也能够重复实验结果。
cuDNN 的随机数
cuDNN 中对 卷积操作 进行了优化,牺牲了精度来换取计算效率。如果需要保证可重复性,可以使用如下设置:
torch.backends.cudnn.deterministic = True
参考
Python 3.5 文档:Environment variables:PYTHONHASHSEED
文档信息
- 本文作者:Bookstall
- 本文链接:https://bookstall.github.io/2023/02/20/pytorch-reproduced-settings/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)