【问题标题】:Performance difference between numpy.random and random.random in PythonPython 中 numpy.random 和 random.random 的性能差异
【发布时间】:2019-12-04 20:15:08
【问题描述】:

我想看看我的神经网络中哪个随机数生成器包更快。

我目前正在从 github 更改代码,其中 numpy.random 和 random 包都用于生成随机整数、随机选择、随机样本等。

我更改此代码的原因是出于研究目的,我想设置一个全局种子,以便能够比较不同超参数设置的准确性性能。问题是,此时我必须为 random 包和 numpy 包设置 2 个全局种子。理想情况下,我只想设置一个种子,因为来自两个随机数生成器序列的绘图可能会更快地相互关联。

但是,我不知道哪个包的性能更好(就速度而言):numpy 或 random。所以我想为这两个包找到与完全相同的 Mersenne Twister 序列相对应的种子。这样,两个模型的图纸是相同的,因此每个梯度下降步骤中的迭代次数也相同,导致速度差异仅由我使用的包引起。

我找不到任何关于种子对的任何文档,这些种子对最终以相同的随机数序列用于两个包,而且尝试各种组合似乎有点麻烦。

我尝试了以下方法:

np.random.seed(1)
numpy_1=np.random.randint(0,101)
numpy_2=np.random.randint(0,101)
numpy_3=np.random.randint(0,101)
numpy_4=np.random.randint(0,101)
for i in range(20000000):
    random.seed(i)
    random_1=random.randint(0,101)
    if random_1==numpy_1:
        random_2=random.randint(0,101)
        if random_2==numpy_2:
            random_3=random.randint(0,101)
            if random_3==numpy_3:
                random_4=random.randint(0,101)
                if random_4==numpy_4:
                    break
print(np.random.randint(0,101))
print(random.randint(0,101))

但正如预期的那样,这并没有真正奏效。

【问题讨论】:

  • np.sin 在处理一个值时比math.sin 慢,但在处理大型数组时更快。这可能同样适用于randomnp.random 对于一个值可能会更慢,但如果要求提供数千个值则更快。

标签: python performance numpy random random-seed


【解决方案1】:

numpy.random 和 python random 以不同的方式工作,但正如您所说,它们使用相同的算法。

就种子而言:您可以使用来自numpy.randomset_stateget_state 函数(在python 中random 称为getstategetstatesetstate)并传递状态从一个到另一个。结构略有不同(在 python 中,pos 整数附加到状态元组中的最后一个元素)。请参阅 numpy.random.get_state()random.getstate() 的文档:

import random
import numpy as np
random.seed(10)
s1 = list(np.random.get_state())
s2 = list(random.getstate())

s1[1] = np.array(s2[1][:-1]).astype('int32')
s1[2] = s2[1][-1]

np.random.set_state(tuple(s1))

print(np.random.random())
print(random.random())
>> 0.5714025946899135
0.5714025946899135

在效率方面:这取决于你想做什么,但 numpy 通常更好,因为你可以创建元素数组而不需要循环:

%timeit np.random.random(10000)
142 µs ± 391 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit [random.random() for i in range(10000)]
1.48 ms ± 2.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

在“随机性”方面,numpy 是(根据他们的docs),也更好:

注意:Python stdlib 模块“random”还包含一个 Mersenne Twister 伪随机数生成器,其中包含许多方法 与RandomState 中提供的类似。 RandomState, 除了支持 NumPy 之外,它还有一个优点是它提供了很多 更多的概率分布可供选择。

【讨论】:

  • 缺少称为矢量化的显式循环通常会显着提高性能。
  • 就“随机性”而言,numpy 并不好。你写的是它有更多的概率分布。这是另一回事,它更丰富(而不是更随机)。
【解决方案2】:

考虑以下肮脏的黑客行为:

import random
import numpy as np

random.seed(42)
np.random.seed(42)

print(random.random(), np.random.random())

# copy numpy random module state to python random module
a = random.getstate()
b = np.random.get_state()
a2 = (a[0], tuple(int(val) for val in list(b[1]) + [a[1][-1]]), *a[2:])
random.setstate(a2)

print(random.random(), np.random.random())

输出:

0.6394267984578837 0.3745401188473625  # different
0.9507143064099162 0.9507143064099162  # same

不确定这种方式在两种实现的所有可能性中是否真的一致。

【讨论】:

  • 你介意扩展一下这个黑客吗?谢谢你。这些元组是什么等。
  • @YaroslavNikitenko 相同的伪随机生成器在 python 标准库和 numpy 中的实现略有不同。所以这些元组代表相同状态的不同格式。我称其为“hack”,因为不确定这种方式是否始终正确和一致。
【解决方案3】:

这个post的重复

答案取决于需求:
- 密码学/安全:秘密
- 科学研究:numpy
- 常用:随机

【讨论】:

  • 我之前读过那篇文章,我不会说这是那篇文章的重复。我想在我的整个代码中比较两个包的整体性能。比较两个包中的每个函数的性能需要做很多工作,即使我这样做了,我也应该计算每个 random/numpy.random 函数被调用的次数。如果我能把整个程序运行两次就好了;一次使用 numpy.random,一次使用 random 包,使用相同的随机数序列,所以我真的知道我的程序的性能差异是什么。
  • "我更改此代码的原因是出于研究目的" => "numpy.random 库包含一些在科学研究中常用的额外概率分布" 您的“测试”算法也有评估平均结果(处理器不会以相同的方式安排两个程序,可能会同时运行一些消耗性的东西等......)
  • 我明白你在说什么。我尝试通过在仅由该程序使用的服务器上串行运行这两个程序来考虑处理器使用情况。当然总会有小的偏差,我尽量控制。但我认为在这种情况下,随机数的不同序列将是一个更大的问题。当然,我也可以在没有任何种子的情况下多次运行这两个程序并平均性能速度,但我最终可能会以这种方式进行更多的运行。而且由于一次运行至少需要一小时,我希望有一个更智能的解决方案。
猜你喜欢
  • 2011-10-25
  • 2018-02-22
  • 2020-09-04
  • 1970-01-01
  • 1970-01-01
  • 2015-06-08
  • 1970-01-01
相关资源
最近更新 更多