numpy.random.seed(0) 做啥?

Posted

技术标签:

【中文标题】numpy.random.seed(0) 做啥?【英文标题】:What does numpy.random.seed(0) do?numpy.random.seed(0) 做什么? 【发布时间】:2014-02-24 23:58:22 【问题描述】:

np.random.seed 在以下来自 Scikit-Learn 教程的代码中做了什么?我对 NumPy 的随机状态生成器的东西不是很熟悉,所以我非常感谢外行的术语解释。

np.random.seed(0)
indices = np.random.permutation(len(iris_X))

【问题讨论】:

我发现这篇文章对理解np.random.seed() 和伪随机数很有帮助:sharpsightlabs.com/blog/numpy-random-seed 这仍然是推荐的答案吗? towardsdatascience.com/… 【参考方案1】:

我希望给出一个非常简短的答案:

seed 使(下一个系列)随机数可预测。你可以想,每次调用seed后,它会预先定义序列号,numpy random 会保留它的迭代器,然后每次你得到一个随机数它就会调用get next。

例如:

np.random.seed(2)
np.random.randn(2) # array([-0.41675785, -0.05626683])
np.random.randn(1) # array([-1.24528809])

np.random.seed(2)
np.random.randn(1) # array([-0.41675785])
np.random.randn(2) # array([-0.05626683, -1.24528809])

您可以注意到,当我设置相同的种子时,无论您每次向 numpy 请求多少个随机数,它总是给出相同的数字序列,在本例中为 array([-0.41675785, -0.05626683, -1.24528809])

【讨论】:

【参考方案2】:

以上所有答案都显示了np.random.seed() 在代码中的实现。我会尽力简要解释它为什么会发生。计算机是基于预定义算法设计的机器。计算机的任何输出都是在输入上实施的算法的结果。因此,当我们要求计算机生成随机数时,请确保它们是随机的,但计算机并不是随机产生的!

因此,当我们编写 np.random.seed(any_number_here) 时,算法将输出一组特定的数字,这些数字对参数 any_number_here 是唯一的。如果我们传递正确的参数,这几乎就像可以获得一组特定的随机数。但这需要我们知道算法是如何工作的,这非常乏味。

因此,例如,如果我写 np.random.seed(10),即使我在 10 年后执行同一行,我获得的特定数字集也将保持不变,除非算法发生变化。

【讨论】:

【参考方案3】:
numpy.random.seed(0)
numpy.random.randint(10, size=5)

这会产生以下输出: array([5, 0, 3, 3, 7]) 同样,如果我们运行相同的代码,我们将得到相同的结果。

现在,如果我们将种子值 0 更改为 1 或其他值:

numpy.random.seed(1)
numpy.random.randint(10, size=5)

这会产生以下输出:array([5 8 9 5 0]),但现在的输出与上面不同。

【讨论】:

【参考方案4】:

Numpy 文档中有一个很好的解释: https://docs.scipy.org/doc/numpy-1.15.1/reference/generated/numpy.random.RandomState.html 它指的是Mersenne Twister 伪随机数生成器。关于算法的更多细节在这里:https://en.wikipedia.org/wiki/Mersenne_Twister

【讨论】:

【参考方案5】:

np.random.seed(0) 使随机数可预测

>>> numpy.random.seed(0) ; numpy.random.rand(4)
array([ 0.55,  0.72,  0.6 ,  0.54])
>>> numpy.random.seed(0) ; numpy.random.rand(4)
array([ 0.55,  0.72,  0.6 ,  0.54])

随着种子重置(每次),相同的组数字每次都会出现。

如果随机种子未重置,则每次调用都会出现不同的数字:

>>> numpy.random.rand(4)
array([ 0.42,  0.65,  0.44,  0.89])
>>> numpy.random.rand(4)
array([ 0.96,  0.38,  0.79,  0.53])

(伪)随机数的工作原理是从一个数字(种子)开始,将其乘以一个大数,添加一个偏移量,然后对该总和取模。然后将得到的数字用作生成下一个“随机”数字的种子。当你设置种子(每次)时,它每次都做同样的事情,给你同样的数字。

如果您想要看似随机的数字,请不要设置种子。但是,如果您的代码使用了要调试的随机数,那么在每次运行之前设置种子会非常有帮助,这样代码每次运行时都会执行相同的操作。

