如何使用 TensorFlow 获得稳定的结果,设置随机种子

Posted

技术标签:

【中文标题】如何使用 TensorFlow 获得稳定的结果,设置随机种子【英文标题】:How to get stable results with TensorFlow, setting random seed 【发布时间】:2016-07-17 05:46:46 【问题描述】:

我正在尝试使用不同的参数多次运行神经网络,以校准网络参数(辍学概率、学习率等)。但是我遇到的问题是,当我在循环中运行网络时,在保持参数相同的情况下运行网络仍然给了我不同的解决方案,如下所示:

filename = create_results_file()
for i in range(3):
  g = tf.Graph()
  with g.as_default():
    accuracy_result, average_error = network.train_network(
        parameters, inputHeight, inputWidth, inputChannels, outputClasses)
    f, w = get_csv_writer(filename)
    w.writerow([accuracy_result, "did run %d" % i, average_error])
    f.close()

在设置网络的层和错误函数之前,我在 train_network 函数的开头使用以下代码:

np.random.seed(1)
tf.set_random_seed(1)

我也尝试在创建 TensorFlow 图形之前添加此代码,但我在结果输出中不断得到不同的解决方案。

我正在使用 AdamOptimizer,并正在使用 tf.truncated_normal 初始化网络权重。此外,我使用np.random.permutation 对每个时期的传入图像进行洗牌。

【问题讨论】:

Reproducible results in Tensorflow with tf.set_random_seed的可能重复 但是这个问题是在 2 年前提出的,所以这个问题是重复的。 【参考方案1】:

设置当前的 TensorFlow 随机种子仅影响当前的默认图。由于您正在为训练创建一个新图并将其设置为默认值 (with g.as_default():),因此您必须在该 with 块的范围内设置随机种子。

例如,您的循环应如下所示:

for i in range(3):
  g = tf.Graph()
  with g.as_default():
    tf.set_random_seed(1)
    accuracy_result, average_error = network.train_network(
        parameters, inputHeight, inputWidth, inputChannels, outputClasses)

请注意,这将为外部for 循环的每次迭代使用相同的随机种子。如果您想在每次迭代中使用不同但仍具有确定性的种子,您可以使用tf.set_random_seed(i + 1)

【讨论】:

我相信我的 set_random_seed(1) 已经在 g.as_default() 块中,因为它是 train_network 代码中的第一行之一。尽管如此,我已经尝试将代码放在您的示例中,但我仍然得到不稳定的结果: > 准确度标签错误 > 0.9805 运行 0 2.96916 > 0.9807 运行 1 2.96494 > 0.9804 运行 2 2.95215 我遇到了同样的问题。 tensorflow 0.12.1 按指定设置随机种子 我发现每次运行的概率输出略有不同。 原因取决于你的函数是什么,但精度计算的微小差异很可能是由像tf.reduce_sum() 这样的操作的非确定性并行减少引起的。 (这些操作将浮点加法视为可交换的,而实际上并非如此,并且减少顺序的更改可能会导致结果出现轻微错误......) @mrry,我遇到了与DropoutWrapper 类似的错误。当我保留keep_prob=1 时,我会得到一致的结果。然而,不同的运行给我不同的值keep_prob=0.8。可能是什么原因?我已将其移至 ***.com/questions/42156296【参考方案2】:

可以通过提供图形级或操作级种子来获得确定性行为。两者都为我工作。可以使用tf.set_random_seed 放置图形级种子。操作级种子可以放置在变量初始化器中,例如:

myvar = tf.Variable(tf.truncated_normal(((10,10)), stddev=0.1, seed=0))

【讨论】:

【参考方案3】:

Tensorflow 2.0 Compatible Answer:对于Tensorflow 2.0以上的版本,如果我们要设置全局随机种子,使用的命令是tf.random.set_seed

如果我们从 Tensorflow Version 1.x to 2.x 迁移,我们可以使用命令, tf.compat.v2.random.set_seed

请注意,在这种情况下,tf.function 就像重新运行程序一样。

要设置操作级别种子(如上所述),我们可以使用命令,tf.random.uniform([1], seed=1)

更多详情,请参考Tensorflow Page。

【讨论】:

【参考方案4】:

后端设置:cuda:10.1cudnn: 7tensorflow-gpu: 2.1.0keras: 2.2.4-tfvgg19 自定义模型

在研究了使用 GPU 训练和基于 keras 的大型神经网络模型的 tensorflow 后端结果不稳定的问题后,我终于能够获得可重现(稳定)的结果,如下所示:

    仅导入设置种子和初始化种子值所需的库
import tensorflow as tf
import os
import numpy as np
import random

SEED = 0
    为所有可能具有随机行为的库初始化种子的函数
def set_seeds(seed=SEED):
    os.environ['PYTHONHASHSEED'] = str(seed)
    random.seed(seed)
    tf.random.set_seed(seed)
    np.random.seed(seed)
    激活Tensorflow确定性行为
def set_global_determinism(seed=SEED):
    set_seeds(seed=seed)

    os.environ['TF_DETERMINISTIC_OPS'] = '1'
    os.environ['TF_CUDNN_DETERMINISTIC'] = '1'
    
    tf.config.threading.set_inter_op_parallelism_threads(1)
    tf.config.threading.set_intra_op_parallelism_threads(1)

