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
像素,并将它们分成两个文件夹(两个二进制类),分别标记为0
和1
。这两个类的数量在~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%的主要内容,如果未能解决你的问题,请参考以下文章