随机性能的验证和测试精度,而训练精度非常高
Validation and Test accuracy at random performance, whereas Train accuracy very high
我正在尝试在 TensorFlow2.1 中为 CIFAR10 使用 ResNet50 在 imagenet 上预训练的分类器 来自 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,而且模型似乎从未真正改进测试集。
到目前为止我做了什么:
- 检查单热标签在整个训练和测试过程中是否一致
- 尝试了不同的 FNN 配置
- 尝试了方法
fit_generator
而不是 fit
- 预处理图像,调整图像大小 input_shapes
并且总是遇到同样的问题。
如有任何提示,我们将不胜感激。
问题可能是由于使用 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.VGG16
、keras.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
我正在尝试在 TensorFlow2.1 中为 CIFAR10 使用 ResNet50 在 imagenet 上预训练的分类器 来自 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,而且模型似乎从未真正改进测试集。
到目前为止我做了什么:
- 检查单热标签在整个训练和测试过程中是否一致
- 尝试了不同的 FNN 配置
- 尝试了方法
fit_generator
而不是fit
- 预处理图像,调整图像大小 input_shapes
并且总是遇到同样的问题。
如有任何提示,我们将不胜感激。
问题可能是由于使用 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.VGG16
、keras.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