python - 为什么即使我设置了随机种子,我也无法在 Keras 中获得可重现的结果?
问题描述
我正在 Mac OSX 上使用 Keras 对虚拟数据训练 MobileNet 架构。我同时设置了nump.random
和tensorflow.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 文档中找到答案:https ://keras.io/getting-started/faq/#how-can-i-obtain-reproducible-results-using-keras-during-development 。
简而言之,要绝对确定您将在一台计算机/笔记本电脑的 CPU 上使用您的 python 脚本获得可重现的结果,那么您必须执行以下操作:
- 将
PYTHONHASHSEED
环境变量设置为固定值 - 将
python
内置伪随机发生器设置为固定值 - 将
numpy
伪随机发生器设置为固定值 - 将
tensorflow
伪随机发生器设置为固定值 - 配置新的全局
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 脚本中使用的任何seed
或random_state
at或/函数numpy
,因为使用上面的源代码,我们将它们的伪随机生成器全局设置为固定值。scikit-learn
tensorflow
keras
推荐阅读
- django - Embed plotly:dash figure inside django template
- javascript - iPhone / iPad - 终止应用程序时未保存 Safari 浏览器 cookie
- node.js - 为什么我的快速路由器中间件没有定义 req.route?
- vue.js - 事件高度,如使用 vue-cal 的谷歌日历
- wpf - StackPanel 水平内容对齐在 dataTemplate 中居中
- php - 如何使用php只显示全名
- java - 来自组合字符串的正则表达式数字和点(点)
- java - Selenium DataProvider - 如何在 HashMap 中添加 Excel 工作表中的所有值
- nestjs - 有没有办法从 nest.js 中进行 jayson npm JSON-RPC 调用?
- r - 创建从 0 到表变量中的值的新列