# Call the above function with seed value
set_global_determinism(seed=SEED)

重要提示:

请在执行任何其他代码之前调用上述代码 由于代码是确定性的,模型训练可能会变慢,因此需要权衡 我用不同数量的 epoch 和不同的设置(包括 shuffle=True 的 model.fit())进行了多次实验,上面的代码给出了可重现的结果。

参考资料:

    https://suneeta-mall.github.io/2019/12/22/Reproducible-ml-tensorflow.html https://keras.io/getting_started/faq/#how-can-i-obtain-reproducible-results-using-keras-during-development https://www.tensorflow.org/api_docs/python/tf/config/threading/set_inter_op_parallelism_threads https://www.tensorflow.org/api_docs/python/tf/random/set_seed?version=nightly

【讨论】:

根据docs.nvidia.com/deeplearning/frameworks/…,设置TF_DETERMINISTIC_OPS=1就足够了。它将自行启用 TF_CUDNN_DETERMINISTIC。【参考方案5】:

由于 CuDNN 中的底层实现问题,这些答案似乎都不起作用。

你可以通过添加一个额外的标志来获得更多的确定性

os.environ['PYTHONHASHSEED']=str(SEED)
os.environ['TF_CUDNN_DETERMINISTIC'] = '1'  # new flag present in tf 2.0+
random.seed(SEED)
np.random.seed(SEED)
tf.set_random_seed(SEED)

但这仍然不是完全确定的。要获得更精确的解决方案,您需要使用此 nvidia repo 中概述的过程。

【讨论】:

需要注意的是,在进程内设置PYTHONHASHSEED没有任何作用——它需要在进程本身之外设置,或者脚本必须打开一个预先设置了该环境变量的新进程。跨度> 【参考方案6】:

请在您的代码前添加所有随机种子函数:

tf.reset_default_graph()
tf.random.set_seed(0)
random.seed(0)
np.random.seed(0)

我认为,TensorFlow 中的一些模型正在使用 numpy 或 python 随机函数。

【讨论】:

【参考方案7】:

我正在使用 TensorFlow 2 (2.2.0),并且正在 JupyterLab 中运行代码。我已经在 macOS Catalina 和 Google Colab 中对此进行了测试,结果相同。我会在Tensorflow Support's答案中添加一些东西。

当我使用 model.fit() 方法进行一些训练时,我会在一个单元格中进行。我在其他牢房里做一些其他的事情。这是我在提到的单元格中运行的代码:

# To have same results always place this on top of the cell
tf.random.set_seed(1)

(x_train, y_train), (x_test, y_test) = load_data_onehot_grayscale()
model = get_mlp_model_compiled() # Creates the model, compiles it and returns it

history = model.fit(x=x_train, y=y_train,
                    epochs=30,
                    callbacks=get_mlp_model_callbacks(),
                    validation_split=.1,
                   )

这是我的理解:

    TensorFlow 有一些随机过程发生在不同的阶段(初始化、洗牌等),每次这些过程发生时,TensorFlow 都会使用一个随机函数。当您使用 tf.random.set_seed(1) 设置种子时,您会让这些进程使用它,如果设置了种子并且进程没有更改,结果将是相同的。 现在,在上面的代码中,如果我将 tf.random.set_seed(1) 更改为低于 model = get_mlp_model_compiled() 行,我的结果会发生变化,我相信这是因为 get_mlp_model_compiled() 使用随机性并且没有使用我想要的种子。 关于第 2 点的警告:如果我连续运行单元格 3 次,我会得到相同的结果。我相信会发生这种情况,因为在运行 nº1 get_mlp_model_compiled() 时,我的种子没有使用 TensorFlow 的内部计数器。在第 2 次运行中,它将使用种子,并且所有后续运行也将使用种子,因此第 2 次运行后的结果将是相同的。

我可能有一些信息有误,请随时纠正我。

要了解发生了什么,您应该阅读the docs,它们并不长且易于理解。

【讨论】:

【参考方案8】:

此答案是对Luke's answer 和 TF v2.2.0 的补充

import numpy as np
import os
import random
import tensorflow as tf # 2.2.0

SEED = 42
os.environ['PYTHONHASHSEED']=str(SEED)
os.environ['TF_CUDNN_DETERMINISTIC'] = '1'  # TF 2.1
random.seed(SEED)
np.random.seed(SEED)
tf.random.set_seed(SEED)

【讨论】:

使用TF_CUDNN_DETERMINISTIC 会破坏带有 tf 2.3.0 的笔记本,不知道为什么。这让我在我的代码中直接调试了 2 天!不要使用这个。

以上是关于如何使用 TensorFlow 获得稳定的结果,设置随机种子的主要内容,如果未能解决你的问题,请参考以下文章

如何高效的学习 TensorFlow 代码

Tensorflow model.evaluate 给出的结果与从训练中获得的结果不同

如何高效的学习 TensorFlow 代码

如何在保持相同形状和尺寸的同时获得 tensorflow 数据集中的最大值?

如何在稳定的基线中获得 action_propability() 3

将随机值从数组复制到对象无法获得稳定的结果