为什么在相同的数据上运行相同的代码每次都会给出不同的结果?

数据挖掘 Python 深度学习 喀拉斯
2021-10-04 19:56:11

我在 Jupyter Notebook 中使用 Keras。

我知道对于相同的结果,随机数应该每次都从同一个种子产生。

因此,在我的所有代码中,我首先random.seed在一个单元格中设置为 1234。

np.random.seed(1234)

然后其他单元格是我的模型的代码以及拟合和评估代码。但是每次我运行模型单元时,损失值都是不同的!

为什么会这样?我该如何解决?

3个回答

正如您所见,仅设置 numpy 随机种子是不够的 - Keras 文档还指出,有必要设置:

  • python哈希种子
  • 核心python rng
  • 您后端到 keras 的随机种子
  • 并强制您的后端使用单个线程。

所有这些的交互通常会导致不同的损失值,这主要是由于随机权重初始化的变化,这些数据最终会出现在你的训练/验证/测试拆分中,以及数据传递给模型进行训练的顺序。

正如其他人所提到的,少量的差异是可以预料的,当然不值得限制你的表现(通过将自己限制在一个线程中);设置种子和 rng 应该足以让人们满意,您的结果是可重复的。

如果在采取这些步骤后您的结果仍然存在不可接受的差异,那么这可能表明您的模型很脆弱并且可能无法很好地推广到新数据,因此您需要解决这个问题。

最后的想法 - 当你说每次运行模型单元时值都不同时,你是在删除/覆盖你已经训练过的模型吗?如果您在现有模型/权重值上运行模型单元,那么这与训练更多时期相同,并且通常会对您的结果产生很大影响。

围绕这个主题有几件事需要了解:

Keras 后端

使用 Keras 可能很难获得相同的结果。这是因为它是对低级库的封装,例如Tensorflow、Theano 和 CNTK

使用这些后端,构建了一个静态图,表示网络中的所有计算步骤。然后,这允许执行自动微分(以及反向传播)。构建的图形可能分为几个块。例如,在 Tensorflow 中,您可以使用上下文管理器来区分何时以及如何更新权重(主要是使用with块。

如果您的模型确实有这些(在引擎盖下或其他地方!),您需要在每个块中设置一个随机种子。您可以在此处了解更多有关此主题的信息

灾难性取消

除了上述之外,Tensorflow(可能还有其他框架)中还有一些运算符,它们使用近似/简化来提高效率和速度。tf.reduce_sum是一个示例,它引入了可能导致准确性变化的不确定性偏差。该运算符用于将模型的错误相加,并将以我们无法知道顺序(或使用种子设置)的并行方式进行。出现问题是因为该运算符中使用的数字总和不是可交换的。

例子:

如果我将数字1 + 2 + 7或数字相加7 + 1 + 2,两者都会给我们 10 的结果——因为加法是可交换的。但是,在浮点加法中,我们添加的数字如1.2223427 + 7.0195516 + 1.9719819, (或实际上具有更多小数位的数字)将会降低准确性,因为我们无法保留所有信息......可以想象它就像舍入错误它也被称为灾难性取消在此处查看更多详细信息

在这种情况下,我们将数字相加的顺序很重要!正如我之前提到的,操作的并行化意味着我们无法知道操作的顺序,因此我们不能保证相同的算法运行得到相同的答案,同时仍然享受并行计算!

实用性

尽管这可能会让一些人头疼,因为可重复性是一个很大的问题——无论是在学术研究中还是在行业应用中——由于这种伪随机性和并行化/求和错误导致的结果变化在大局中确实可以忽略不计。

在深度神经网络中改变一个层,改变学习率或正则化都是更重要的因素,并且会在结果上产生更大的差异。它们还对您作为从业者做出的知识和决定进行编码。我建议花时间考虑这些事情,而不要担心这些小问题。


奖金

Python Guru & Core DEv 有一篇不错的帖子:Raymond Hettinger,他在其中展示了如何保持浮点数求和的完全精度它涉及跟踪小计,可用于确保最终总和不会导致任何精度损失。

np.random.seed(1234)如果在导入 Keras 之前 初始化伪随机数生成器(


编辑:上述解决方案适用于 Theano 后端,但不适用于 TensorFlow 后端。