图像分类中的过度拟合问题

3
我正在处理手语数字数据集的图像分类问题,该数据集包含10个类别(数字0到10)。我的模型因某种原因出现了严重过拟合,即使我尝试了简单模型(如1个卷积层)、经典的ResNet50和最先进的NASNetMobile。
这些图像是彩色的,大小为100x100。我尝试调整学习率,但效果不大,降低批量大小会导致val准确度早期增加。
我对图像进行了增强,但结果也不理想:训练准确度可以达到1.0,而验证准确度无法超过0.6。
我查看了数据,似乎加载正常。验证集中类别的分布也很公平。总共有2062张图片。
当我将损失函数更改为binary_crossentropy时,似乎对训练准确度和验证准确度都有更好的效果,但这似乎不正确。
我不明白出了什么问题,请问您能帮我找出我错过的东西吗? 谢谢。
这是我笔记本的链接:点击
1个回答

9
这将是一个非常有趣的答案。在解决问题时,您需要注意很多事情。幸运的是,有一种方法论(可能含糊不清,但仍然是一种方法论)。 TLDR:从数据开始你的旅程,而不是模型。

分析数据

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

enter image description here

你有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)

你可能会注意到我设置了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
    )

再次强调,你需要在开始建模前花时间理解数据。这是解决问题的最基本要求清单。也可以尝试其他方法。

创建模型

下面是我对模型所做的更改。

  • 在所有卷积层中添加了padding='same'。如果你不这样做,默认情况下它会使用padding=valid,这会导致自动降维。这意味着,你越深入,输出就越小。而且你可以看到在你的模型中,你有一个最终的卷积输出大小为(3,3)。这对于密集层来说可能太小了。所以要注意密集层得到的内容。
  • 减小了内核大小——内核大小直接影响参数数量。因此,为了减少对您的小数据集过度拟合的可能性,尽可能选择较小的内核大小。
  • 从卷积层中删除了dropout——这是我作为一种预防措施所做的。就个人而言,我不知道dropout是否与密集层一样适用于卷积层。所以我不想在开始时在我的模型中增加未知的复杂性。
  • 删除了最后一个卷积层——减少模型中的参数以减少过度拟合的可能性。

关于优化器

当您完成这些更改后,您无需更改Adam的学习率。 Adam在没有任何调整的情况下表现得非常好。因此,您可以将这个问题留到以后再处理。

关于批量大小

您使用的批量大小为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()

最终结果

在开始建模之前进行一些预先的思考,我获得了比您更显着的结果。

您的结果

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

我的结果

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

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

非常感谢您的建议!我已经尝试了您的建议,并且进行了更多的训练(20个周期),但模型似乎仍然存在过拟合问题。在验证集上,最高准确率只有78%,而在训练集上则为94%。我也进行了一些微调,但效果并不明显。 - notEmissary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接