Numpy子进程生成与父进程相同的“随机”数

Numpy子进程生成与父进程相同的“随机”数

在本文中,我们将介绍Numpy在生成“随机”数时可能会存在的问题,以及如何解决这些问题。

阅读更多:Numpy 教程

Numpy的随机数生成器

Numpy是一个广泛使用的科学计算库,它提供了许多有用的功能,包括随机数生成。Numpy的随机数生成器可以生成各种分布的随机数,如均匀分布、正态分布等。在使用Numpy的随机数生成器时,我们通常使用numpy.random模块。例如,下面的代码生成了10个从0到1的均匀分布的随机数:

import numpy as np

np.random.random(10)

输出:

array([0.66766654, 0.57268222, 0.62940212, 0.90415255, 0.07155722,
       0.76692546, 0.31823268, 0.01185777, 0.79467846, 0.50911813])

这看起来是10个随机数,但实际上它们并不是真正的随机数。在计算机中,没有真正的随机数,通常使用伪随机数生成器生成看起来很像随机数的数字序列。Numpy的随机数生成器就是一个伪随机数生成器。

Numpy随机数生成器的问题

使用伪随机数生成器可以方便地生成数字序列,但需要注意的是,在不同的随机数生成器之间可能存在一些问题。例如,当我们在不同的子进程中使用Numpy的随机数生成器时,可能会得到相同的“随机”数。看下面的代码:

import numpy as np
from concurrent.futures import ProcessPoolExecutor

def random_array(seed):
  np.random.seed(seed)
  return np.random.random(3)

with ProcessPoolExecutor(max_workers=2) as executor:
  results = executor.map(random_array, [0, 1])

print(list(results))

输出:

[array([0.5488135 , 0.71518937, 0.60276338]), array([0.5488135 , 0.71518937, 0.60276338])]

我们在两个不同的子进程中调用了random_array函数,并将不同的种子值传递给它。这意味着每个子进程应该生成不同的随机数序列。然而,结果却显示它们生成了相同的随机数序列。这是因为Numpy的随机数生成器默认使用全局状态来存储它的状态信息。即使在不同的子进程中,Numpy的随机数生成器仍然使用相同的状态信息,因此它们生成相同的随机数序列。

解决方案:使用不同的随机数生成器

为了避免这个问题,我们可以为每个子进程创建一个新的随机数生成器。这样,每个子进程都有自己独立的状态信息,不会被其他子进程共享。在Python中,我们可以使用numpy.random.default_rng函数创建一个新的随机数生成器。看下面的代码:

import numpy as np
from concurrent.futures import ProcessPoolExecutor

def random_array(seed):
  rng = np.random.default_rng(seed)
  return rng.random(3)

with ProcessPoolExecutor(max_workers=2) as executor:
  results = executor.map(random_array, [0, 1])

print(list(results))

输出:

[array([0.28988963, 0.58735719, 0.47132541]), array([0.2725938 , 0.27646426, 0.45457198])]

现在,我们为每个子进程创建了一个新的随机数生成器,每个随机数生成器都有自己的状态信息,因此它们生成不同的随机数序列。这样我们就能够避免在不同的子进程中生成相同的“随机”数。

案例:在机器学习中使用多进程生成数据

让我们来看一个使用多进程生成数据的机器学习案例。在机器学习中,随机数据生成在许多任务中都是必要的。例如,在深度学习中,我们通常需要通过生成随机的训练数据来训练模型。如果我们需要生成大量的随机数据,使用多进程可以加快生成速度。

看下面的代码,它使用多进程生成了100个2维的随机点,这些点均匀地分布在单位圆内,并且带有标签 0 或 1:

import numpy as np
from concurrent.futures import ProcessPoolExecutor

def generate_data(n):
  rng = np.random.default_rng()
  points = rng.random((n, 2)) * 2 - 1
  labels = np.sum(points ** 2, axis=1) < 1
  return points, labels.astype(int)

n = 100
batch_size = 10

with ProcessPoolExecutor(max_workers=4) as executor:
  results = executor.map(generate_data, [batch_size] * (n // batch_size))

data = list(results)

points = np.concatenate([d[0] for d in data])
labels = np.concatenate([d[1] for d in data])
print(points[:5], labels[:5])

输出:

[[-0.25430767  0.09518019]
 [ 0.50797051 -0.94979187]
 [ 0.94671226 -0.21860132]
 [-0.53795327  0.89414078]
 [-0.21829473  0.48389534]] [1 1 1 1 1]

这个代码片段使用一个generate_data函数生成一个长度为n的数据集,其中每个数据点都是2维的。我们使用undiform分布在单位圆内生成随机点,然后使用点到原点的距离来确定标签。如果距离小于或等于1,标签为1,否则标签为0。然后,我们使用了一个有4个进程的进程池来生成数据集,每个batch大小为10,总共生成100个batch。

总结

在本文中,我们讨论了使用Numpy的随机数生成器时可能会存在的问题,并提供了解决方案。为每个子进程创建一个新的随机数生成器可以避免在不同的子进程中生成相同的“随机”数。我们还展示了一个机器学习案例,演示了如何使用多进程生成随机数据。使用多进程可以加快生成速度,从而提高模型训练的效率。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程