在GPU上实现可重复结果的Keras项目架构

3
我正在编写一个tensorflow.Keras的包装器,以执行机器学习实验。
我需要我的框架能够按照配置yaml文件指定的实验进行并行GPU运行。
然后,我需要保证如果我再次运行实验,我会得到与之前相同或者相似的结果。
为了尝试确保这一点,我的训练脚本在开头包含以下代码,遵循官方文档的指导。
# Set up random seeds
random.seed(seed)
np.random.seed(seed)
tf.set_random_seed(seed)

这已经被证明是不够的。

我运行了相同的配置4次,并绘制了结果:

enter image description here

正如您所见,不同运行结果差异很大。

我该如何在Keras中设置训练会话以确保在GPU上训练时获得相似的结果?这是否可能?

完整的训练脚本可以在此处找到。

我的一些同事正在使用纯TF,他们的结果似乎更加一致。而且,除了确保训练和验证拆分始终相同之外,他们似乎没有种植任何随机性。


1
就我个人而言,除了训练/测试分离之外,我从未使用过其他种子。我不熟悉你的数据,不能确定,但根据我的经验,在训练中模型最常失败的地方是1.批量大小和2.优化器和学习率。看着你的脚本,你正在使用Adam优化器,我个人非常喜欢它,但如果你没有正确设置学习率,它可能会明显地超调。一眼看去,我会建议你更多地探索你的数据,找出变化幅度,并尝试调整批量大小和学习率(假设你的模型没有任何错误)。 - Alexander Ejbekov
2个回答

7
Keras + Tensorflow.
第一步,禁用GPU。
import os
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"] = ""

第二步,为代码中包含的库设置种子,例如“tensorflow,numpy,random”。

import tensorflow as tf
import numpy as np
import random as rn

sd = 1 # Here sd means seed.
np.random.seed(sd)
rn.seed(sd)
os.environ['PYTHONHASHSEED']=str(sd)

from keras import backend as K
config = tf.ConfigProto(intra_op_parallelism_threads=1,inter_op_parallelism_threads=1)
tf.set_random_seed(sd)
sess = tf.Session(graph=tf.get_default_graph(), config=config)
K.set_session(sess)

确保在你的代码开头包含这两个代码片段,然后结果将是可重现的。


你能解释一下为什么要禁用GPU吗?GPU是训练过程中至关重要的元素... - Nathan B
2
@NadavB,文档已经很好地解释了:https://keras.io/getting_started/faq/#how-can-i-obtain-reproducible-results-using-keras-during-development。具体来说,“此外,在GPU上运行时,某些操作具有不确定的输出,特别是tf.reduce_sum()。这是因为GPU并行运行许多操作,因此执行顺序并不总是保证的。” - cddt
@cddt,很有趣,但是当你拥有多个核心时,CPU也会并行运行,不是吗? - Nathan B
@guirui AttributeError: 模块 'tensorflow' 没有属性 'ConfigProto' - jtlz2
AttributeError: module 'tensorflow' has no attribute 'set_random_seed' - jtlz2
AttributeError: module 'tensorflow' has no attribute 'Session' “属性错误:模块'tensorflow'没有属性'Session'” - jtlz2

1
尝试将种子参数添加到权重/偏置初始化器中,这只是为了更具体地补充Alexander Ejbekov的评论。
Tensorflow有两个随机种子:图级别和操作级别。如果您使用多个图形,则需要在每个图形中指定种子。您可以通过在函数内设置种子参数来覆盖图级别种子,并且如果设置相同的种子,则可以使来自不同图形的两个函数输出相同的值。请考虑以下示例:
g1 = tf.Graph()
with g1.as_default():
    tf.set_random_seed(1)
    a = tf.get_variable('a', shape=(1,), initializer=tf.keras.initializers.glorot_normal())
    b = tf.get_variable('b', shape=(1,), initializer=tf.keras.initializers.glorot_normal(seed=2))
with tf.Session(graph=g1) as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run(a)) 
    print(sess.run(b))
g2 = tf.Graph()
with g2.as_default():
    a1 = tf.get_variable('a1', shape=(1,), initializer=tf.keras.initializers.glorot_normal(seed=1))

with tf.Session(graph=g2) as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run(a1))

在这个例子中,a 的输出与 a1 相同,但是b不同。

谢谢您的回答!如果我使用 tensorflow.keras 接口而不是裸 TF 会话,我该如何适应这个问题? - Jsevillamol
你可以在keras.layers中设置种子,也可以通过tf.get_default_graph()访问图形。 - Sharky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接