要为每次运行获取最多的随机数,请致电numpy.random.seed()。 This 将导致 numpy 将种子设置为从 /dev/urandom 或其 Windows 模拟获得的随机数,或者,如果两者都不可用,它将使用时钟。

有关使用种子生成伪随机数的更多信息,请参阅wikipedia。

【讨论】:

这个答案应该添加到numpy的文档中。谢谢。 另外,当您调用 numpy.random.seed(None) 时,它“将尝试从 /dev/urandom(或 Windows 模拟)中读取数据(如果可用)或从时钟中读取数据”。 @Jonathan 关于numpy.random.seed(None) 的精彩之处。我用该信息和文档链接更新了答案。 @L3viathan 好点!为了更完整和准确,我应该提到添加了一个偏移量。答案已更新。对于那些想了解更多细节的人,我还添加了一个链接到***关于伪随机数生成器的讨论。【参考方案6】:

假设您正在向某人展示如何用一堆“随机”数字编写代码。通过使用 numpy 种子,他们可以使用相同的种子数并获得相同的“随机”数集。

所以它不是完全随机的,因为算法会吐出数字,但它看起来像是随机生成的一堆。

【讨论】:

【参考方案7】:

我在神经网络中经常使用它。众所周知,当我们开始训练神经网络时,我们会随机初始化权重。该模型在特定数据集上的这些权重上进行训练。在经过数个时期后,您将获得训练有素的权重集。

现在假设您想再次从头开始训练,或者您想将模型传递给其他人以重现您的结果,权重将再次初始化为一个随机数,该随机数大部分与之前的不同。在与之前的相同数量的时期(保持相同的数据和其他参数)之后获得的训练权重会有所不同。问题是您的模型不再具有可重复性,即每次您从头开始训练模型时,它都会为您提供不同的权重集。这是因为模型每次都被不同的随机数初始化。

如果每次您从头开始训练时,模型都被初始化为相同的随机初始化权重集怎么办?在这种情况下,您的模型可能会变得可重现。这是通过 numpy.random.seed(0) 实现的。通过将 seed() 提到一个特定的数字,你总是挂在同一组随机数上。

【讨论】:

【参考方案8】:

设置特定种子值后生成的所有随机数在所有平台/系统中都是相同的。

【讨论】:

【参考方案9】:

如果每次调用numpy的其他随机函数时都设置np.random.seed(a_fixed_number),结果都是一样的:

>>> import numpy as np
>>> np.random.seed(0) 
>>> perm = np.random.permutation(10) 
>>> print perm 
[2 8 4 9 1 6 7 3 0 5]
>>> np.random.seed(0) 
>>> print np.random.permutation(10) 
[2 8 4 9 1 6 7 3 0 5]
>>> np.random.seed(0) 
>>> print np.random.permutation(10) 
[2 8 4 9 1 6 7 3 0 5]
>>> np.random.seed(0) 
>>> print np.random.permutation(10) 
[2 8 4 9 1 6 7 3 0 5]
>>> np.random.seed(0) 
>>> print np.random.rand(4) 
[0.5488135  0.71518937 0.60276338 0.54488318]
>>> np.random.seed(0) 
>>> print np.random.rand(4) 
[0.5488135  0.71518937 0.60276338 0.54488318]

但是,如果只是调用一次,使用各种随机函数,结果还是会有所不同:

>>> import numpy as np
>>> np.random.seed(0) 
>>> perm = np.random.permutation(10)
>>> print perm 
[2 8 4 9 1 6 7 3 0 5]
>>> np.random.seed(0) 
>>> print np.random.permutation(10)
[2 8 4 9 1 6 7 3 0 5]
>>> print np.random.permutation(10) 
[3 5 1 2 9 8 0 6 7 4]
>>> print np.random.permutation(10) 
[2 3 8 4 5 1 0 6 9 7]
>>> print np.random.rand(4) 
[0.64817187 0.36824154 0.95715516 0.14035078]
>>> print np.random.rand(4) 
[0.87008726 0.47360805 0.80091075 0.52047748]

【讨论】:

