训练准确率约为 97%,但验证准确率停留在约 40%

数据挖掘 神经网络 深度学习 喀拉斯 张量流 图像分类
2022-02-10 15:08:24

我正在尝试使用 Conv2D 网络将图像分类为 27 个类。训练准确度按预期通过 epochs 上升,但 val_accuracy 和 val_loss 值波动剧烈且不够好。

我正在使用单独的数据集进行训练和验证。这些图像的大小为 256 x 256,并且是二进制阈值图像。

训练和验证图像的样本

训练集中有 22127 张图像(每类约 800 张),验证集中有 11346 张图像(每类约 400 张),所以我相信没有类不平衡。

这是我的架构:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 126, 126, 32)      320       
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 63, 63, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 61, 61, 32)        9248      
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 30, 30, 32)        0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 28800)             0         
_________________________________________________________________
dense_1 (Dense)              (None, 128)               3686528   
_________________________________________________________________
dropout_1 (Dropout)          (None, 128)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 96)                12384     
_________________________________________________________________
dropout_2 (Dropout)          (None, 96)                0         
_________________________________________________________________
dense_3 (Dense)              (None, 64)                6208      
_________________________________________________________________
dense_4 (Dense)              (None, 27)                1755      
=================================================================



Total params: 3,716,443
Trainable params: 3,716,443
Non-trainable params: 0

Found 22127 images belonging to 27 classes.
Found 11346 images belonging to 27 classes.

这是我用来制作这个模型的代码:

classifier = Sequential()

classifier.add(Convolution2D(32, (3, 3), input_shape=(sz, sz, 1), activation='relu'))
classifier.add(MaxPooling2D(pool_size=(2, 2)))
classifier.add(Convolution2D(32, (3, 3), activation='relu'))
classifier.add(MaxPooling2D(pool_size=(2, 2)))

classifier.add(Flatten())

classifier.add(Dense(units=128,
                     activation='relu'))
classifier.add(Dropout(0.40))


classifier.add(Dense(units=96,
                     activation='relu'))
classifier.add(Dropout(0.40))


classifier.add(Dense(units=64,
                     activation='relu'))

classifier.add(Dense(units=27, activation='softmax'))

使用的优化器是 adam,我使用的损失函数是 categorical_crossentropy。

from keras import optimizers

opt = optimizers.Adam(learning_rate = 0.001)

classifier.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accuracy'])

classifier.summary()

这是将数据从目录流向模型的代码

train_datagen = ImageDataGenerator(
        rescale=1./255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True)

test_datagen = ImageDataGenerator(rescale=1./255)

training_set = train_datagen.flow_from_directory('Dataset2/Training Data',
                                                 target_size=(sz, sz),
                                                 batch_size=10,
                                                 color_mode='grayscale',
                                                 class_mode='categorical',
                                                 shuffle = True)

test_set = test_datagen.flow_from_directory('Dataset2/Test Data',
                                            target_size=(sz , sz),
                                            batch_size=10,
                                            color_mode='grayscale',
                                            class_mode='categorical',
                                            #shuffle = True
                                            )

classifier_obj = classifier.fit_generator(
        training_set,
        #steps_per_epoch=22127,
        epochs=10,
        validation_data=test_set,
        #validation_steps=11346
    verbose = 1)

此代码产生的输出是:

