我在 Jupyter Notebook 中使用 Keras。
我知道对于相同的结果,随机数应该每次都从同一个种子产生。
因此,在我的所有代码中,我首先random.seed
在一个单元格中设置为 1234。
np.random.seed(1234)
然后其他单元格是我的模型的代码以及拟合和评估代码。但是每次我运行模型单元时,损失值都是不同的!
为什么会这样?我该如何解决?
我在 Jupyter Notebook 中使用 Keras。
我知道对于相同的结果,随机数应该每次都从同一个种子产生。
因此,在我的所有代码中,我首先random.seed
在一个单元格中设置为 1234。
np.random.seed(1234)
然后其他单元格是我的模型的代码以及拟合和评估代码。但是每次我运行模型单元时,损失值都是不同的!
为什么会这样?我该如何解决?
正如您所见,仅设置 numpy 随机种子是不够的 - Keras 文档还指出,有必要设置:
所有这些的交互通常会导致不同的损失值,这主要是由于随机权重初始化的变化,这些数据最终会出现在你的训练/验证/测试拆分中,以及数据传递给模型进行训练的顺序。
正如其他人所提到的,少量的差异是可以预料的,当然不值得限制你的表现(通过将自己限制在一个线程中);设置种子和 rng 应该足以让人们满意,您的结果是可重复的。
如果在采取这些步骤后您的结果仍然存在不可接受的差异,那么这可能表明您的模型很脆弱并且可能无法很好地推广到新数据,因此您需要解决这个问题。
最后的想法 - 当你说每次运行模型单元时值都不同时,你是在删除/覆盖你已经训练过的模型吗?如果您在现有模型/权重值上运行模型单元,那么这与训练更多时期相同,并且通常会对您的结果产生很大影响。
围绕这个主题有几件事需要了解:
使用 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,他在其中展示了如何保持浮点数求和的完全精度。它涉及跟踪小计,可用于确保最终总和不会导致任何精度损失。