Keras LSTM - 为什么 "same" 模型和相同权重的结果不同?

Keras LSTM - why different results with "same" model & same weights?

(注意: 在创建每个模型之前正确修复 RNG 状态,如评论中的评论所述 实际上 解决了我的问题,如3 位小数的结果是一致的,但它们并非 完全如此 ,因此在某处存在 隐藏的随机源 未通过播种 RNG 来修复。 . 可能有些库使用时间 milisecs 或 smth...如果有人对此有想法,知道它会很酷,所以我会等待并且还没有结束问题 :) )

我创建了一个 Keras LSTM 模型(用于预测一些时间序列数据,不重要什么),每次我尝试重新创建一个相同的模型(从[=49=加载相同的模式配置,从文件加载相同的权重,编译函数的相同参数),我在相同的火车和测试数据上得到截然不同的结果。为什么?

代码大致是这样的:

# fix random
import random
random.seed(42)

# make model & compile
model = Sequential([
    LSTM(50, input_shape=(None, 1), return_sequences=True),
    LSTM(100, return_sequences=False),
    Dense(1),
    Activation("linear")
])
model.compile(loss="mse", optimizer="rmsprop")

# save it and its initial random weights
model_json = model.to_json()
model.save_weights("model.h5")

# fit and predict
model.fit(x_train, y_train, epochs=3)
r = model.predict(x_test)

# create new "identical" model
model2 = model_from_json(model_json)
model2.load_weights("model.h5")
model2.compile(loss="mse", optimizer="rmsprop")

# fit and predict "identical" model
model2.fit(x_train, y_train, epochs=3)
r2 = model2.predict(x_test)

# ...different results :(

我知道该模型具有初始随机权重,因此我正在保存它们并重新加载它们。我也很偏执地假设有一些我可能不知道的 "hidden" 参数,所以我将模型序列化为 json 并重新加载而不是手动重新创建一个相同的参数(试过,同样的事情顺便提一句)。我还修复了随机数生成器。

这是我第一次使用 Keras,我也是神经网络的初学者。但这让我发疯......wtf可以改变吗?!


关于修复随机数生成器:我 运行 使用 TensorFlow 后端的 Keras,并且我在开始时有这些代码行来尝试修复 RNG 以用于实验目的:

import random
random.seed(42)
import numpy
numpy.random.seed(42)
from tensorflow import set_random_seed
set_random_seed(42)

...但他们仍然没有修复随机性。

而且我知道目标是让我的模型表现得非随机 尽管 NN 固有的随机性。但出于实验目的,我需要暂时修复此问题(我什至同意它只能在一台机器上重现!)。

机器学习算法通常是非确定性的。这意味着每次您 运行 他们的结果都会有所不同。这与权重的随机初始化有关。如果要使结果可重现,则必须消除 table 中的随机性。一个简单的方法是使用 随机种子 .

import numpy as np
import tensorflow as tf

np.random.seed(1234)
tf.random.set_seed(1234)

# rest of your code

如果你想要随机因子而不是输出中的高方差,我建议要么降低你的学习率,要么改变你的优化器(我建议使用学习率相对较低的 SGD 优化器)。提供了梯度下降优化的精彩概述 here


关于 TensorFlow 的随机生成器的注意事项是,除了全局种子(即 tf.random.set_seed())之外,它们还使用内部计数器,因此如果您 运行

tf.random.set_seed(1234)
print(tf.random.uniform([1]).numpy())
print(tf.random.uniform([1]).numpy())

您将分别获得 0.53803930.3253647。但是,如果您重新 运行 相同的代码段,您将再次获得相同的两个数字。

有关随机种子如何在 TensorFlow 中工作的详细说明,请参阅 here


对于较新的 TF 版本也要注意这一点: TensorFlow 2.2 附带一个 os 环境变量 TF_DETERMINISTIC_OPS 如果设置为 '1', 将确保只使用确定性 GPU 操作。

This code is for keras using tensorflow backend

这是因为权重是使用随机数初始化的,因此每次都会得到不同的结果。这是预期的行为。要获得可重现的结果,您需要将随机种子设置为。下面的示例设置 operation-level 和 graph-level 种子以获取更多信息,请查看 here

import tensorflow as tf
import random as rn

os.environ['PYTHONHASHSEED'] = '0'

# Setting the seed for numpy-generated random numbers
np.random.seed(37)

# Setting the seed for python random numbers
rn.seed(1254)

# Setting the graph-level random seed.
tf.set_random_seed(89)

from keras import backend as K

session_conf = tf.ConfigProto(
      intra_op_parallelism_threads=1,
      inter_op_parallelism_threads=1)

#Force Tensorflow to use a single thread
sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)

K.set_session(sess)

# Rest of the code follows from here on ...

我通过添加 os.environ['TF_DETERMINISTIC_OPS'] = '1'

解决了这个问题

举个例子:

import os
os.environ['TF_DETERMINISTIC_OPS'] = '1'
#rest of the code
# tf version 2.3.1