在两个不同的运行tensorflow中有相同的结果

Have the same result in two different runs tensorflow

我正在尝试 运行 Training a neural network on MNIST with Keras 中的示例。我想做两次给出权重而不是洗牌,所以我在两个 运行 中得到相同的结果。完整代码在这里:

import tensorflow.compat.v2 as tf
import tensorflow_datasets as tfds
import numpy as np

tf.enable_v2_behavior()
tfds.disable_progress_bar()

def normalize_img(image, label):
    """Normalizes images: `uint8` -> `float32`."""
    return tf.cast(image, tf.float32) / 255., label

def get_dataset():
    (ds_train, ds_test), ds_info = tfds.load(
        'mnist',
        split=['train', 'test'],
        shuffle_files=True,
        as_supervised=True,
        with_info=True,
    )

    ds_train = ds_train.map(normalize_img, num_parallel_calls=tf.data.experimental.AUTOTUNE)
    ds_train = ds_train.cache()
    # ds_train = ds_train.shuffle(ds_info.splits['train'].num_examples)
    ds_train = ds_train.batch(128)
    ds_train = ds_train.prefetch(tf.data.experimental.AUTOTUNE)

    ds_test = ds_test.map(normalize_img, num_parallel_calls=tf.data.experimental.AUTOTUNE)
    ds_test = ds_test.batch(128)
    ds_test = ds_test.cache()
    ds_test = ds_test.prefetch(tf.data.experimental.AUTOTUNE)

    return ds_train, ds_test

def keras_fit(ds_train, ds_test, verbose=True, init1='glorot_uniform', init2='glorot_uniform'):
    # https://www.tensorflow.org/datasets/keras_example
    model = tf.keras.models.Sequential([
      tf.keras.layers.Flatten(input_shape=(28, 28, 1)),
      tf.keras.layers.Dense(128, activation='relu', kernel_initializer=init1),
      tf.keras.layers.Dense(10, activation='softmax', kernel_initializer=init2)
    ])
    model.compile(
        loss='sparse_categorical_crossentropy',
        optimizer=tf.keras.optimizers.Adam(0.001),
        metrics=['accuracy'],
    )
    model.fit(
        ds_train,
        epochs=6,
        validation_data=ds_test,
        verbose=verbose, shuffle=False
    )
    return model.evaluate(ds_test, verbose=verbose)

def test_mnist():
    init = tf.keras.initializers.GlorotUniform()
    init1 = tf.constant_initializer(init((784, 128)).numpy())
    init2 = tf.constant_initializer(init((128, 10)).numpy())
    ds_train, ds_test = get_dataset()
    keras1 = keras_fit(ds_train, ds_test, init1=init1, init2=init2)
    keras2 = keras_fit(ds_train, ds_test, init1=init1, init2=init2)
    print(keras1)
    print(keras2)

if __name__ == "__main__":
    test_mnist()

根据我的理解,两个层都将使用完全相同的值进行初始化,并且我不会随机打乱数据(拟合函数具有 shuffle=False)。我不应该得到完全相同的结果吗?我做错了什么?

我得到的结果非常相似,有时准确度也一样,但这不是 100% 确定。

PS:我在每个时期后收到以下消息:

[[{{node IteratorGetNext}}]]
         [[Shape/_6]]
2020-12-20 13:52:10.002034: W tensorflow/core/common_runtime/base_collective_executor.cc:217] BaseCollectiveExecutor::StartAbort Out of range: End of sequence
         [[{{node IteratorGetNext}}]]

我尝试了基本相同的脚本,但使用了 fashion MNIST。它奏效了!我得到完全相同的结果。

区别在于 Fashion MNIST 使用 numpy 数组而不是 tf.dataset

问题一定是 tf.dataset class 完成的洗牌或者我收到的警告消息,也许我在停止并开始之前没有完成对整个数据集的迭代下一个在同一时间?

tensorflow 随机初始化 Dense 的权重。

np.random.seed(24)
tf.random.set_seed(24)

可能会有帮助。

好的,我得到了为什么有时有效而有时无效的答案。我开始意识到它在使用 CPU 而不是在使用 GPU 时有效。

因此,如果您有 GPU,此代码将无法运行,但可以在开始时使用 os.environ['CUDA_VISIBLE_DEVICES'] = '-1' 使其运行。

我对发生这种情况的理论如下: 假设我有 2 个批次,在 CPU,我将在批次 1 上训练,更新权重,然后在批次 2 上训练。在 GPU 上,我将发送两个批次进行并行训练,因此批次 2 将在其他权重(在第 1 批更新之前)。