即使设置了随机种子也无法重现张量流结果

时间:2018-11-20 15:47:55

标签: python tensorflow random-seed

为了能够执行超参数优化,我想最好设置随机种子,以便我们更好地比较模型。因此,我通过以下方式在张量流中设置了随机种子:tf.set_random_seed(mseed),并创建了一个初始化器:kernel_initializer = tf.glorot_normal_initializer(seed=mseed),将后者传递给LSTM单元格。因此模型如下:

import tensorflow as tf
import numpy as np


def lstm_model(lstm_model(inputs, cell_size1, kernel_initializer, m_dtype, dropout, is_training, use_peepholes, mseed, num_classes):

    with tf.variable_scope('lstm_model'):

        cell = tf.nn.rnn_cell.LSTMCell(cell_size1, initializer=kernel_initializer)
        initial_state = cell.zero_state(34 if is_training else 14, dtype=tf.float32)

        output, new_state = tf.nn.dynamic_rnn(cell, inputs, dtype=m_dtype, initial_state=initial_state)


    with tf.variable_scope("output"):
        output = tf.reshape(output, shape=[-1, cell_size1])
        output = tf.layers.dense(output, units=num_classes,
                                 kernel_initializer=kernel_initializer)

        if is_training:
            output = tf.reshape(output, shape=[34, -1, num_classes])
        else:
            output = tf.reshape(output, shape=[14, -1, num_classes])

        return output, new_state, initial_state, model_summary


def model(inputs..., mseed, kernel_initializer, reuse=False):
    with tf.variable_scope('model', reuse=reuse):

        output, new_state, initial_state, model_summary = lstm_model(inputs, num_units,
                                                                     kernel_initializer,
                                                                     tf.float32, dropout, not reuse, True,
                                                                     mseed, num_classes=num_classes)

    # Now I calculate the loss and used an optimizer in case of training...
    return output, new_state, initial_state, model_summary

mseed = 123
seed(mseed)
tf.set_random_seed(mseed)
kernel_initializer = tf.glorot_normal_initializer(seed=mseed)

# here I loaded the data as numpy arrays...
# Here I created the placeholders...

# t for train, and d for development
output_t, new_state_t, init_state_t = model(inputs_t..., mseed, kernel_initializer, reuse=False)
output_d, new_state_d, init_state_d = model(inputs_d..., mseed, kernel_initializer, reuse=True)

train_model()...

因此,对代码进行了汇总,使其仅包括其中的重要部分。

现在即使在创建内核时设置了随机种子并使用mseed之后,我仍然无法再现相同的结果。

以下是准确性和时间损失的屏幕截图。我们可以看到值几乎在一开始就相同,然后又变得不同。

enter image description here

enter image description here

我想知道我可能会在哪里弄错或者至少要调试代码的哪一部分。最后,请注意,通过培训,我将每批产品的最后一个隐藏状态反馈到初始状态。如下:

new_state_train_py = sess.run(initiale_state_train)
    for i in range(num_iterations):
        _, summary_t, new_state_train_py = sess.run([train_step, summary_train, new_state_train],
                                feed_dict={train_x_ph: train_x[:, i*time_steps: (i + 1) * time_steps, :],
                                           train_y_ph: train_y[:, i*time_steps: (i + 1) * time_steps, :],
                                           initiale_state_train: new_state_train_py})

        train_writer.add_summary(summary_t, epoch * num_iterations + i)

到目前为止,我所知道的是主要问题应该在模型定义中,因为这定义了整个模型中的任何随机性,这使同一模型的不同运行之间的预测有所不同。如果我弄错了,请纠正我。

调试后,我注意到当我将图中每个操作的dtype更改为tf.float64时,我发现两条曲线都完全相交,除了最后一条,我在曲线上又有了一些细微的变化。可能是什么原因导致了这种行为?

enter image description here enter image description here

非常感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

如果您在GPU上运行代码,则可能是由于cuDNN的不确定行为(有关更多详细信息,请参见this thread)。由于性能优化,在GPU上执行某些操作的顺序可能是随机的。这意味着舍入误差也会以不同的顺序发生,从而导致这些运算结果的微小差异。在您的情况下,这些小的差异会在整个培训过程中加起来,这导致在经过几个培训步骤后就已经存在明显不同的行为。

舍入误差的数量级取决于GPU使用的浮点精度。与float64相比,使用float32时,舍入错误要花费更长的时间才能明显累加。

在CPU上,当固定python,numpytensorflow的随机种子时,不应出现这种不确定性行为。因此,如果您在CPU上运行代码,则每次运行都应获得相同的结果(但当然要花更长的时间)。