过拟合图像分类

not*_*ary 3 python computer-vision deep-learning keras tensorflow

我正在研究具有 10 个类别(从 0 到 10 的数字)的手语数字数据集的图像分类问题。由于某种原因,我的模型高度过度拟合,尽管我尝试了简单的模型(如 1 个卷积层)、经典的 ResNet50 甚至最先进的 NASNetMobile。

图像是彩色的,大小为 100x100。我尝试调整学习率,但它没有多大帮助,尽管减少批量大小会导致 val 准确性的早期增加。

我对图像应用了增强,但也没有帮助:当 val 精度不能高于 0.6 时,我的训练精度可以达到 1.0。

我查看了数据,它似乎加载得很好。验证集中的类分布也是公平的。我总共有 2062 张图片。

当我将损失更改为binary_crossentropy它时,它似乎可以为训练准确度和 val 准确度提供更好的结果,但这似乎并不正确。

我不明白出了什么问题,你能帮我找出我错过了什么吗?谢谢你。

这是我的笔记本的链接:单击

thu*_*v89 7

这将是一个非常有趣的答案。在查看问题时,您需要注意很多事情。幸运的是,有一种方法论(可能很模糊,但仍然是一种方法论)。

TLDR:从数据而不是模型开始您的旅程。

分析数据

首先让我们看看你的数据?

在此处输入图片说明

你有 10 个班级。每个图像都是(100,100). 并且只有 2062 张图像。这是你的第一个问题。与标准图像分类问题相比,数据很少。因此,您需要确保您的数据易于学习,而不会牺牲数据的普遍性(即,它可以在验证/测试集上表现良好)。我们怎么做?

  • 了解您的数据
  • 规范化您的数据
  • 减少特征数量

理解数据是其他部分反复出现的主题。所以我不会有一个单独的部分。

规范化您的数据

这是第一个问题。您正在将数据重新缩放到 [0,1] 之间。但是您可以通过标准化您的数据(即(x - mean(x))/std(x))做得更好。这是你如何做到的。

def create_datagen():
    return tf.keras.preprocessing.image.ImageDataGenerator(
        samplewise_center=True,
        samplewise_std_normalization=True,
        horizontal_flip=False,
        rotation_range=30,
        shear_range=0.2,
        validation_split=VALIDATION_SPLIT)
Run Code Online (Sandbox Code Playgroud)

您可能会注意到的另一件事是我已经设置了horizontal_flip=False. 这让我回到第一点。您必须做出判断,以了解哪些增强技术可能有意义。

  • 亮度/剪切力 - 看起来不错
  • 裁剪/调整大小 - 看起来没问题
  • 水平/垂直翻转 - 这不是我一开始会尝试的。如果有人向您展示两个不同水平方向的手势,您可能无法理解某些手势。

减少特征数量

这是非常重要的。你没有那么多数据。并且您希望确保充分利用数据。数据的原始大小为(100,100)。您可以使用显着较小尺寸的图像(我已经尝试过(64,64)- 但您可能可以做得更小)。因此,请尽可能减小图像的大小

接下来,您是否看到 RGB 或灰度符号都没有关系。您仍然可以识别该标志。但与 RGB 相比,灰度减少了 66% 的样本量。因此,尽可能少使用颜色通道

这就是你如何做这些,

def create_flow(datagen, subset, directory, hflip=False):
    return datagen.flow_from_directory(
        directory=directory,
        target_size=(64, 64),
        color_mode='grayscale',
        batch_size=BATCH_SIZE,
        class_mode='categorical',
        subset=subset,
        shuffle=True
    )
Run Code Online (Sandbox Code Playgroud)

所以再次重申,在继续建立模型之前,您需要花时间理解数据。这是此问题的最小列表。也可以随意尝试其他东西。

创建模型

所以,这是我对模型所做的更改。

  • 添加padding='same'到所有卷积层。如果您默认情况下不这样做,则它具有padding=valid,这会导致自动降维。这意味着,你走得越深,你的输出就越小。你可以在模型中看到你有一个 size 的最终卷积输出(3,3)。这对于密集层来说可能太小而无法理解。所以要注意密集层得到了什么。
  • 减小内核大小 - 内核大小与参数数量直接相关。所以为了减少过度拟合你的小数据集的机会。尽可能使用较小的内核大小。
  • 从卷积层中删除了 dropout - 这是我作为预防措施所做的事情。就个人而言,我不知道 dropout 是否适用于卷积层以及 Dense 层。所以一开始我不想在我的模型中有未知的复杂性。
  • 移除了最后一个卷积层——减少模型中的参数以减少过拟合的变化。

关于优化器

完成这些更改后,您无需更改 的学习率AdamAdam无需任何调整即可正常工作。所以这是一个你可以留到以后担心的问题。

关于批量大小

您使用的批次大小为 8。这甚至不足以为批次中的每个类包含单个图像。尝试将其设置为更高的值。我把它设置为32. 每当您可以尝试增加批量大小时。可能不是非常大的值。但最多大约 128(对于这个问题应该没问题)。

model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Convolution2D(8, (5, 5), activation='relu', input_shape=(64, 64, 1), padding='same'))
model.add(tf.keras.layers.MaxPooling2D((2, 2)))
model.add(tf.keras.layers.BatchNormalization())

