我正在尝试使用通过 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,并且由于该模型似乎从未真正改善测试集,因此我排除了这种过拟合现象。
到目前为止我所做的:
fit_generator
代替fit
并且总是遇到同样的问题。
任何提示将不胜感激。
答案 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
引起的。
作为一种解决方法,我下载并使用了其他经过预先训练的深度网络,例如OEM
,ResNet50
,并且测试集的准确性如预期的那样提高。
更新
此答案的以上部分只是姑息治疗。为了了解实际情况,并最终在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