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

Neu*_*onQ 8 python machine-learning neural-network lstm keras

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

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

代码大致是这样的:

# 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 :(
Run Code Online (Sandbox Code Playgroud)

我知道模型具有初始随机权重,因此我将它们保存并重新加载。我也很偏执,假设有一些我可能不知道的“隐藏”参数,所以我将模型序列化为 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)
Run Code Online (Sandbox Code Playgroud)

...但他们仍然没有解决随机性。

而且我知道目标是让我的模型表现出非随机性,尽管NN 具有固有的随机性。但是我需要为了实验目的暂时修复这个问题(我什至可以在一台机器上重现它!)。

Dji*_*011 7

机器学习算法通常是非确定性的。这意味着每次运行它们时,结果都应该有所不同。这与权重的随机初始化有关。如果您想让结果可重复,您必须消除表格中的随机性。一个简单的方法是使用随机种子

import numpy as np
import tensorflow as tf

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

# rest of your code
Run Code Online (Sandbox Code Playgroud)

如果您想要随机因子但输出中的方差不那么大,我建议您降低学习率或更改优化器(我建议使用学习率相对较低的 SGD 优化器)。梯度下降优化清凉的概述,请点击这里


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

tf.random.set_seed(1234)
print(tf.random.uniform([1]).numpy())
print(tf.random.uniform([1]).numpy())
Run Code Online (Sandbox Code Playgroud)

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

可以在此处找到有关 TensorFlow 中随机种子如何工作的详细说明。


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

  • 如果 keras 使用 theano 后端,这将起作用。对于 tensorflow 后端,您还需要使用 set_random_seed 指定种子。请参阅此处:/sf/ask/3217907871/#45970553 (3认同)

Mil*_*ore 5

此代码适用于使用tensorflow后端的keras

这是因为权重是使用随机数初始化的,因此每次都会得到不同的结果。这是预期的行为。为了获得可重现的结果,您需要将随机种子设置为。下面的示例设置了操作级别和图形级别种子以获取更多信息,请参见此处

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 ...
Run Code Online (Sandbox Code Playgroud)