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

时间:2016-03-29 15:11:05

标签: python numpy tensorflow

我正在尝试使用不同的参数多次运行神经网络,以便校准网络参数(丢失概率,学习率e.d.)。但是我遇到的问题是,当我在循环中运行网络时,运行网络同时保持参数相同仍然给我一个不同的解决方案:

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来为每个纪元改变传入的图像。

8 个答案:

答案 0 :(得分:36)

设置当前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)

答案 1 :(得分:13)

Tensorflow 2.0兼容答案:对于大于2.0的Tensorflow版本,如果我们要设置全局随机种子,则使用的命令为 tf.random.set_seed 。< / p>

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

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

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

有关更多详细信息,请参阅此firebase documentation

答案 2 :(得分:12)

可以通过提供图表级别或操作级别种子来获得确定性行为。两者都适合我。图表级种子可以与tf.set_random_seed一起放置。操作级种子可以放在例如变量初始化器中,如下所示:

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

答案 3 :(得分:7)

由于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中概述的过程。

答案 4 :(得分:7)

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

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

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

SEED = 0
  1. 为可能具有随机行为的所有库初始化种子的函数
def set_seeds(seed=SEED):
    os.environ['PYTHONHASHSEED'] = str(seed)
    random.seed(seed)
    tf.random.set_seed(seed)
    np.random.seed(seed)
  1. 激活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())进行了多次实验,上面的代码给了我可重复的结果。

参考:

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

答案 5 :(得分:1)

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

tf.reset_default_graph()

tf.set_random_seed(0)

random.seed(0)

np.random.seed(0)

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

答案 6 :(得分:0)

我正在使用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,
                   )

这是我的理解:

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

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

要了解正在发生的事情,您应该阅读the docs,它们不那么长而且有点容易理解。

答案 7 :(得分:-1)

此答案是对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)