【问题标题】:Poor results on image classification with CNN and VGG16 transfer learning使用 CNN 和 VGG16 迁移学习进行图像分类的结果不佳
【发布时间】:2021-08-16 16:55:44
【问题描述】:

我使用 Keras 和 VGG16 迁移学习训练了一个 7 类图像分类器来预测手袋品牌。我每个类有 1000 个样本图像,并动态使用图像增强来增强数据集。令人惊讶的是,它返回的训练和验证准确性很差。此外,我在高原回调上设置了提前停止并减少了 LR,这些回调在 50 个 epoch 中的 40 个开始,让我获得了 14% 的训练和 10% 的验证准确率。这很奇怪,因为哑分类器的准确率会超过 14%。 这次我用 ResNet50 尝试了相同的集合,在 50 个 epoch 6 的训练和验证准确率分别为 17% 和 19%(提前停止回调开始)

我把我的代码放在这里给你们看看有没有我可能遗漏的地方。

image_shape = (224, 224)
batch_size = 128

train_datagen = ImageDataGenerator(rescale=1./255,
                                   brightness_range = (0.5,1.5),
                                   rotation_range=10, 
                                   width_shift_range=0.1,
                                   height_shift_range=0.1,
                                   shear_range=0.15, 
                                   zoom_range=0.1,
                                   channel_shift_range = 10, 
                                   horizontal_flip=True,
                                   validation_split= 0.2
                                   )
test_datagen = ImageDataGenerator(rescale=1./255,
                                  validation_split= 0.2)

train_generator = train_datagen.flow_from_directory(dst_dir,
                                                    target_size=image_shape,
                                                    batch_size=batch_size,
                                                    seed = 835,
                                                    subset= "training",
                                                    class_mode = "sparse"
                                                    )
val_generator = test_datagen.flow_from_directory(dst_dir,
                                                 target_size=image_shape,
                                                 batch_size=batch_size,
                                                 seed = 835,
                                                 subset="validation",
                                                 class_mode = "sparse"
                                                 )

# Define some callbacks
early_stopping = tf.keras.callbacks.EarlyStopping( monitor="val_loss", 
                                                   min_delta=0,
                                                   patience=5,
                                                   verbose=0,
                                                   mode="auto",
                                                   baseline=None,
                                                   restore_best_weights=False,
                                                   )
reduceLR = tf.keras.callbacks.ReduceLROnPlateau(monitor="val_loss",
                                                factor=0.1,
                                                patience=5,
                                                verbose=0,
                                                mode="auto",
                                                min_delta=0.0001,
                                                cooldown=0,
                                                min_lr=0,
                                                )

#Transfer learning with VGG16
vgg16_model = tf.keras.applications.VGG16(pooling='avg', 
                                          weights='imagenet', 
                                          include_top=False, 
                                          input_shape=image_shape +(3,)
                                          )
for layers in vgg16_model.layers:
            layers.trainable=False
last_output = vgg16_model.layers[-1].output
vgg_x = Flatten()(last_output)
vgg_x = Dense(128, activation = 'relu')(vgg_x)
vgg_x = Dense(7, activation = 'softmax')(vgg_x)
vgg16_final_model = tf.keras.Model(vgg16_model.input, vgg_x)
vgg16_final_model.compile(loss = tf.keras.losses.SparseCategoricalCrossentropy(), 
                          optimizer= 'adam', 
                          metrics=['acc'])
vgg16_final_model.summary()

number_of_epochs = 50
vgg16_history = vgg16_final_model.fit(train_generator, 
                                      epochs = number_of_epochs,
                                      validation_data = val_generator,
                                      callbacks=[early_stopping, reduceLR],
                                      verbose=1)

这是学习曲线:

【问题讨论】:

  • 看一下分类混淆矩阵;这可能对正在发生的事情提供一些见解。

标签: python keras deep-learning conv-neural-network image-classification


【解决方案1】:

在您的代码中,您已将所有层设置为不可训练:

for layers in vgg16_model.layers:
        layers.trainable=False

在这种情况下,网络将使用 ImageNet 中的权重,因为您已导入模型设置 weights = 'imagenet'。看起来密集层不足以收敛。要解决此问题,在上述循环中设置 layers_trainable=True 可能会很有用。

另一种方法是简单地预训练您的模型,即不导入权重并在您自己的数据集上进行训练。

增加 FC 层的数量可能有用,但我认为这是一种改进,而不是当前问题的核心。

利用这一点,我会给你一些提示:

  1. flow_from_directory 函数中的

    class_mode 参数。从“稀疏”设置为“分类”。正如您在文档中看到的“稀疏”将是一维整数标签,即 1、2、3、...、7。这种标签可能很难学习。请记住将损失函数更改为“categorical_crossentropy”并测试结果。

  2. 您需要先自行测试数据。增强对学习过程有益吗?你必须注意你正在做什么样的增强。它们中的任何一个会损害您的数据结构吗?

【讨论】:

  • 感谢您的 cmets。如果我将 layers_trainable 设置为 True,那么我必须在数百万个 VGG16 权重上训练我的模型,这将在我的本地机器上花费很长时间,而且我也会失去预训练的权重。我的计划是通过解冻 VGG16 的最后两层来微调我的模型,以从我的数据中学习。我检查了您对 class_mode 的建议以及该模型在没有增强的情况下如何工作
  • 是的,如果您的本地计算机的处理能力较低,那么微调可能会很好。如果这些提示对您有帮助,请告诉我。
猜你喜欢
  • 1970-01-01
  • 2018-05-11
  • 2017-09-14
  • 2020-10-10
  • 2022-08-03
  • 1970-01-01
  • 2023-03-30
  • 2019-10-29
  • 2020-04-18
相关资源
最近更新 更多