用于分类的 CNN 给出极端结果概率

数据挖掘 Python 神经网络 喀拉斯 西阿诺 卷积
2022-01-28 16:19:34

我在使用带有 Theano 后端的 Keras 时遇到了我的 CNN 问题。基本上,我需要将 340x340 灰度图像分为 6 个类别。问题是我的 CNN 给出了太“硬”的概率,例如它很少给出带有一些不确定性的预测,并且总是试图为一个类争取 90%+。问题是,对于我的课程作业,对于完全未命中分类所使用的惩罚非常苛刻,并且更倾向于不确定性。(所以有一个像 [0.6, 0.3, 0.2, ...] 的预测比有 [0.9,0.03,0.02,..] 好得多。

我不确定为什么会这样。我的数据集包含 2400 张来自不同闭路电视的图像,任务是识别可能的对象。只有 800 个样本实际上来自数据,其他 1600 个样本是通过数据增强生成的。请注意,因此极有可能某些图片相同或极其相似(例如,同一场景,一秒钟后)

model = Sequential()
#1 
# Few filter to take big stuff out
# Also, first layer is not conv so that I can reuse that layer separately
model.add(Dropout(0.1, input_shape=(1,340,340)))
model.add(Convolution2D(64, 4, 4, border_mode='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2), dim_ordering="th"))   

#2
model.add(Dropout(0.1))
model.add(Convolution2D(128, 4, 4, border_mode='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2), dim_ordering="th"))   

#3
model.add(Dropout(0.1))
model.add(Convolution2D(256, 4, 4, border_mode='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2), dim_ordering="th"))   

#4
model.add(Flatten())
model.add(Dense(1024))
model.add(Activation('relu'))
#5
model.add(Dense(512))
model.add(Activation('relu'))
#6
model.add(Dense(6))
model.add(Activation('softmax'))

opt = SGD(lr=0.001)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])

print "Training.."


filepath = "log/weights-improvement-{epoch:02d}---{val_acc:.2f}.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor='val_acc', verbose=1, save_best_only=True, mode='max')
callbacks_list = [checkpoint] 
model.fit(X_t, y_t, validation_split=0.1, nb_epoch=500, batch_size=32, callbacks=callbacks_list)

你建议我如何解决这个问题?先感谢您!

1个回答

这里涉及几个不同的因素。如果不深入参与,很难说这可能是最重要的。我会按照我认为值得一看的顺序排列它们。

  • 您的数据是来自闭路电视的图像,因此您可能拥有来自每台摄像机的多个图像。从您的结果(合理的培训和 CV 分数,但糟糕的培训)来看,您似乎过度拟合。但是您的简历方法没有发现这一点。所以我认为测试集很可能来自与训练集不同的相机集。因此,为了正确测量 CV,您必须通过相机拆分 train/cv - 您不能只使用 0.1 拆分,因为随机拆分将包括与训练数据相关的图像,并且会给您过高的估计值,让您在不注意的情况下过拟合。

    • 在我看来,这可能只是您的数据扩充给您带来了问题。如果您扩充然后随机拆分为训练/CV,那么您的 CV 集将包含与训练集非常相似的图像,并且得分太高。您可以更轻松地检查和修复此问题,而不是通过相机拆分,因此请尝试一下。
  • 800 张原始图像的使用量并不大。你需要为此做点什么。这里有一些想法:

    • 缩小图像。您可能不需要 340x340。根据目标对象,也许只有 78x78 就可以了。您可以很容易地评估这一点 - 缩小并检查您是否仍然可以通过肉眼轻松区分这些类别。

    • 您没有足够的数据在较低层获得最佳质量的过滤器,这将限制 CNN 的功能。您可以从预先训练的图像模型引导。以公开可用的预训练 CNN 为例,例如 VGG-19,使用其在卷积层中的权重作为起点,将不同的分类器层放在顶部,并从这里开始微调您的分类器。这也可能会改变理想的图像比例——你想要适合预先训练的 CNN 的东西。

    • 增强数据,你已经开始了。你可以走得更远。从训练示例中获取随机补丁,可能水平翻转(如果这保持对象类)。但是,不要扩充用于交叉验证的数据,除非您用于测试的模型还包括扩充 - 例如,如果它需要测试图像的 8 个随机扩充变体并返回预测的平均值,那么您可以对交叉验证进行类似的操作.

  • 在这么多数据上运行一次 0.1 的训练/CV 拆分不会给您对模型的准确评估。您需要运行 k 折交叉验证。这很烦人,因为 NN 需要很长时间来训练,但是如果你想确信自己确实找到了一些好的参数,你就需要这样做。如果可以的话,记得用相机分割。

  • 评分似乎与分类交叉熵密切相关,因此您拥有正确的损失函数。您应该使用交叉验证进行优化,以找到损失最低的模型,而不是最佳准确度。