随机性能的验证和测试精度,而训练精度非常高

Validation and Test accuracy at random performance, whereas Train accuracy very high

我正在尝试在 TensorFlow2.1 中为 CIFAR10 使用 ResNet50imagenet 上预训练的分类器 来自 keras.application 然后在其上堆叠一个小的 FNN:

# Load ResNet50 pre-trained on imagenet
resn = applications.resnet50.ResNet50(weights='imagenet', input_shape=(IMG_SIZE, IMG_SIZE, 3), pooling='avg', include_top=False)

# Load CIFAR10 
(c10_train, c10_test), info = tfds.load(name='cifar10', split=['train', 'test'], with_info=True, as_supervised=True)

# Make sure all the layers are not trainable
for layer in resn.layers:
    layer.trainable = False

# Transfert Learning for CIFAR10: fine-tune the network by stacking a trainable FNN on top of Resnet
from tensorflow.keras import models, layers

def build_model():
  model = models.Sequential()
  # Feature extractor
  model.add(resn)
  # Small FNN
  model.add(layers.Dense(256, activation='relu'))
  model.add(layers.Dropout(0.4))
  model.add(layers.Dense(10, activation='softmax'))

  model.compile(loss='categorical_crossentropy',
                optimizer=tf.keras.optimizers.SGD(learning_rate=0.1),
                metrics=['accuracy'])

  return model

# Build the resulting net
resn50_c10 = build_model()

我在验证或测试准确性时遇到以下问题:

history = resn50_c10.fit_generator(c10_train.shuffle(1000).batch(BATCH_SIZE), validation_data=c10_test.batch(BATCH_SIZE), epochs=20)

Epoch 1/20
25/25 [==============================] - 113s 5s/step - loss: 0.9659 - accuracy: 0.6634 - val_loss: 2.8157 - val_accuracy: 0.1000
Epoch 2/20
25/25 [==============================] - 109s 4s/step - loss: 0.8908 - accuracy: 0.6920 - val_loss: 2.8165 - val_accuracy: 0.1094
Epoch 3/20
25/25 [==============================] - 116s 5s/step - loss: 0.8743 - accuracy: 0.7038 - val_loss: 2.7555 - val_accuracy: 0.1016
Epoch 4/20
25/25 [==============================] - 132s 5s/step - loss: 0.8319 - accuracy: 0.7166 - val_loss: 2.8398 - val_accuracy: 0.1013
Epoch 5/20
25/25 [==============================] - 132s 5s/step - loss: 0.7903 - accuracy: 0.7253 - val_loss: 2.8624 - val_accuracy: 0.1000
Epoch 6/20
25/25 [==============================] - 132s 5s/step - loss: 0.7697 - accuracy: 0.7325 - val_loss: 2.8409 - val_accuracy: 0.1000
Epoch 7/20
25/25 [==============================] - 132s 5s/step - loss: 0.7515 - accuracy: 0.7406 - val_loss: 2.7697 - val_accuracy: 0.1000   
#... (same for the remaining epochs) 

尽管模型似乎从训练拆分中充分学习,验证集的准确性和损失都没有任何改善。是什么导致了这种行为?

我排除这是过度拟合,因为我正在应用 Dropout,而且模型似乎从未真正改进测试集。

到目前为止我做了什么:

并且总是遇到同样的问题。

如有任何提示,我们将不胜感激。

问题可能是由于使用 tfds 加载数据然后传递给 Keras .fit

尝试使用

加载您的数据
from keras.datasets import cifar10

(x_train, y_train), (x_test, y_test) = cifar10.load_data()

然后

fit(x=x_train, y=y_train, batch_size=BATCH_SIZE, epochs=20, verbose=1, callbacks=None, validation_split=0.2, validation_data=None, shuffle=True)

显然问题是由使用 ResNet50.

引起的

作为解决方法,我下载并使用了其他预训练的深度网络,例如 keras.applications.vgg16.VGG16keras.applications.densenet.DenseNet121,测试集的准确性如预期的那样提高。

更新

这个答案的以上部分只是治标不治本。为了了解真正发生的事情并最终通过 ResNet50 正确使用迁移学习,请继续阅读。

根本原因似乎在于 Keras 如何处理 Batch Normalization 层:

During fine-tuning, if a Batch Normalization layer is frozen it uses the mini-batch statistics. I believe this is incorrect and it can lead to reduced accuracy especially when we use Transfer learning. A better approach in this case would be to use the values of the moving mean and variance.

正如此处更深入的解释:https://github.com/keras-team/keras/pull/9965

即使在 TensorFlow 2 中实现了正确的方法,当我们使用 tf.keras.applications 时,我们参考了 TensorFlow 1.0 行为用于批量归一化。这就是为什么我们需要在加载模块时通过添加参数 layers=tf.keras.layers 来显式注入对 TensorFlow 2 的引用。所以在我的例子中,ResNet50 的加载将变成

history = resn50_c10.fit_generator(c10_train.shuffle(1000).batch(BATCH_SIZE), validation_data=c10_test.batch(BATCH_SIZE), epochs=20, layers=tf.keras.layers)

这样就可以了。

@rpeloff 解决方案的致谢:https://github.com/keras-team/keras/pull/9965#issuecomment-549126009