如何使用 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.1
、cudnn: 7
、tensorflow-gpu: 2.1.0
、keras: 2.2.4-tf
和 vgg19
自定义模型
在研究了使用 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 model.evaluate 给出的结果与从训练中获得的结果不同
如何在保持相同形状和尺寸的同时获得 tensorflow 数据集中的最大值?