Epoch 1/10
2213/2213 [==============================] - 302s 136ms/step - loss: 0.0130 - accuracy: 0.7108 - val_loss: 0.0604 - val_accuracy: 0.3293
Epoch 2/10
2213/2213 [==============================] - 312s 141ms/step - loss: 0.0035 - accuracy: 0.9371 - val_loss: 0.0279 - val_accuracy: 0.4069
Epoch 3/10
2213/2213 [==============================] - 305s 138ms/step - loss: 0.0024 - accuracy: 0.9558 - val_loss: 0.0260 - val_accuracy: 0.4266
Epoch 4/10
2213/2213 [==============================] - 336s 152ms/step - loss: 0.0018 - accuracy: 0.9680 - val_loss: 0.0452 - val_accuracy: 0.4323
Epoch 5/10
2213/2213 [==============================] - 310s 140ms/step - loss: 0.0015 - accuracy: 0.9731 - val_loss: 0.0339 - val_accuracy: 0.3659
Epoch 6/10
2213/2213 [==============================] - 317s 143ms/step - loss: 0.0014 - accuracy: 0.9746 - val_loss: 0.0415 - val_accuracy: 0.4496
Epoch 7/10
2213/2213 [==============================] - 297s 134ms/step - loss: 0.0012 - accuracy: 0.9777 - val_loss: 0.0379 - val_accuracy: 0.4512
Epoch 8/10
2213/2213 [==============================] - 285s 129ms/step - loss: 0.0012 - accuracy: 0.9782 - val_loss: 0.0157 - val_accuracy: 0.4603
Epoch 9/10
2213/2213 [==============================] - 274s 124ms/step - loss: 0.0012 - accuracy: 0.9795 - val_loss: 0.0289 - val_accuracy: 0.4430
Epoch 10/10
2213/2213 [==============================] - 274s 124ms/step - loss: 9.1970e-04 - accuracy: 0.9837 - val_loss: 0.0459 - val_accuracy: 0.4800
Model Saved
Weights saved

看到有希望的结果,我增加了 epoch 的数量以期获得更高的 val_Accuracy,但结果是 val_accuracy 低于前一个。

我更改了一些参数,并在一夜之间运行了 100 个 epoch 的代码。这是输出:

超过 100 个 epoch 的精度

损失超过 100 个 epoch

我在其他答案中发现并尝试但失败的一些事情:

  1. 使用 SGD 优化器
  2. 使用正则化器
  3. 玩弄密集层中的单位数量。

根据其他答案,我认为要么我的模型过度拟合,要么数据不好。请帮助我,因为我完全一无所知。

2个回答

主要问题之一是每个类别的记录数量。绝对使用数据增强总是有助于获得良好的准确性,但更好的方法是使用带有数据增强的迁移学习技术。

在您的方法中,模型开始过度拟合,因为它开始具有良好的训练准确度但验证准确度较差。让我们看看迁移学习的实现。要了解有关迁移学习的更多信息,请查看此链接文章链接

import tensorflow.keras as keras

model = keras.models.Sequential()

model.add(keras.applications.ResNet50(include_top=False, weights='imagenet', input_shape=(128, 128, 3)))

model.add(keras.layers.Flatten())

model.add(keras.layers.Dense(27, activation='softmax')) 

model.layers[0].trainable=False

model.compile(keras.optimizers.Adam(0.001), loss='categorical_crossentropy', metrics=['accuracy'])

model.summary()

model_obj = model.fit_generator(training_set, epochs=1, validation_data=test_set, verbose = 1)

不要忘记将数据增强生成器作为输入数据传递给 fit_generator。如果您在验证/测试中使用数据扩充,则没有效果。您可以使用交叉验证技术或基于 cnn 的集成技术来获得更好的结果。

这是过拟合,它表明每个类中的图像与其他类中的图像非常相似。

由于您跨类别的图像看起来非常相似,因此每个类别 800 个实际上并不是需要训练的大量数据。您的模型很可能正在努力根据它所能学到的东西将开发数据区分为正确的类。您的混淆矩阵可能会证实这一点。

在尝试任何正则化技术之前,我会尝试通过增强来为每个类获取更多数据。为了测试这一点,您可以先尝试在更少的类(例如 2 个)上运行模型,看看它是否能够更好地区分这两个类,如果不能,那么可能毕竟需要一些正则化。

您还可以构建更多模型来区分每个模型的更少类,关键是将最容易混淆的类保留在单独的模型中。