Python多进程NumPy随机化

5

numpy的ndarray在被multiprocessing调用的函数中作用是否有所不同?以下是一个例子:

使用Python的multiprocessing模块,我像这样调用一个函数:

for core in range(cores):
    #target could be f() or g()
    proc = mp.Process(target=f, args=(core))
    jobs.append(proc)
for job in jobs:
    job.start()
for job in jobs:
    job.join()

def f(core):
    x = 0
    x += random.randint(0,10)
    print x

def g(core):
    #Assume an array with 4 columns and n rows
    local = np.copy(globalshared_array[:,core])
    shuffled = np.random.permutation(local)

调用 f(core) 函数时,变量 x 是进程局部的,即它打印的随机整数与预期不同。这些整数不超过 10,表明在每个进程中 x=0。这是否正确?

调用 g(core) 函数并对数组的副本进行置换操作会返回 4 个完全相同的“洗牌”数组。这似乎表明工作副本不是子进程局部的。这是否正确?如果是,除了使用共享内存空间外,当需要从共享内存空间填充 ndarray 时,是否有可能将其设为子进程局部?

编辑:

将一个随机整数添加到 g(core) 函数中似乎产生了预期的效果。数组显示了不同的值。在 permutation 中发生了某些随机排序列(每个子进程都是局部的)的情况...有什么想法吗?

def g(core):
    #Assume an array with 4 columns and n rows
    local = np.copy(globalshared_array[:,core])
    local += random.randint(0,10)

编辑 II:np.random.shuffle 也表现出相同的行为。数组的内容正在洗牌,但在每个核心上都洗牌到相同的值。


1
我认为可能只是因为随机数生成器和线程之间的结合会有潜在的问题(即,你得到幸运一次,下一次却不行)。你可能需要确保每个线程单独初始化一个随机状态或使用np.random.RandomState这样的函数。 - seberg
@seberg 我也尝试使用 np.random.random_integer,但是返回的数组在所有进程中都是相同的。你是否引用了 np.random.mtrand.RandomState?因此,为每个子进程实例化一个随机类,因为它们可能会实例化一个类或互相覆盖。 - Jzl5325
不确定它们何时被实例化,但我不确定它们是否可能恰好被实例化为相同的状态(它们可能使用系统时间),或者只是在分叉时复制相同的状态,并且应该再次实例化。 - seberg
无论如何,我可能想错了,但是也许只需确保将其初始化为进程 ID 或其他对于每个进程都是唯一的东西。 - seberg
@Jzl5325,它们不必同时生成才能具有相同的种子。这取决于时钟分辨率。在多核CPU上,也可能同时生成进程。 - Bakuriu
显示剩余3条评论
2个回答

5
调用g(core)并对数组的副本进行排列,将返回4个完全相同的“打乱”数组。这似乎表明工作副本不是子进程本地的。
实际上,这很可能表明在每个子进程中随机数生成器被初始化为相同的值,从而产生相同的序列。你需要为每个子进程的生成器设置种子(可以将子进程的进程ID加入其中)。

这个问题漫游到了 OP 的评论中。使用 pid 或 randomint(0,1000) 进行种子初始化并没有改变随机解决方案。 - Jzl5325
3
当状态相同时,使用随机整数进行种子生成是毫无意义的。请尝试在函数中使用pid进行种子生成,例如np.random.seed(pid) - seberg
我想在子进程中共享父进程的numpy随机状态。我尝试使用Manager,但仍然没有成功。您能否请看一下我的问题这里,看看是否可以提供解决方案?如果每次生成随机数时都执行np.random.seed(None),我仍然可以获得不同的随机数,但这不允许我使用父进程的随机状态,这不是我想要的。非常感谢您的帮助。 - Amir

4
为了生成一个随机数组,这篇文章提供了很有用的帮助。下面的g(core)函数成功地为每个核心生成了一个随机排列。
def g(core):
    pid = mp.current_process()._identity[0]
    randst = np.random.mtrand.RandomState(pid)
    randarray = randst.randint(0,100, size=(1,100)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接