(注意: 在每次创建模型前正确地固定随机数生成器的状态,如评论中所述,实际上解决了我的问题,因为在小数点后三位以内结果是一致的,但它们并不是完全一致的,所以可能还存在某个未被随机数种子修复的隐藏随机性来源… 可能是某些库使用了时间毫秒或其他什么…如果有人有这方面的想法,知道后会很酷,所以我会等待,不会立即关闭这个问题 🙂 )
我创建了一个Keras LSTM 模型(用于预测一些时间序列数据,具体是什么不重要),每次我尝试重新创建一个相同的模型(从json加载相同的模型配置,从文件加载相同的权重,使用相同的参数编译函数),在相同训练和测试数据上得到的结果却大相径庭。为什么会这样?
代码大致如下:
# 固定随机数import randomrandom.seed(42)# 创建模型并编译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")# 保存模型及其初始随机权重model_json = model.to_json()model.save_weights("model.h5")# 拟合和预测model.fit(x_train, y_train, epochs=3)r = model.predict(x_test)# 创建新的“相同”模型model2 = model_from_json(model_json)model2.load_weights("model.h5")model2.compile(loss="mse", optimizer="rmsprop")# 拟合和预测“相同”模型model2.fit(x_train, y_train, epochs=3)r2 = model2.predict(x_test)# ...结果不同 :(
我知道模型有初始随机权重,所以我保存它们并重新加载。我还足够偏执,假设存在一些我不知道的“隐藏”参数,所以我将模型序列化为json并重新加载,而不是手动重新创建一个相同的模型(尝试过,效果相同)。我还固定了随机数生成器。
这是我第一次使用Keras,我对神经网络也只是初学者。但这让我发疯… 到底是什么在变化?!
关于固定随机数生成器: 我使用TensorFlow后端运行Keras,并在开始时加入以下代码行,试图为实验目的固定RNG:
import randomrandom.seed(42)import numpynumpy.random.seed(42)from tensorflow import set_random_seedset_random_seed(42)
…但它们仍然无法修复随机性。
我明白目标是使我的模型在神经网络固有的随机性尽管如此表现出非随机性。但出于实验目的,我需要暂时修复这个问题(我甚至接受它只在一台机器上可重现!)。
回答:
机器学习算法通常是非确定性的。这意味着每次运行它们时,结果应该会有所不同。这与权重的随机初始化有关。如果你想使结果可重现,你必须消除随机性。一个简单的方法是使用随机种子。
import numpy as npimport tensorflow as tfnp.random.seed(1234)tf.random.set_seed(1234)# 你的其他代码
如果你想要随机性但不想让输出差异过大,我建议你降低学习率或更换优化器(我建议使用SGD优化器并设置相对较低的学习率)。关于梯度下降优化的一个很好的概述可以在这里找到!
关于TensorFlow的随机数生成器需要注意的是,除了全局种子(即tf.random.set_seed()
),它们还使用内部计数器,因此如果你运行
tf.random.set_seed(1234)print(tf.random.uniform([1]).numpy())print(tf.random.uniform([1]).numpy())
你会分别得到0.5380393
和0.3253647
。但是,如果你重新运行同一代码片段,你会再次得到这两个相同的数字。
关于TensorFlow中随机种子如何工作的详细解释可以在这里找到。
对于较新的TF版本也要注意以下内容: TensorFlow 2.2 引入了操作系统环境变量TF_DETERMINISTIC_OPS
,如果将其设置为'1'
,将确保只使用确定性的GPU操作。