为什么使用tensorflow2.0的同一数据集的训练准确性和验证准确性会有所不同?

时间:2019-11-15 10:30:13

标签: tensorflow keras tensorflow-datasets tensorflow2.0 tf.keras

我正在使用tensorflow2.0和tensorflow_datasets进行训练。但是我不明白:为什么训练的准确性和损失与valdataion的准确性和损失不同?

这是我的代码:

import tensorflow as tf
import tensorflow_datasets as tfds

data_name = 'uc_merced'
dataset = tfds.load(data_name)
# the train_data and the test_data are same dataset
train_data, test_data = dataset['train'], dataset['train'] 

def parse(img_dict):
    img = tf.image.resize_with_pad(img_dict['image'], 256, 256)
    #img = img / 255.
    label = img_dict['label']
    return img, label

train_data = train_data.map(parse)
train_data = train_data.batch(96)

test_data = test_data.map(parse)
test_data = test_data.batch(96)

strategy = tf.distribute.MirroredStrategy()
with strategy.scope():
    model = tf.keras.applications.ResNet50(weights=None, classes=21, 
            input_shape=(256, 256, 3))
    model.compile(optimizer='adam',
            loss='sparse_categorical_crossentropy',
            metrics=['accuracy'])

model.fit(train_data, epochs=50, verbose=2, validation_data=test_data)

这非常简单,您可以在计算机上运行它。您可以看到我的火车数据和验证数据是相同的train_data, test_data = dataset['train'], dataset['train']

但是火车的准确性(损失)与验证准确性(损失)不同。为什么会这样呢?这是tensorflow2.0的错误吗?

Epoch 1/50
22/22 - 51s - loss: 3.3766 - accuracy: 0.2581 - val_loss: 0.0000e+00 - val_accuracy: 0.0000e+00
Epoch 2/50
22/22 - 30s - loss: 1.8221 - accuracy: 0.4590 - val_loss: 123071.9851 - val_accuracy: 0.0476
Epoch 3/50
22/22 - 30s - loss: 1.4701 - accuracy: 0.5405 - val_loss: 12767.8928 - val_accuracy: 0.0519
Epoch 4/50
22/22 - 30s - loss: 1.2113 - accuracy: 0.6071 - val_loss: 3.9311 - val_accuracy: 0.1186
Epoch 5/50
22/22 - 31s - loss: 1.0846 - accuracy: 0.6567 - val_loss: 23.7775 - val_accuracy: 0.1386
Epoch 6/50
22/22 - 31s - loss: 0.9358 - accuracy: 0.7043 - val_loss: 15.3453 - val_accuracy: 0.1543
Epoch 7/50
22/22 - 32s - loss: 0.8566 - accuracy: 0.7243 - val_loss: 8.0415 - val_accuracy: 0.2548

1 个答案:

答案 0 :(得分:2)

简而言之,罪魁祸首是BatchNorm。

由于数据集较小且批处理量较大,因此每个纪元仅进行22次更新。 BatchNorm图层的默认动量为0.99,因此需要花费一些时间才能将BatchNorm运行均值/方差移动到更适合您的数据集的值(如果您不对像素值进行归一化,则其值不会超出[0,255]范围,与通常设计/初始化的神经网络期望的典型mean=0, variance=1范围相去甚远。

训练与验证损失/准确性之间存在较大差异的原因是,批次规范与测试行为的训练行为非常不同,尤其是对于很少的批次。训练期间通过网络运行的数据平均值与到目前为止积累的运行平均值相差很远,由于BatchNorm的默认动量/衰减为0.99,更新的平均值仅会缓慢更新。

如果将批次大小从96减少到4,则将大大增加BatchNorm运行均值/方差的更新频率。这样做,加上在数据解析函数中取消注释#img = img / 255.行,可以在很大程度上缓解训练/验证差异。这样做为我提供了三个时期的输出:

Epoch 1/7
525/525 - 51s - loss: 3.2650 - accuracy: 0.1633 - val_loss: 0.0000e+00 - val_accuracy: 0.0000e+00
Epoch 2/7
525/525 - 38s - loss: 2.6455 - accuracy: 0.2152 - val_loss: 12.1067 - val_accuracy: 0.2114
Epoch 3/7
525/525 - 38s - loss: 2.5033 - accuracy: 0.2414 - val_loss: 16.9369 - val_accuracy: 0.2095

您还可以使代码保持不变,而是修改Resnet50的keras_applications实现以在所有地方使用BatchNormalization(..., momentum=0.9)。在两个时期之后,这给了我以下输出,我认为这或多或少表明确实是您问题的主要原因:

Epoch 1/2
22/22 [==============================] - 33s 1s/step - loss: 3.1512 - accuracy: 0.2357 - val_loss: 0.0000e+00 - val_accuracy: 0.0000e+00
Epoch 2/2
22/22 [==============================] - 16s 748ms/step - loss: 1.7975 - accuracy: 0.4505 - val_loss: 4.1324 - val_accuracy: 0.2810