首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在并行程序中播种随机数生成器

在并行程序中播种随机数生成器
EN

Stack Overflow用户
提问于 2015-04-25 01:59:05
回答 3查看 10.9K关注 0票数 24

我正在研究Python的多处理模块。我有两个案例:

例如。1

代码语言:javascript
复制
def Foo(nbr_iter):
    for step in xrange(int(nbr_iter)) :
        print random.uniform(0,1)
...

from multiprocessing import Pool

if __name__ == "__main__":
    ...
    pool = Pool(processes=nmr_parallel_block)
    pool.map(Foo, nbr_trial_per_process)

示例2. (使用numpy)

代码语言:javascript
复制
 def Foo_np(nbr_iter):
     np.random.seed()
     print np.random.uniform(0,1,nbr_iter)

在这两种情况下,随机数生成器都是在其派生进程中播种的。

为什么我必须在numpy示例中显式地进行种子设定,而不是在Python示例中呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-04-25 03:33:12

如果没有显式提供种子,numpy.random将使用依赖于操作系统的随机性来源来为自己设定种子。通常,它会在基于Unix的系统上使用/dev/urandom (或一些与Windows类似的系统),但如果由于某种原因而不可用,那么它将从挂钟中自动生成种子。由于自播种发生在新子进程派生时,如果多个子进程同时派生,则它们可能继承相同的种子,从而导致由不同的子进程产生相同的随机变量。

这通常与您正在运行的并发线程的数量相关。例如:

代码语言:javascript
复制
import numpy as np
import random
from multiprocessing import Pool

def Foo_np(seed=None):
    # np.random.seed(seed)
    return np.random.uniform(0, 1, 5)

pool = Pool(processes=8)
print np.array(pool.map(Foo_np, xrange(20)))

# [[ 0.14463001  0.80273208  0.5559258   0.55629762  0.78814652] <-
#  [ 0.14463001  0.80273208  0.5559258   0.55629762  0.78814652] <-
#  [ 0.14463001  0.80273208  0.5559258   0.55629762  0.78814652] <-
#  [ 0.14463001  0.80273208  0.5559258   0.55629762  0.78814652] <-
#  [ 0.14463001  0.80273208  0.5559258   0.55629762  0.78814652] <-
#  [ 0.14463001  0.80273208  0.5559258   0.55629762  0.78814652] <-
#  [ 0.14463001  0.80273208  0.5559258   0.55629762  0.78814652] <-
#  [ 0.64672339  0.99851749  0.8873984   0.42734339  0.67158796]
#  [ 0.64672339  0.99851749  0.8873984   0.42734339  0.67158796]
#  [ 0.64672339  0.99851749  0.8873984   0.42734339  0.67158796]
#  [ 0.64672339  0.99851749  0.8873984   0.42734339  0.67158796]
#  [ 0.64672339  0.99851749  0.8873984   0.42734339  0.67158796]
#  [ 0.11283279  0.28180632  0.28365286  0.51190168  0.62864241]
#  [ 0.11283279  0.28180632  0.28365286  0.51190168  0.62864241]
#  [ 0.28917586  0.40997875  0.06308188  0.71512199  0.47386047]
#  [ 0.11283279  0.28180632  0.28365286  0.51190168  0.62864241]
#  [ 0.64672339  0.99851749  0.8873984   0.42734339  0.67158796]
#  [ 0.11283279  0.28180632  0.28365286  0.51190168  0.62864241]
#  [ 0.14463001  0.80273208  0.5559258   0.55629762  0.78814652] <-
#  [ 0.11283279  0.28180632  0.28365286  0.51190168  0.62864241]]

您可以看到多达8个线程的组同时使用相同的种子分叉,给出了相同的随机序列(我已经用箭头标记了第一组)。

在一个子进程中调用np.random.seed()会强制线程本地RNG实例从/dev/urandom或时钟中重新设定自己的种子,这(可能)会阻止您看到来自多个子进程的相同输出。最佳实践是显式地将不同的种子(或numpy.random.RandomState实例)传递给每个子进程,例如:

代码语言:javascript
复制
def Foo_np(seed=None):
    local_state = np.random.RandomState(seed)
    print local_state.uniform(0, 1, 5)

pool.map(Foo_np, range(20))

我不完全确定randomnumpy.random在这方面的不同之处是什么(也许与numpy.random相比,它在选择随机来源进行自我播种时的规则略有不同?)。为了安全起见,我仍然建议显式地将种子或random.Random实例传递给每个子进程。您还可以使用random.Random.jumpahead()方法,该方法设计用于在多线程程序中打乱Random实例的状态。

票数 30
EN

Stack Overflow用户

发布于 2019-07-28 15:38:04

刚刚引入了引用"..three策略的实现,可用于跨多个进程生成可重复的伪随机数(本地或分布式)..“

第一种策略是使用SeedSequence对象。有许多父/子选项,但对于我们的例子,如果您希望生成相同的随机数,但每次运行时不同,则使用

(python3,打印来自4个进程的3个随机数)

代码语言:javascript
复制
from numpy.random import SeedSequence, default_rng
from multiprocessing import Pool

def rng_mp(rng):
    return [ rng.random() for i in range(3) ]

seed_sequence = SeedSequence()
n_proc = 4
pool = Pool(processes=n_proc)
pool.map(rng_mp, [ default_rng(seed_sequence) for i in range(n_proc) ])

# 2 different runs
[[0.2825724770857644, 0.6465318335272593, 0.4620869345284885],
 [0.2825724770857644, 0.6465318335272593, 0.4620869345284885],
 [0.2825724770857644, 0.6465318335272593, 0.4620869345284885],
 [0.2825724770857644, 0.6465318335272593, 0.4620869345284885]]

[[0.04503760429109904, 0.2137916986051025, 0.8947678672387492],
 [0.04503760429109904, 0.2137916986051025, 0.8947678672387492],
 [0.04503760429109904, 0.2137916986051025, 0.8947678672387492],
 [0.04503760429109904, 0.2137916986051025, 0.8947678672387492]]

如果您希望在重现时获得相同的结果,只需使用相同的种子(17)重新播种即可:

代码语言:javascript
复制
import numpy as np
from multiprocessing import Pool

def rng_mp(seed):
    np.random.seed(seed)
    return [ np.random.rand() for i in range(3) ]

n_proc = 4
pool = Pool(processes=n_proc)
pool.map(rng_mp, [17] * n_proc)

# same results each run:
[[0.2946650026871097, 0.5305867556052941, 0.19152078694749486],
 [0.2946650026871097, 0.5305867556052941, 0.19152078694749486],
 [0.2946650026871097, 0.5305867556052941, 0.19152078694749486],
 [0.2946650026871097, 0.5305867556052941, 0.19152078694749486]]
票数 3
EN

Stack Overflow用户

发布于 2019-02-04 03:25:10

这里有一个很好的blog post,它将解释numpy.random的工作方式。

如果您使用np.random.rand(),它将采用您导入np.random模块时创建的种子。因此,您需要在每个线程上手动创建一个新种子(例如,参见博客文章中的示例)。

python random模块没有这个问题,它会自动为每个线程生成不同的种子。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29854398

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档