训练期间接近 100% 的准确率,但在图像分类器的测试/验证期间 <50%

Posted

技术标签:

【中文标题】训练期间接近 100% 的准确率,但在图像分类器的测试/验证期间 <50%【英文标题】:Near 100% accuracy during training but <50% during testing/validation on image classifier 【发布时间】:2019-12-10 05:20:15 【问题描述】:

过去几天我一直在尝试训练我的模型,但每次无论我尝试什么,都会遇到同样的问题。我的准确率开始很低,在第一个 epoch 内达到 90% 以上,但每个 epoch 结束时的验证结果在 20-50% 之间,并且测试模型预测对于某些类是准确的,但对大多数类来说完全错误。我的数据集有 20000 张图像,每类 2000 张,以及 100 张测试图像(如果需要可以获取更多)。我将非常感谢你们提供的任何意见,因为我对整个机器学习还很陌生,而且我并不完全理解其中的所有内容。

我查看了几篇描述类似问题及其修复的在线帖子和文章,无论是将激活定义为它们自己的层而不是参数,添加批量归一化层并改变它们的动量,尝试几种不同的优化器和学习率,不同大小的数据集,使用自定义初始化器,甚至完全改变我的模型的结构。没有任何效果。

这是网络的主要部分:

model = Sequential()
initializer = keras.initializers.he_normal(seed=None)

model.add(Conv2D(64, (3, 3), padding='same', use_bias=False, kernel_initializer=initializer, input_shape=x_train.shape[1:]))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3), padding='same', use_bias=False, kernel_initializer=initializer))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(128, (3, 3), padding='same', use_bias=False, kernel_initializer=initializer))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(128, (3, 3), padding='same', use_bias=False, kernel_initializer=initializer))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(256, (3, 3), padding='same', use_bias=False, kernel_initializer=initializer))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(256, (3, 3), padding='same', use_bias=False, kernel_initializer=initializer))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(2048, use_bias=False, kernel_initializer=initializer))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Dropout(0.4))
model.add(Dense(num_classes, use_bias=False))
model.add(BatchNormalization())
model.add(Activation('softmax'))

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

# train the model
if not testing_mode:
    model.fit(x_train, y_train, epochs=epochs, batch_size=batch_size, shuffle=True, validation_data=(x_test, y_test))

scores = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', scores[0])
print('Test accuracy:', scores[1])

这是一个 epoch 的最后几批及其最后的验证:

19776/20000 [============================>.] - ETA: 25s - loss: 0.4859 - acc: 0.9707
19840/20000 [============================>.] - ETA: 18s - loss: 0.4855 - acc: 0.9708
19904/20000 [============================>.] - ETA: 11s - loss: 0.4851 - acc: 0.9709
19968/20000 [============================>.] - ETA: 3s - loss: 0.4848 - acc: 0.9710 
20000/20000 [==============================] - 2323s 116ms/step - loss: 0.4848 - acc: 0.9710 - val_loss: 1.9185 - val_acc: 0.5000

编辑:我被告知要添加有关我的数据集的更多信息。我正在使用 10 类不同手势的 this 数据集进行训练。每张图像都被预处理为 128x128 和灰度,我的 100 张图像测试集是从训练集中的每个类中获取的 10 张图像。我知道最好获取与训练集分开的数据进行测试,但我不确定从训练集中删除图像是否是个好主意。这也是我觉得这个问题很奇怪的原因之一,因为如果模型过度拟合到训练数据上,那么为什么面对它已经看到的数据时准确率会这么低呢?如果您需要更多信息,请告诉我。

【问题讨论】:

你的模型过拟合了!您需要描述您正在训练的内容、正在测试的内容、分类值、类值的分布以及更多信息,以获得更有意义的 cmets。 【参考方案1】:

您的模型似乎过度拟合,这意味着它正在非常接近地适应 [学习] 训练集。

如果您的训练集未包含所有案例类型,则可能会导致此问题,请尝试再次打乱您的数据。

【讨论】:

你知道有什么方法可以在不弄乱标签的情况下打乱数据吗?【参考方案2】:

您的模型很可能过度拟合。这意味着您的模型的预测准确性很差,并且无法泛化到训练集之外。发生这种情况的原因有多种,因此在我们获得有关您的模型的更多信息之前,我们无法提出建议。

编辑 1

我的理解是,模型不应该在训练集中找到测试集的观察结果。我对使用的语法不是很熟悉,但我认为您可以使用.fit 函数中的validation_split 参数来分隔集合。建议的拆分是大约 85% 的训练 / 15% 的测试

来源:https://keras.io/models/model/

【讨论】:

@mattsap 的评论是一个好的开始。如果我正确理解您的编辑#1,您的测试集是否包含在您的训练集中?我没有关注这个 测试图像存储在单独的位置,但它们都可以在训练集中的某个位置找到。所以,是的。 据我了解,这不好。测试集数据不应包含在您的训练集中。 那么,我是否应该创建一个新的测试集,但删除我从训练集中获取的图像? 我本来打算这样做,但是似乎参数在洗牌之前从训练集的末尾进行拆分,并且我的训练集首先按顺序加载。它依赖于洗牌。如果您知道我可以事先洗牌的任何方式,我将使用验证拆分。【参考方案3】:

在训练卷积神经网络 (CNN) 时,为了摆脱过度拟合问题,您可以应用以下方法 -

    您可以使用 Dropout 来玩弄它们的概率值,作为 CNN 正则化器 使用数据增强等技术添加更多数据 使用迁移学习(预训练模型)

【讨论】:

我应该使用更高还是更低的 dropout 值? 隐藏层中 dropout 的良好值介于 0.5 和 0.8 之间。但我可以说,您可以在 0.3 到 0.8 之间的值范围内进行调整,然后检查哪个会产生更好的结果。

以上是关于训练期间接近 100% 的准确率,但在图像分类器的测试/验证期间 <50%的主要内容,如果未能解决你的问题,请参考以下文章

为啥打乱训练数据会影响我的随机森林分类器的准确性?

决策树分类器的准确性

使用评估生成器的准确度为 0%,但在使用相同数据进行训练期间的准确度为 75%——这是怎么回事?

sklearn:朴素贝叶斯分类器的准确性低

文本二进制分类训练期间的波动损失

提高knn分类器的准确性