在python 3.7,numpy 1.17.3:上测试
使用固定种子和多线程时,使用numpy生成随机数似乎无法提供一致的结果。这个问题不是由scipy引起的。以下片段显示了问题:
import numpy as np
from scipy.stats import nbinom
from concurrent.futures import ThreadPoolExecutor, as_completed
def load_data_np():
np.random.seed(0)
return np.random.negative_binomial(5, 0.3, size=2)
def load_data_scipy():
return nbinom.rvs(5, 0.3, size=2, random_state=0)
因此,这两种方法应该总是产生相同的数字。但是当在线程循环中生成数据时。。。
with ThreadPoolExecutor() as executor:
futures = list(
(executor.submit(load_data_np)
for i in range(1000))
)
print(np.diff([future.result() for future in as_completed(futures)]))
on可以在numpy的输出中找到这样的值:
...
[ 4]
[ -3]
[-15]
[ -3]
[ 5]
[ -6]
[ 0]
[ 6]
[ 1]
[-13]
[ -7]
[ 3]
[ 6]
[ -2]
[ -1]
[-11]
[ 3]
...
这一定意味着,在2个样本(大小=2(的后续计算之间,随机种子必须由另一个线程重置,这会使其他线程的rng计数丢失。只是将其与scipy进行比较:
with ThreadPoolExecutor(max_workers=cpu_count()) as executor:
futures = list(
(executor.submit(load_data_scipy)
for i in range(1000))
)
print(np.diff([future.result() for future in as_completed(futures)]))
每次迭代都产生相同的值
...
[-11]
[-11]
[-11]
[-11]
[-11]
[-11]
[-11]
[-11]
[-11]
[-11]
[-11]
[-11]
[-11]
[-11]
[-11]
...
那么,在numpy中使用固定种子的线程安全rng的正确方法是什么呢?在谷歌上搜索这个问题让我回到了np.random.seed.
干杯,Michael
我修改了您的load_data_np
方法,使其不使用np.random.seed
。
正如我在其他一些SO线程中发现的那样,已知seed
不是线程安全的,建议使用您自己的RandomState
实例。
def load_data_np():
rs = np.random.RandomState(0)
return rs.negative_binomial(5, 0.3, size=2)
现在的输出看起来和预期的一样
...
[-11]
[-11]
[-11]
[-11]
[-11]
...
这应该会有所帮助。