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

时间:2020-05-03 16:16:00

标签: keras deep-learning tensorflow2.0 resnet batch-normalization

我正在尝试使用通过 keras的 imagenet 预训练的 ResNet50 在TensorFlow2.1中为 CIFAR10 构建分类器。应用程序,然后在其顶部堆叠一个小的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,并且由于该模型似乎从未真正改善测试集,因此我排除了这种过拟合现象。

到目前为止我所做的:

  • 在培训和测试过程中检查单贴标签是否一致
  • 尝试了不同的FNN配置
  • 尝试使用方法fit_generator代替fit
  • 预处理图像,使用不同的input_shapes调整图像大小

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

任何提示将不胜感激。

2 个答案:

答案 0 :(得分:0)

问题可能是由于使用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)

答案 1 :(得分:0)

显然,该问题是由使用OEM引起的。

作为一种解决方法,我下载并使用了其他经过预先训练的深度网络,例如OEMResNet50,并且测试集的准确性如预期的那样提高。

更新

此答案的以上部分只是姑息治疗。为了了解实际情况,并最终在ResNet50中正确使用转移学习,请继续阅读。

根本原因似乎在于keras.applications.vgg16.VGG16处理keras.applications.densenet.DenseNet121层的方式:

在微调期间,如果冻结了“批次标准化”层,则它将使用微型批次统计信息。我认为这是不正确的,并且会导致准确性降低,尤其是当我们使用转移学习时。在这种情况下,一种更好的方法是使用移动平均值和方差的值。

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

即使在使用Keras TensorFlow 2 中实现了正确的方法,我们也会引用 TensorFlow 1.0 行为进行批处理规范化。这就是为什么我们需要在加载模块时通过添加参数Batch Normalization来显式地注入对 TensorFlow 2 的引用。因此,以我为例,ResNet50的加载将变为

tf.keras.applications

这将解决问题。

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