model.add(tf.keras.layers.Convolution2D(16, (3, 3), activation='relu', padding='same'))
model.add(tf.keras.layers.MaxPooling2D((2, 2)))
model.add(tf.keras.layers.BatchNormalization())

model.add(tf.keras.layers.Convolution2D(32, (3, 3), activation='relu', padding='same'))
model.add(tf.keras.layers.MaxPooling2D((2, 2)))
model.add(tf.keras.layers.BatchNormalization())

model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(128, activation='relu'))
model.add(tf.keras.layers.Dropout(0.5))
model.add(tf.keras.layers.Dense(10, activation='softmax'))
model.summary()
Run Code Online (Sandbox Code Playgroud)

最后结果

通过在开始制作模型之前进行一些预冥想,我取得了比您所获得的结果要好得多的结果。

你的结果

Epoch 1/10
233/233 [==============================] - 37s 159ms/step - loss: 2.6027 - categorical_accuracy: 0.2218 - val_loss: 2.7203 - val_categorical_accuracy: 0.1000
Epoch 2/10
233/233 [==============================] - 37s 159ms/step - loss: 1.8627 - categorical_accuracy: 0.3711 - val_loss: 2.8415 - val_categorical_accuracy: 0.1450
Epoch 3/10
233/233 [==============================] - 37s 159ms/step - loss: 1.5608 - categorical_accuracy: 0.4689 - val_loss: 2.7879 - val_categorical_accuracy: 0.1750
Epoch 4/10
233/233 [==============================] - 37s 158ms/step - loss: 1.3778 - categorical_accuracy: 0.5145 - val_loss: 2.9411 - val_categorical_accuracy: 0.1450
Epoch 5/10
233/233 [==============================] - 38s 161ms/step - loss: 1.1507 - categorical_accuracy: 0.6090 - val_loss: 2.5648 - val_categorical_accuracy: 0.1650
Epoch 6/10
233/233 [==============================] - 38s 163ms/step - loss: 1.1377 - categorical_accuracy: 0.6042 - val_loss: 2.5416 - val_categorical_accuracy: 0.1850
Epoch 7/10
233/233 [==============================] - 37s 160ms/step - loss: 1.0224 - categorical_accuracy: 0.6472 - val_loss: 2.3338 - val_categorical_accuracy: 0.2450
Epoch 8/10
233/233 [==============================] - 37s 158ms/step - loss: 0.9198 - categorical_accuracy: 0.6788 - val_loss: 2.2660 - val_categorical_accuracy: 0.2450
Epoch 9/10
233/233 [==============================] - 37s 160ms/step - loss: 0.8494 - categorical_accuracy: 0.7111 - val_loss: 2.4924 - val_categorical_accuracy: 0.2150
Epoch 10/10
233/233 [==============================] - 37s 161ms/step - loss: 0.7699 - categorical_accuracy: 0.7417 - val_loss: 1.9339 - val_categorical_accuracy: 0.3450
Run Code Online (Sandbox Code Playgroud)

我的结果

Epoch 1/10
59/59 [==============================] - 14s 240ms/step - loss: 1.8182 - categorical_accuracy: 0.3625 - val_loss: 2.1800 - val_categorical_accuracy: 0.1600
Epoch 2/10
59/59 [==============================] - 13s 228ms/step - loss: 1.1982 - categorical_accuracy: 0.5843 - val_loss: 2.2777 - val_categorical_accuracy: 0.1350
Epoch 3/10
59/59 [==============================] - 13s 228ms/step - loss: 0.9460 - categorical_accuracy: 0.6676 - val_loss: 2.5666 - val_categorical_accuracy: 0.1400
Epoch 4/10
59/59 [==============================] - 13s 226ms/step - loss: 0.7066 - categorical_accuracy: 0.7465 - val_loss: 2.3700 - val_categorical_accuracy: 0.2500
Epoch 5/10
59/59 [==============================] - 13s 227ms/step - loss: 0.5875 - categorical_accuracy: 0.8008 - val_loss: 2.0166 - val_categorical_accuracy: 0.3150
Epoch 6/10
59/59 [==============================] - 13s 228ms/step - loss: 0.4681 - categorical_accuracy: 0.8416 - val_loss: 1.4043 - val_categorical_accuracy: 0.4400
Epoch 7/10
59/59 [==============================] - 13s 228ms/step - loss: 0.4367 - categorical_accuracy: 0.8518 - val_loss: 1.7028 - val_categorical_accuracy: 0.4300
Epoch 8/10
59/59 [==============================] - 13s 226ms/step - loss: 0.3823 - categorical_accuracy: 0.8711 - val_loss: 1.3747 - val_categorical_accuracy: 0.5600
Epoch 9/10
59/59 [==============================] - 13s 227ms/step - loss: 0.3802 - categorical_accuracy: 0.8663 - val_loss: 1.0967 - val_categorical_accuracy: 0.6000
Epoch 10/10
59/59 [==============================] - 13s 227ms/step - loss: 0.3585 - categorical_accuracy: 0.8818 - val_loss: 1.0768 - val_categorical_accuracy: 0.5950
Run Code Online (Sandbox Code Playgroud)

注意:这是我付出的最小努力。您可以通过增加数据、优化模型结构、选择正确的批量大小等来进一步提高准确性。