如何利用 TensorFlow 获得稳定的结果,设置随机种子
- 2025-04-16 08:58:00
- admin 原创
- 9
问题描述:
我正在尝试使用不同的参数多次运行神经网络,以便校准网络参数(例如dropout概率、学习率等)。然而,我遇到了一个问题:即使参数保持不变,当我循环运行网络时,仍然会得到不同的结果,如下所示:
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
来对每个时期的传入图像进行打乱。
解决方案 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)
。
解决方案 2:
后端设置:cuda:10.1
、、、和自cudnn: 7
定义tensorflow-gpu: 2.1.0
模型keras: 2.2.4-tf
`vgg19`
在研究了使用 GPU 训练的 tensorflow 后端和基于 keras 的大型神经网络模型的结果不稳定的问题后,我终于能够获得可重复(稳定)的结果,如下所示:
仅导入设置种子所需的库并初始化种子值
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://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
解决方案 3:
可以通过提供图级或操作级种子来获得确定性行为。对我来说,两种方法都有效。图级种子可以通过tf.set_random_seed来设置。操作级种子可以放置在变量初始化器中,例如:
myvar = tf.Variable(tf.truncated_normal(((10,10)), stddev=0.1, seed=0))
解决方案 4:
Tensorflow 2.0 兼容答案:对于大于 2.0 的 Tensorflow 版本,如果我们要设置全局随机种子,使用的命令是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 页面。
解决方案 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中概述的步骤。
解决方案 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 支持人员的回答中添加一些内容。
当我使用 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 次,我会得到相同的结果。我认为这是因为第一次运行
get_mlp_model_compiled()
没有使用 TensorFlow 的内部计数器和我的种子。第二次运行会使用种子,并且所有后续运行也会使用这个种子,所以第二次运行之后的结果会相同。
我可能有一些信息错误,所以请随时纠正我。
要了解发生了什么,您应该阅读文档,它们不太长并且很容易理解。
解决方案 8:
这个答案是对Luke 的答案的补充,也是针对 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)
扫码咨询,免费领取项目管理大礼包!