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

Unable to reproduce tensorflow results even after setting random seed

为了能够执行超参数优化,我想最好设置随机种子,以便我们更好地比较模型。因此,我通过 tf.set_random_seed(mseed) 在 tensorflow 中设置了随机种子,并创建了一个初始值设定项: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 之后,我也无法重现相同的结果。

这是准确率和随时间损失的屏幕截图。我们可以看到,开始时的值几乎相同,然后它们变得不同。

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

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 时,我发现两条曲线完全相交,除了最后,我得到另一个细微的变化曲线。是什么导致了这种行为?

非常感谢任何帮助!!

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

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

在 CPU 上,如果 python、numpytensorflow 的随机种子是固定的(并且操作并行性已停用,更多信息 here)。所以,如果你 运行 你的代码在 CPU 上,你应该对每个 运行 得到相同的结果(但当然需要更长的时间)。