【问题标题】:Why can't I get reproducible results in Keras even though I set the random seeds?为什么即使我设置了随机种子,我也无法在 Keras 中获得可重现的结果?
【发布时间】:2018-11-12 13:02:46
【问题描述】:

我正在 Mac OSX 上使用 Keras 训练关于虚拟数据的 MobileNet 架构。我同时设置了nump.randomtensorflow.set_random_seed,但由于某些原因,我无法获得可重现的结果:每次重新运行代码时,都会得到不同的结果。为什么?这不是因为 GPU,因为我在 MacBook Pro 2017 上运行,它有一个 Radeon 显卡,因此 Tensorflow 没有利用它。代码运行与

python Keras_test.py

所以这不是状态问题(我没有使用 Jupyter 或 IPython:每次运行代码时都应该重置环境)。

编辑:我通过移动所有种子的设置导入 Keras 来更改我的代码。结果仍然不是确定性的,但是结果的方差比以前小得多。这很奇怪。

当前的模型非常小(就深度神经网络而言),而且并不重要,它不需要 GPU 即可运行,并且可以在现代笔记本电脑上训练几分钟,因此重复我的实验是在任何人的范围内抵达。我邀请您这样做:我非常有兴趣了解从一个系统到另一个系统的变化程度。

import numpy as np
# random seeds must be set before importing keras & tensorflow
my_seed = 512
np.random.seed(my_seed)
import random 
random.seed(my_seed)
import tensorflow as tf
tf.set_random_seed(my_seed)

# now we can import keras
import keras.utils
from keras.applications import MobileNet
from keras.callbacks import ModelCheckpoint
from keras.optimizers import Adam
import os

height = 224
width = 224
channels = 3
epochs = 10
num_classes = 10



# Generate dummy data
batch_size = 32  
n_train = 256
n_test = 64
x_train = np.random.random((n_train, height, width, channels))
y_train = keras.utils.to_categorical(np.random.randint(num_classes, size=(n_train, 1)), num_classes=num_classes)
x_test = np.random.random((n_test, height, width, channels))
y_test = keras.utils.to_categorical(np.random.randint(num_classes, size=(n_test, 1)), num_classes=num_classes)
# Get input shape
input_shape = x_train.shape[1:]

# Instantiate model 
model = MobileNet(weights=None,
                  input_shape=input_shape,
                  classes=num_classes)

model.compile(loss='categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])
# Viewing Model Configuration
model.summary()

# Model file name
filepath = 'model_epoch_{epoch:02d}_loss_{loss:0.2f}_val_{val_loss:.2f}.hdf5'

# Define save_best_only checkpointer
checkpointer = ModelCheckpoint(filepath=filepath,
                             monitor='val_acc',
                             verbose=1,
                             save_best_only=True)

# Let's fit!
model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=epochs,
          validation_data=(x_test, y_test),
          callbacks=[checkpointer])

与往常一样,这是我的 Python、Keras 和 Tensorflow 版本:

python -c 'import keras; import tensorflow; import sys; print(sys.version, 'keras.__version__', 'tensorflow.__version__')'
/anaconda2/lib/python2.7/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters
Using TensorFlow backend.
('2.7.15 |Anaconda, Inc.| (default, May  1 2018, 18:37:05) \n[GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)]', '2.1.6', '1.8.0')

以下是多次运行此代码获得的一些结果:如您所见,该代码使用描述性文件名保存了 10 个 epoch 中的最佳模型(最佳验证精度),因此比较不同运行的文件名可以判断可变性结果。

model_epoch_01_loss_2.39_val_3.28.hdf5
model_epoch_01_loss_2.39_val_3.54.hdf5
model_epoch_01_loss_2.40_val_3.47.hdf5
model_epoch_01_loss_2.41_val_3.08.hdf5

【问题讨论】:

  • 我认为你必须在导入 keras 之前设置随机种子。
  • 您所说的哪些结果不同?训练数据,丢失?
  • 我有两个建议给你: 1. 让你的训练数据具有确定性。它将确保问题出在 tensorflow 方面。 2. 我看到人们也设置了 python 随机模块种子。如果 Keras 在某处使用 python 随机种子,它将有助于解决问题。 `导入随机随机种子(my_seed)`
  • @nuric 我说的是损失。如果我发布两个不同的结果会有帮助吗?
  • 我认为最终这一切都是基于 numpy 随机种子。在导入其他任何东西之前设置它

