Keras 用于二元分类预测的 fit_generator() 总是 50%

Posted

技术标签:

【中文标题】Keras 用于二元分类预测的 fit_generator() 总是 50%【英文标题】:Keras' fit_generator() for binary classification predictions always 50% 【发布时间】:2019-04-18 02:37:01 【问题描述】:

我已经建立了一个模型来训练对图像是否是某个视频游戏进行分类。我将pre-scaled 我的图像转换为250x250 像素,并将它们分成两个文件夹(两个二进制类),分别标记为01。这两个类的数量在~100 范围内,我总共有大约3500 个图像。

以下是训练过程、模型设置和一些预测的照片:https://imgur.com/a/CN1b6LV

train_datagen = ImageDataGenerator(
    rescale=1. / 255,
    shear_range=0,
    zoom_range=0,
    horizontal_flip=True,
    width_shift_range=0.1,
    height_shift_range=0.1,
    validation_split=0.2)
train_generator = train_datagen.flow_from_directory(
    'data\\',
    batch_size=batchsize,
    shuffle=True,
    target_size=(250, 250),
    subset="training",
    class_mode="binary")
val_generator = train_datagen.flow_from_directory(
    'data\\',
    batch_size=batchsize,
    shuffle=True,
    target_size=(250, 250),
    subset="validation",
    class_mode="binary")
pred_datagen = ImageDataGenerator(
    rescale=1. / 255,
    shear_range=0,
    zoom_range=0,
    horizontal_flip=False,
    width_shift_range=0.1,
    height_shift_range=0.1)
pred_generator = pred_datagen.flow_from_directory(
    'batch_pred\\',
    batch_size=30,
    shuffle=False,
    target_size=(250, 250))


model = Sequential()
model.add(Conv2D(input_shape=(250, 250, 3), filters=25, kernel_size=3, activation="relu", padding="same"))
model.add(Conv2D(filters=32, kernel_size=3, activation="relu", padding="same"))
model.add(Conv2D(filters=32, kernel_size=3, activation="relu", padding="same"))
model.add(MaxPooling2D(pool_size=2,  padding="same", strides=(2, 2)))
model.add(BatchNormalization())
model.add(Conv2D(filters=64, kernel_size=3, activation="relu", padding="same"))
model.add(Conv2D(filters=64, kernel_size=3, activation="relu", padding="same"))
model.add(Conv2D(filters=64, kernel_size=3, activation="relu", padding="same"))
model.add(MaxPooling2D(pool_size=2, padding="same", strides=(2, 2)))
model.add(BatchNormalization())
model.add(Conv2D(filters=128, kernel_size=3, activation="relu", padding="same"))
model.add(Conv2D(filters=128, kernel_size=3, activation="relu", padding="same"))
model.add(Conv2D(filters=128, kernel_size=3, activation="relu", padding="same"))
model.add(MaxPooling2D(pool_size=2, padding="same", strides=(2, 2)))
model.add(Conv2D(filters=256, kernel_size=3, activation="relu", padding="same"))
model.add(Conv2D(filters=256, kernel_size=3, activation="relu", padding="same"))
model.add(Conv2D(filters=256, kernel_size=3, activation="relu", padding="same"))
model.add(MaxPooling2D(pool_size=2, padding="same", strides=(2, 2)))
model.add(BatchNormalization())
dense = False
if dense:
    model.add(Flatten())
    model.add(Dense(250, activation="relu"))
    model.add(BatchNormalization())
    model.add(Dense(50, activation="relu"))
else:
    model.add(GlobalAveragePooling2D())
model.add(Dense(1, activation="softmax"))
model.compile(loss='binary_crossentropy',
              optimizer=Adam(0.0005), metrics=["acc"])
callbacks = [EarlyStopping(monitor='val_acc', patience=200, verbose=1),
             ModelCheckpoint(filepath="model_checkpoint.h5py",
                             monitor='val_acc', save_best_only=True, verbose=1)]
model.fit_generator(
      train_generator,
      steps_per_epoch=train_generator.samples // batchsize,
      validation_data=val_generator,
      validation_steps=val_generator.samples // batchsize,
      epochs=500,
      callbacks=callbacks)

model 按纪元迭代数据、找到正确数量的图像等而言,一切似乎都运行正确。然而,我的预测始终是50%,尽管验证准确度好、损失低、准确度高等等

我不确定自己做错了什么,如果有任何帮助,我们将不胜感激。

【问题讨论】:

如果以下答案之一解决了您的问题,请接受点击答案旁边的复选标记将其标记为“已回答” - 请参阅What should I do when someone answers my question? 【参考方案1】:

问题是您在一个单元的密集层上使用softmax。 Softmax 函数对其输入进行归一化,使其元素之和等于 1。因此,如果它有一个单元,那么输出将始终为 1。相反,对于二进制分类,您需要使用 sigmoid 函数作为最后一层的激活函数。

【讨论】:

我很欣赏这个建议,但我已经尝试过 sigmoid 而不是 softmax,我遇到了同样的问题!事实上,当我使用 softmax 时,我的损失/准确率在训练中非常差,使用 sigmoid 我的准确率/验证准确率达到 95%+,但每个预测仍然达到 50%。 @CharlesAnderson 在使用predict() 方法之前,您是否通过将测试图像除以 255.0 来重新缩放测试图像? @CharlesAnderson 好的,我看到你已经定义了一个 pred_generator,我认为你可以在 predict_generator() 中使用它来进行预测。现在告诉我们你如何解释预测的结果?你如何找到预测的类?【参考方案2】:

我认为您的问题是您使用 sigmoid 进行二进制分类,您的最终层激活函数应该是线性的。

【讨论】:

以上是关于Keras 用于二元分类预测的 fit_generator() 总是 50%的主要内容,如果未能解决你的问题,请参考以下文章

Keras 二元分类 - Sigmoid 激活函数

预测取决于 Keras 中的批量大小

二元分类 predict() 方法:sklearn vs keras

keras中二元分类的类不平衡

使用 Keras 进行多类图像分类的多重预测

LOSS 在非常简单的 KERAS 二元分类器中没有改变