【问题标题】:Keras Tensoflow full resetKeras TensorFlow 完全重置
【发布时间】:2021-05-01 12:22:44
【问题描述】:

我知道这个问题被很多人问过很多次,但我仍然没有任何可行的解决方案。

我有一个 Python 代码,它倾向于创建一个模型,对其进行拟合,然后进行预测。由于我有许多特征可以用来训练模型,因此我创建了一个包含我的特征的所有组合的列表,例如 2 of 10、4 of 10 等。现在我想循环调用我的代码。

The loop looks like:

for each combination in all combinations:
    model = Sequential()
    ... add some layers...
    model.compile(...)
    model.fit()
    ...
    model.predict()

而且我发现每次在同一组功能上运行它时都会得到不同的结果。当然,我已经禁用了所有的随机性,所以这不是问题。如果我只是从命令行运行我的代码(没有循环 - 即 python 在运行之间完全退出),我会得到一个完全重复的结果。

所以我的假设是 Keras 或/和 Tensorflow 不会在循环之间完全重置。

我已经尝试了很多方法,例如在我希望我的模型被丢弃之后添加以下行:

model.reset_states()
del model
gc.collect()
tf.keras.backend.set_learning_phase(1)
keras.backend.clear_session()
K.clear_session()
tf.compat.v1.reset_default_graph()
from tensorflow.python.framework import ops
ops.reset_default_graph()

没有任何效果 - 循环之间的结果不一致。正确工作的唯一方法是从批处理文件中运行我的文件,其中包含很多行允许 python 在下次运行之前退出。

任何建议如何处理?我在 Windows 上使用 TS 2.4.1 和最新的 keras。

谢谢

我正在使用此代码来防止随机性:

def reset_random_seeds():
    os.environ['PYTHONHASHSEED'] = str(1)
    tf.random.set_seed(1)
    np.random.seed(1)
    random.seed(1)

【问题讨论】:

  • Of course I've disabled all the randomness so it is not an issue. 我很确定这是的问题。考虑阅读documentation of tf.random.set_seed
  • 感谢您的快速回复。我在帖子中添加了我用来禁用随机性的代码。
  • 如果我多次运行我的代码(不在同一代码内的循环中),我会得到相同的结果。只是当我在不退出 Python 的情况下运行它时,我会得到不同的结果。

标签: loops tensorflow keras model reset


【解决方案1】:

TL;DR:您需要在创建模型的循环中重置随机生成器状态,方法是调用tf.random.set_seed

解释:

神经网络由一系列数学运算组成。神经网络中最常见的操作可以视为以下线性方程:y=W*x+b,其中:

  • x 是输入
  • y 是输出
  • W是网络节点的权重
  • b 是网络节点的偏差。

(所有这些线性方程然后被非线性分隔以避免网络崩溃)。

大多数时候,神经网络的权重 (W) 是随机初始化的。这意味着每次你运行神经网络的训练时,你都会得到稍微不同的结果。如果您的模型足够稳健,那么这些结果将在统计上相似。

现在,如果想要重现一些精确的结果,权重的随机初始化可能是个问题。为了能够重现一些精确的数字,可以为随机生成器设置一个种子,以保证在程序执行期间,生成的随机数始终来自同一系列、相同的顺序。

在终端中两次运行同一个程序

考虑以下程序,名为network_with_seed.py

import tensorflow as tf
tf.random.set_seed(0)
model = tf.keras.Sequential([tf.keras.layers.Dense(1,input_shape=(1,))])
print(model.trainable_weights)

该程序是一个简单的网络,具有一个与节点完全连接的层(也称为感知器)。该网络作为一个权重W,程序将打印。

如果我们第一次执行该程序,我们会得到:

$ python network_with_seed.py
[<tf.Variable 'dense/kernel:0' shape=(1, 1) dtype=float32, numpy=array([[-0.7206192]], dtype=float32)>, <tf.Variable 'dense/bias:0' shape=(1,) dtype=float32, numpy=array([0.], dtype=float32)>]

现在,如果我们再次执行该代码:

python network_with_seed.py
[<tf.Variable 'dense/kernel:0' shape=(1, 1) dtype=float32, numpy=array([[-0.7206192]], dtype=float32)>, <tf.Variable 'dense/bias:0' shape=(1,) dtype=float32, numpy=array([0.], dtype=float32)>] 