是否有一个函数可以调用一次,以便为所有后续np.random 调用设置随机种子,直到种子被更改?每次都必须调用它似乎不必要地冗长且容易忘记。 @LubedUpSlug 你可以装饰它们——至少对于我测试过的一些简单的情况,它应该可以工作。 def seed_first(fun, seed=0): | \tdef wrapped(*args, **kwargs): | \t\tnp.random.seed(seed) | \t\treturn fun(*args, **kwargs) | \treturn wrapped,然后是for m in np.random.__all__: | \tif m != 'seed': | \t\tsetattr(np.random, m, seed_first(getattr(np.random, m))) 但是,从长远来看,这可能会导致非常微妙的错误和奇怪的行为。 (将 \t 替换为四个空格,将 | 替换为换行符...) @SebastianHöffner 感谢您的评论。我的问题有点误导,因为我被这句话弄糊涂了“但是,如果你只调用一次并使用各种随机函数,结果仍然会有所不同:”在程序开始时调用一次np.random.seed()总是会产生相同种子的结果相同,因为随后对 np.random 函数的调用将确定性地更改后续调用的种子。在每次调用 np.random 函数之前调用 np.random.seed() 可能会产生不希望的结果。 这仍然是推荐的答案吗? towardsdatascience.com/…【参考方案10】:

随机种子指定计算机生成随机数序列时的起点。

例如,假设您想在 Excel 中生成一个随机数(注意:Excel 为种子设置了 9999 的限制)。如果您在此过程中在随机种子框中输入一个数字,您将能够再次使用同一组随机数。如果您在框中键入“77”,并在下次运行随机数生成器时键入“77”,Excel 将显示同一组随机数。如果你输入“99”,你会得到一组完全不同的数字。但是,如果您恢复到种子 77,那么您将获得与开始时相同的一组随机数。

例如,“取一个数字 x,加上 900 +x,然后减去 52。”为了启动该过程,您必须指定一个起始编号 x(种子)。让我们以起始数字 77 为例:

加 900 + 77 = 977 减去 52 = 925 按照相同的算法,第二个“随机”数将是:

900 + 925 = 1825 减去 52 = 1773 这个简单的例子遵循一个模式,但计算机数字生成背后的算法要复杂得多

【讨论】:

【参考方案11】:

如前所述,numpy.random.seed(0) 将随机种子设置为 0,因此您从 random 获得的伪随机数将从同一点开始。在某些情况下,这可能有利于调试。但是,经过一番阅读,如果您有线程,这似乎是错误的方法,因为它不是线程安全的。

来自differences-between-numpy-random-and-random-random-in-python:

对于numpy.random.seed(),主要的难点在于它不是 线程安全 - 也就是说,如果您有许多不同的,使用它是不安全的 执行线程,因为如果两个 不同的线程同时执行该函数。如果 你没有使用线程,如果你可以合理地期望你 将来不需要以这种方式重写您的程序, numpy.random.seed() 应该可以用于测试目的。如果有 有任何理由怀疑您将来可能需要线程,这是 从长远来看,按照建议进行操作会更安全,并在本地进行 numpy.random.Random 类的实例。据我所知, random.random.seed() 是线程安全的(或者至少,我没有找到任何 相反的证据)。

如何做的例子:

from numpy.random import RandomState
prng = RandomState()
print prng.permutation(10)
prng = RandomState()
print prng.permutation(10)
prng = RandomState(42)
print prng.permutation(10)
prng = RandomState(42)
print prng.permutation(10)

可以给:

[3 0 4 6 8 2 1 9 7 5]

[1 6 9 0 2 7 8 3 5 4]

[8 1 5 0 7 2 9 4 3 6]

[8 1 5 0 7 2 9 4 3 6]

最后,请注意,由于 xor 的工作方式,在某些情况下,初始化为 0(与并非所有位都为 0 的种子相反)可能会导致一些第一次迭代的分布不均匀,但这取决于关于算法,超出了我目前的担忧和这个问题的范围。

【讨论】:

这仍然是推荐的答案吗? towardsdatascience.com/…

以上是关于numpy.random.seed(0) 做啥?的主要内容,如果未能解决你的问题,请参考以下文章

random VS numpy.random

Numpy 函数总结 (不断更新)

使用 numpy.random.seed 在潜在狄利克雷分配中的可重复性

scipy.stats 种子?

机器学习-MNIST数据集-神经网络

无法使用 Sklearn 和 Keras Wrappers 使 pipeline.fit() 工作