为什么我在Keras中设置了随机种子但无法获得可重复的结果?

19

我正在使用Keras在Mac OSX上用虚拟数据训练MobileNet结构。我设置了nump.randomtensorflow.set_random_seed,但由于某些原因,我无法获得可重复的结果:每次重新运行代码时,我都会得到不同的结果。为什么?这不是因为GPU,因为我在一台带有Radeon图形卡的MacBook Pro 2017上运行,因此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次epochs中保存最佳模型(最佳验证准确率)并使用具有描述性的文件名,因此通过比较不同运行之间的文件名可以判断结果的变异性。

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
2个回答

39

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

简而言之,为了确保您的Python脚本在一台计算机/笔记本电脑的CPU上得到可重复的结果,您需要执行以下操作:

  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,因为我们在上面的源代码中全局设置了它们的伪随机生成器的固定值。


2

5
这应该是一条评论,而不是一个回答。 - Jason Angel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接