感谢种子,我们得到了完全相同的权重值W-0.7206192

循环创建模型

现在,假设我们想要创建该网络两次,并获得一些数字,但我们想在一个 python 脚本中完成所有事情。

考虑一下那个程序,loop_network_with_seed.py

import tensorflow as tf
tf.random.set_seed(0)
for idx in range(2):
  print(f"Model {idx+1}")
  model = tf.keras.Sequential([tf.keras.layers.Dense(1,input_shape=(1,))])
  print(model.trainable_weights)

如果我们运行它

$ python loop_network_with_seed.py
Model 1
[<tf.Variable 'dense/kernel:0' shape=(1, 1) dtype=float32, numpy=array([[-0.7206192]], dtype=float32)>, <tf.Variable 'dense/bias:0' shape=(1,) dtype=float32, numpy=array([0.], dtype=float32)>]
Model 2
[<tf.Variable 'dense_1/kernel:0' shape=(1, 1) dtype=float32, numpy=array([[0.19195998]], dtype=float32)>, <tf.Variable 'dense_1/bias:0' shape=(1,) dtype=float32, numpy=array([0.], dtype=float32)>]

如果我们只查看随机初始化的内核W,我们会看到,对于同一个模型,不同的值:-0.7206192, 0.19195998,与我们通过调用脚本network_with_seed.py。如果我们训练这两个网络,我们将不会得到完全相同的结果,因为它们的初始权重 W 是不同的。

请注意,如果您再次运行该程序,您将得到完全相同的结果,因为模型 1 的权重将再次设置为 -0.7206192,而模型 2 的权重 W 将是设置为 0.19195998,感谢种子。种子使每次运行之间的随机性可重现。

这是因为随机数生成器的内部状态。更多信息可以阅读documentation of tf.random.set_seed

重置随机发生器状态

如果您想要同一组参数的可重现结果,您需要在创建每个模型之前重置随机状态。通过设置种子,我们确保相同的随机值将用于我们的权重W

考虑最终方案network_with_seed_in_loop.py

import tensorflow as tf

for _ in range(2):
  print(f"Model {idx+1}")
  tf.random.set_seed(0)
  model = tf.keras.Sequential([tf.keras.layers.Dense(1,input_shape=(1,))])
  print(model.trainable_weights)

输出:

$ python network_with_seed_in_loop.py`
Model 1
[<tf.Variable 'dense/kernel:0' shape=(1, 1) dtype=float32, numpy=array([[-0.7206192]], dtype=float32)>, <tf.Variable 'dense/bias:0' shape=(1,) dtype=float32, numpy=array([0.], dtype=float32)>]
Model 2
[<tf.Variable 'dense_1/kernel:0' shape=(1, 1) dtype=float32, numpy=array([[-0.7206192]], dtype=float32)>, <tf.Variable 'dense_1/bias:0' shape=(1,) dtype=float32, numpy=array([0.], dtype=float32)>]

这里内部状态复位,每个网络的内核W相等。

【讨论】:

  • 实际上把我的禁用随机性的代码解决了这个问题。非常感谢。
  • 嗨,我是来快速回答的。事实上,我仍然想知道我的情况会发生什么。首先,在我的代码开头,我使用以下代码禁用随机性 'def reset_random_seeds(): os.environ['PYTHONHASHSEED'] = str(1) tf.random.set_seed(1) np.random.seed( 1) random.seed(1)'
  • 问题是我没有得到随机的预测结果。如果是这样的话,我会理解的。问题是,如果我从命令提示符运行我的程序两次,我会得到完全相同的结果——我们称之为 A。但如果我用循环运行两次,我得到的结果 A 和结果 B 是不同的。但总是一样的。所以它似乎在运行之间没有被清理。或者另一个问题——我需要在每个模型再次创建后调用那个 set_seed 吗?我认为在启动代码时执行一次就足够了。它是否在模型编译/拟合/预测周期中被重置?
  • 我已经添加了更多解释,如果仍然不清楚,请告诉我。
  • 非常感谢您提供这么好的答案。现在我看到每次创建模型时都需要设置相同的种子。出色的答案
猜你喜欢
  • 2018-12-21
  • 2019-04-30
  • 1970-01-01
  • 1970-01-01
  • 2015-05-07
  • 1970-01-01
  • 2018-08-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多