Numpy子进程生成与父进程相同的“随机”数
在本文中,我们将介绍在使用Numpy库时,子进程生成与父进程相同的“随机”数的问题。Numpy是一个Python科学计算库,广泛应用于数据分析、机器学习、深度学习等领域,其提供了众多的随机数生成器,但在使用子进程时,可能会遇到一些出乎意料的问题。
阅读更多:Numpy 教程
问题描述
在使用Numpy库时,通常我们会使用其提供的随机数生成器来生成一些随机数,例如:
import numpy as np
# 生成一个含有5个数的随机数组
arr = np.random.randn(5)
print(arr)
输出结果可能为:
[ 0.12100115 -1.00229635 -0.33488849 -0.66791272 0.12725359]
但是当我们使用多进程来加速计算时,会发现子进程生成的随机数与父进程相同。例如:
import numpy as np
from multiprocessing import Pool
np.random.seed(42)
def func(_):
arr = np.random.randn(5)
print(arr)
if __name__ == '__main__':
with Pool(2) as p:
p.map(func, [None]*2)
输出结果为:
[-0.1382643 -0.30142671 -0.17377214 0.86405215 -0.90471255]
[-0.1382643 -0.30142671 -0.17377214 0.86405215 -0.90471255]
可以看到,子进程生成的随机数与父进程相同,这显然不是我们想要的结果。
问题原因
这是因为在使用多进程时,子进程会继承父进程的状态,包括随机种子。而Numpy的随机数生成器是伪随机数生成器,其在使用随机种子生成随机数时是按照算法来生成的。因此,当子进程继承了父进程的随机种子后,它们所生成的随机数序列完全相同,即使在不同的进程中也是如此。
解决方法
为了避免子进程生成与父进程相同的“随机”数,我们需要在每个子进程中设置不同的随机种子。有多种方法可以做到这一点。
一种方法是使用随机种子来初始化随机数生成器,例如:
import numpy as np
from multiprocessing import Pool
def func(seed):
np.random.seed(seed)
arr = np.random.randn(5)
print(arr)
if __name__ == '__main__':
with Pool(2) as p:
p.map(func, [42, 43])
输出结果为:
[ 0.49671415 -0.1382643 0.64768854 1.52302986 -0.23415337]
[-0.1382643 -0.30142671 -0.17377214 0.86405215 -0.90471255]
可以看到,子进程生成的随机数不再相同,这是因为每个子进程都使用了不同的随机种子。
另一种方法是使用os模块生成不同的随机种子,例如:
import numpy as np
from multiprocessing import Pool
import os
def func(_):
np.random.seed(os.getpid())
arr = np.random.randn(5)
print(arr)
if __name__ == '__main__':
with Pool(2) as p:
p.map(func, [None]*2)
输出结果为:
[ 1.25286816 -0.88179834 0.26464236 0.75689369 -0.87279198]
[-0.46063952 -0.00801942 0.41251693 -0.62709221 -0.3330574 ]
可以看到,子进程生成的随机数不再相同,这是因为每个子进程使用了不同的随机种子。
此外,如果我们使用Numpy的RandomState对象来生成随机数,则可以避免子进程生成相同的随机数,例如:
import numpy as np
from multiprocessing import Pool
def func(_):
rs = np.random.RandomState()
arr = rs.randn(5)
print(arr)
if __name__ == '__main__':
with Pool(2) as p:
p.map(func, [None]*2)
输出结果为:
[ 0.52670239 0.5381947 -0.12285818 0.80061683 -0.34522049]
[-0.13534804 -1.0246825 0.58542976 0.60063203 -1.61568912]
可以看到,子进程生成的随机数不再相同,因为每个子进程都有自己的RandomState对象。
总结
在使用Numpy库时,如果使用多进程来加速计算,需要注意子进程可能会生成与父进程相同的“随机”数。这是因为子进程继承了父进程的随机种子,解决方法是在每个子进程中使用不同的随机种子,或使用RandomState对象来生成随机数。
极客教程