Numpy 随机数生成器种子在并行程序中的应用

Numpy 随机数生成器种子在并行程序中的应用

在许多科学计算中,随机性是一项不可或缺的要素。在开发并行程序时,使用随机数生成器是必要的,因为它们可以使程序的行为不确定,从而使执行时间,内存和CPU使用等不确定性变得更容易。本文将介绍如何在numpy中种子随机数生成器,以确保在并行程序中获得可重复的结果。

阅读更多:Numpy 教程

numpy的随机数生成器

numpy中的随机数模块有很多函数可以用来生成从均匀分布和正态分布中抽取的随机数。在使用numpy随机生成器时,您需要先选择自己喜欢的生成器的种子,以便该种子可以生成与随机数生成器相同的随机数序列。所以在numpy中,使用种子来确定随机数生成器的状态是通用的,并且始终在每个生成器上产生相同的结果。

例如,对于均匀分布,在范围[0,1)内生成随机浮点数的函数是 numpy.random.rand()。使用指定的大小生成多个值很容易,如下所示:

numpy.random.seed(0)
print(numpy.random.rand(5))
# [0.5488135  0.71518937 0.60276338 0.54488318 0.4236548]

当每次调用此特定随机生成器时,它都将生成与上面相同的序列。函数 numpy.random.seed(0) 是将种子设置为零的方法,但是您可以使用您自己的整数,字符串或数字序列等任何东西作为种子。

但是,如果我们想要在并行程序中使用numpy生成器,如何设置种子是一个问题,下面我们将详细介绍。

并行numpy程序的问题

在许多并行计算中,您需要在每个子进程中使用相同的随机数种子来确保子进程生成相同的随机数序列。但是,有几个 numpy 随机数生成函数 (例如 rand, randn) 是不能并行的,因为它们使用相同的全局状态来生成前一个值与下一个值。这意味着如果多个子进程调用 numpy 中的随机数生成器而未指定不同的种子,则它们将不断共享相同的状态,这样很容易导致结果不确定。

为了解决这个问题,numpy 将确保在并行计算中使用了一种称为“随机状态”的机制,该机制使您可以生成不重叠的随机数序列。这样,在并行计算中使用 numpy 随机数生成器时,您可以确保多个子进程之间没有发生任何干扰,从而使随机数的生成更加准确和可重复。

随机状态的种子与同步

先让我们来看看如何在单进程和多进程模式下种子numpy随机生成器的随机状态。

单进程种子

单进程模式下非常简单,我们可以使用 numpy.random.seed() 方法指定随机状态的种子。例如:

import numpy

numpy.random.seed(0)

a = numpy.random.rand(5)
print(a)
# [ 0.5488  0.7152  0.6028  0.5449  0.4237]

这就使我们的numpy随机状态具有了固定的随机数生成器的种子,而子序列随机数将从这个初始状态开始。

多进程种子

现在,让我们来看看如何在多进程模式中为numpy随机状态种子。在多进程模式中,我们需要采取其他措施来确保每个子进程使用不同的随机状态。这可以通过两种方式完成:1)使用 numpy.random.SeedSequence() 生成随机状态的基本种子,然后使用该基本种子生成子序列随机状态;2)将 numpy 随机状态序列存储在共享内存中,以便子进程可以访问该序列。下面我们将详细介绍这两种方法。

使用 SeedSequence

numpy.random.SeedSequence() 是一种生成随机状态基本种子的方法,可以在多个子进程中使用,以确保每个子进程生成不同的随机序列。要使用这个方法,我们需要指定一个随机种子作为输入。

下面是一个使用 numpy.random.SeedSequence 的例子:

import numpy as np
from multiprocessing import Pool

# base seed generator
ss = np.random.SeedSequence(1234)

def random_process(x):
    # generate a child seed sequence based on the parent one
    child_ss = ss.spawn(x)
    rs = np.random.RandomState(child_ss)
    return rs.rand()

if __name__ == '__main__':
    pool = Pool(4)
    result = pool.map(random_process, [0, 1, 2, 3])
    print(result)

在此代码中,numpy.random.SeedSequence() 生成特定的随机序列种子,然后使用这个种子为生成器生成状态,返回随机数 rand()

每个子进程使用唯一的种子生成了其独有的随机序列。这种方法可以使用在单进程和多进程模式下,在多进程模式中可以确保每个 numpy.random.RandomState() 实例产生不同的随机序列。

保存随机状态序列

另一种在多进程程序中使用 numpy 随机序列的方法是将其存储在共享内存中,以便每个子进程都可以访问和使用该随机序列。这种方式可以在多进程中产生与单一进程相同的随机序列。

一个基本的示例代码如下:

import numpy as np
from multiprocessing import Process, Array

def producer(n, a, seed=0):
    rng = np.random.RandomState(seed)
    for i in range(n):
        a[i] = rng.rand()

def consumer(n, a):
    for i in range(n):
        print(a[i])

if __name__ == '__main__':
    N = 5
    arr = Array('d', N)

    # generate the sequence in producer process
    p = Process(target=producer, args=(N, arr, 0))
    p.start()
    p.join()

    # use the sequence in consumer process
    p = Process(target=consumer, args=(N, arr))
    p.start()
    p.join()

在这个例子中,我们定义并启动了一个进程 producer 用来产生随机序列,然后将序列存储在一个共享的 Array 中。

consumer 进程接收到这个共享的序列,并遍历打印。注意,在 producer 进程中使用了一个带有种子的随机数生成器,以确保每个随机序列都是固定的。

总结

当您在并行程序中使用 numpy 随机数生成器时,您需要使用不同的生成器状态,并使用适当的方法共享状态。我们在本文中介绍了两个不同的方法,一种是使用 numpy.random.SeedSequence() 生成随机状态基本种子,然后使用该基本种子生成子序列随机状态;另一种是将 numpy 随机状态序列存储在共享内存中,在多进程中产生与单一进程相同的随机序列。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程