np.random.integers()如何改变RNG种子?为何前两次循环随机数组一致?
问题:Numpy随机数生成器序列保留异常分析
我正尝试严格保留随机数生成器(RNG)的序列,但以下代码显示随机种子的推进存在问题,无法理解为何前两次循环的random_arr结果完全相同。
代码示例
import numpy as np def train_test_split(X,rint): print('rint = ',rint) return X def index_split(X,rng): X_train = train_test_split(X, rng.integers(65536)) return X_train def new_rng(): rng = np.random.default_rng(seed) return rng seed = 1234 n_params = 4 extranls = [0, 1, 2] X = [0] print('np.__version__ = ',np.__version__) for ind, extran in enumerate(extranls): print('\n\n----------') print('rng #: ',ind) RNG = new_rng() X_train = index_split(X, RNG) for i in range(extran): print('Extra: rng.integers(65536) = ',RNG.integers(65536)) initial_parameters = np.zeros(n_params, dtype=np.float32) random_arr = RNG.random(n_params) print('extran = ',extran) print('random_arr is ',random_arr)
输出结果
np.__version__ = 1.26.4 ---------- rng #: 0 rint = 64182 extran = 0 random_arr is [0.38019574 0.92324623 0.26169242 0.31909706] ---------- rng #: 1 rint = 64182 Extra: rng.integers(65536) = 64008 extran = 1 random_arr is [0.38019574 0.92324623 0.26169242 0.31909706] ---------- rng #: 2 rint = 64182 Extra: rng.integers(65536) = 64008 Extra: rng.integers(65536) = 64745 extran = 2 random_arr is [0.92324623 0.26169242 0.31909706 0.11809123]
问题原因
问题出在Numpy默认RNG(基于PCG64算法)的位消耗机制:
rng.integers(65536)生成16位整数时,仅从当前64位随机数块中截取16位,剩余48位会被缓存。rng.random()生成浮点数时,只会使用完整的64位块,不会利用缓存的剩余位,而是直接生成新的64位块。- 前两次循环中,调用
integers后缓存的剩余位都不足以凑成完整64位块,因此random()均从同一个新块起始位置生成数据,导致结果完全相同。 - 第三次循环中,累计调用
integers的次数触发了生成器状态的跨块推进,random()才开始读取后续块的数据。
解决方法
要严格控制RNG序列推进,需确保每次随机数调用消耗相同单位的生成器状态,推荐以下方式:
方法:统一使用64位操作生成整数
将rng.integers(65536)替换为消耗完整64位块的生成方式,确保每次调用都推进一个块:
修改后的完整代码
import numpy as np def train_test_split(X,rint): print('rint = ',rint) return X def index_split(X,rng): rint = rng.integers(0, 2**64) % 65536 X_train = train_test_split(X, rint) return X_train def new_rng(): rng = np.random.default_rng(seed) return rng seed = 1234 n_params = 4 extranls = [0, 1, 2] X = [0] print('np.__version__ = ',np.__version__) for ind, extran in enumerate(extranls): print('\n\n----------') print('rng #: ',ind) RNG = new_rng() X_train = index_split(X, RNG) for i in range(extran): rint = RNG.integers(0, 2**64) % 65536 print('Extra: rng.integers(65536) = ',rint) initial_parameters = np.zeros(n_params, dtype=np.float32) random_arr = RNG.random(n_params) print('extran = ',extran) print('random_arr is ',random_arr)
修改后,random_arr会随着extran的增加连续推进,不会出现重复结果。
内容的提问来源于stack exchange,提问作者Ed Gan
相关产品推荐
相关产品推荐

