Pytorch随机种子设置及原理
深度学习网络模型中初始的权值参数通常都是初始化成随机数,而使用梯度下降法最终得到的局部最优解对于初始位置点的选择很敏感,下面介绍Pytorch中随机种子的设置及其原理。
1. Pytorch随机种子设置
在同一开发环境中,随机数种子seed确定时,模型的训练结果将始终保持一致。
def setup_seed(seed):
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
np.random.seed(seed)
random.seed(seed)
torch.backends.cudnn.deterministic = True
# 设置随机数种子
setup_seed(20)
# 预处理数据以及训练模型
-
统一随机种子仍然无法复现实验结果的原因
-
其他配置具体操作解读
-
CuDnn
- cuDnn中对卷积操作进行了优化,牺牲了精度来换取计算效率。如果需要保证可重复性,可以使用如下设置:
from torch.backends import cudnn cudnn.benchmark = False # if benchmark=True, deterministic will be False cudnn.deterministic = True
不过实际上这个设置对精度影响不大,仅仅是小数点后几位的差别。所以如果不是对精度要求极高,其实不太建议修改,因为会使计算效率降低。
-
Pytorch
seed = 0 torch.manual_seed(seed) # 为CPU设置随机种子 torch.cuda.manual_seed(seed) # 为当前GPU设置随机种子 torch.cuda.manual_seed_all(seed) # 为所有GPU设置随机种子
-
Python & Numpy
如果读取数据的过程采用了随机预处理(如RandomCrop、RandomHorizontalFlip等),那么对Python、Numpy的随机数生成器也需要设置种子。
import os import random import numpy as np seed = 0 random.seed(seed) np.random.seed(seed) os.environ['PYTHONHASHSEED'] = str(seed) # 为了禁止hash随机化,使得实验可复现。
-
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)
-
2. Pytorch随机种子原理
Pytorch的随机种子生成器位于/torch/include/Aten/core/Generator.h文件中,其中包含完整的生成方法说明
/**
* Note [Generator]
* ~~~~~~~~~~~~~~~~
* A Pseudo Random Number Generator (PRNG) is an engine that uses an algorithm to
* generate a seemingly random sequence of numbers, that may be later be used in creating
* a random distribution. Such an engine almost always maintains a state and requires a
* seed to start off the creation of random numbers. Often times, users have
* found it beneficial to be able to explicitly create, retain, and destroy
* PRNG states and also be able to have control over the seed value.
*
* A Generator in ATen gives users the ability to read, write and modify a PRNG engine.
* For instance, it does so by letting users seed a PRNG engine, fork the state of the
* engine, etc.
*
* By default, there is one generator per device, and a device's generator is
* lazily created. A user can use the torch.Generator() api to create their own generator.
*/
Pytorch采用线性同余方法生成随机种子,线性同余方法(LCG)是一种产生伪随机数的方法,下面将具体介绍该方法:
- 线性同余法最重要的是定义了三个整数,乘数 A、增量 B和模数 M,其中A, B, M是产生器设定的常数。 LCG的周期最大为 M,但大部分情况都会少于M。要令LCG达到最大周期,应符合以下条件:
- 这个算法的缺点是,在参数确定后,伪随机序列只与相关,容易被破解。有一种改进的办法就是每隔N个数就以时钟值对m取模作为新的种子来产生新的序列。还有一种方法是直接将随机数加上时钟值再对m取模。
版权声明:
作者:zhangchen
链接:https://www.techfm.club/p/47027.html
来源:TechFM
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论