标签: python tensorflow keras


【解决方案1】:

您可以在 Keras 文档中找到答案:https://keras.io/getting-started/faq/#how-can-i-obtain-reproducible-results-using-keras-during-development

简而言之,要绝对确保您将在一台计算机/笔记本电脑的 CPU 上使用您的 python 脚本获得可重现的结果,那么您必须执行以下操作:

  1. PYTHONHASHSEED环境变量设置为固定值
  2. python内置伪随机发生器设置为固定值
  3. numpy伪随机生成器设置为固定值
  4. tensorflow伪随机生成器设置为固定值
  5. 配置新的全局tensorflow 会话

按照顶部的Keras链接,我使用的源代码如下:

# Seed value
# Apparently you may use different seed values at each stage
seed_value= 0

# 1. Set `PYTHONHASHSEED` environment variable at a fixed value
import os
os.environ['PYTHONHASHSEED']=str(seed_value)

# 2. Set `python` built-in pseudo-random generator at a fixed value
import random
random.seed(seed_value)

# 3. Set `numpy` pseudo-random generator at a fixed value
import numpy as np
np.random.seed(seed_value)

# 4. Set the `tensorflow` pseudo-random generator at a fixed value
import tensorflow as tf
tf.random.set_seed(seed_value)
# for later versions: 
# tf.compat.v1.set_random_seed(seed_value)

# 5. Configure a new global `tensorflow` session
from keras import backend as K
session_conf = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)
K.set_session(sess)
# for later versions:
# session_conf = tf.compat.v1.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
# sess = tf.compat.v1.Session(graph=tf.compat.v1.get_default_graph(), config=session_conf)
# tf.compat.v1.keras.backend.set_session(sess)

不用说,您不必在您的 Python 脚本中使用的 numpyscikit-learntensorflow/keras 函数中指定任何 seedrandom_state正是因为在上面的源代码中,我们将它们的伪随机生成器全局设置为固定值。

【讨论】:

  • 此代码 sn-p 不适用于我。我在 Google Co-lab 中使用来自 TensorFlow(版本 1.14.0)的 Keras API(2.2.4-tf)进行深度学习。请提出建议。
  • @DrNishaArora,如果不了解您的应用程序及其正在发生的事情,我真的无法判断。可能是您与 Numpy、Tensorflow 一起使用了另一个包,并且您没有为其设置种子,或者您使用了上面代码不起作用的 Tensorflow/Keras 版本。不确定,但可能不是后者,因为到目前为止没有其他人这样报告过我。
  • 我尝试了你的代码[以及我发现为其他人工作的许多其他代码],用于最简单的 ANN,只有一个输入层和 6 组数据点,使其变得简单。我确保每次都重置运行时,我尝试了不同的代码。我不是 IT 背景,所以我可能会犯一些愚蠢的错误。请提出建议,因为我希望在我的其他 colab 文件(DNN、CNN 等)中具有可重复性。这是我的 colab 文件的链接:colab.research.google.com/drive/…
  • 更重要的是,我想了解它是如何工作的,而不是仅仅复制粘贴某人的代码来帮助我。请建议一些我可以从中了解的资源。老实说,我对 GPU、CPU 和 TPU 等硬件加速器了解不多。深度学习的课程不讲他们
  • @DrNishaArora,我不认为你做的事情很愚蠢,因为我的回答以及这里其他人的回答涵盖了 Tensorflow/Keras 可重复性的基本方面。首先,正如我在帖子中强调的那样,我写的是在一台计算机/笔记本电脑的 CPU 上,我强调这一点正是因为在不同的环境或 GPU 等上运行相同的东西可能需要一些额外的东西来确保重现性。因此,首先,您使用 GoogleLab 而不是您自己的个人电脑/笔记本电脑,为什么根据定义可能意味着需要不同的配置来确保可重复性。
【解决方案2】:

使结果可重现的关键点是禁用 GPU。请参阅我在another question(链接https://stackoverflow.com/a/57121117/9501391)上的回答,该回答已被接受。

【讨论】:

  • 这应该是评论而不是答案。
猜你喜欢
  • 1970-01-01
  • 2020-08-02
  • 2018-01-04
  • 2017-11-05
  • 1970-01-01
  • 1970-01-01
  • 2019-06-23
  • 1970-01-01
  • 2018-02-12
相关资源
最近更新 更多