Keras:预测性能与准确性不匹配

数据挖掘 Python 喀拉斯 美国有线电视新闻网 图像分类
2021-09-20 14:40:04

我正在使用 Keras/CNN 来识别使用原位相机收集的浮游生物图像。在训练后对测试集进行混淆矩阵时,我发现预测的准确性很差。

我有大量文件并且一直在使用 flow_from_directory 和生成器,我怀疑预测的索引可能会发生一些事情(例如这篇文章),但据我所知,文件名/标签的索引是匹配。

我做了一个简单的例子,类似于我对mnist_png数据集所做的事情:

import numpy as np
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.layers.advanced_activations import LeakyReLU
from keras import backend as K
from keras.preprocessing.image import ImageDataGenerator

img_width, img_height = 28, 28

train_data_dir = 'S:/mnist_png/training'

num_epochs = 100
batch_size = 128
num_test_samples=10000

if K.image_data_format() == 'channels_first':
    input_shape = (3, img_width, img_height)
else:
    input_shape = (img_width, img_height, 3)

model = Sequential()

model.add(Conv2D(32, (3, 3), input_shape=input_shape))
model.add(Activation('relu'))

model.add(Conv2D(16, (3, 3)))
model.add(Activation('relu'))

model.add(MaxPooling2D(pool_size=(3, 3)))
model.add(Dropout(0.5))

model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))

model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))

model.add(MaxPooling2D(pool_size=(3, 3)))
model.add(Dropout(0.5))

model.add(Flatten())
model.add(Dense(512,activation='linear'))
model.add(LeakyReLU(alpha=.3))
model.add(Dropout(0.5))

model.add(Dense(512,activation='linear'))
model.add(LeakyReLU(alpha=.3))

model.add(Dense(10))
model.add(Activation('softmax'))


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

# augmentation for training
train_datagen = ImageDataGenerator(
    rescale=1. / 255,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    vertical_flip=True,
    rotation_range=90,
    validation_split=0.1)

train_generator = train_datagen.flow_from_directory(
    train_data_dir,
    target_size=(img_width, img_height),
    batch_size=batch_size,
    class_mode='categorical')

model.fit_generator(
    train_generator,
    steps_per_epoch=batch_size,
    epochs=num_epochs)

...在 100 个 epoch 之后,我损失了:0.7517 - acc:0.7482。

然后我评估测试集:

test_data_dir = 'S:/mnist_png/testing'

test_datagen = ImageDataGenerator(
    rescale=1. / 255)

test_generator = test_datagen.flow_from_directory(
    test_data_dir,
    target_size=(img_width, img_height),
    batch_size=batch_size,
    shuffle='False',
    class_mode='categorical')

#Evaluate model on test set
scores = model.evaluate_generator(test_generator,workers=12)

...分数是 0.6184 和 0.8168,所以在同一个球场。

但是当我查看预测时会变得很奇怪,例如:

test_generator.reset()# Necessary to force it to start from beginning
Y_pred = model.predict_generator(test_generator)
y_pred = np.argmax(Y_pred, axis=-1)
sum(y_pred==test_generator.classes)/10000

实际正确的预测比例(在最后一行计算)在 0.1 左右;当我查看混淆矩阵时,它到处都是,对角线有很多零。
我已验证 test_generator.classes 与 test_generator.filenames 中的目录匹配,并且 shuffle 已关闭。根据这篇文章调用 test_generator.reset() 应该强制它按顺序获取文件,但我想知道是否不是。

有没有人对为什么会发生这种情况或解决问题的进一步步骤有任何想法?

3个回答

shuffle=false为我设置evaluate_generatorpredict_generator解决了这个问题。

确实是索引,答案就在这里

我想你想要这样的东西:

image_generator = ImageDataGenerator().flow_from_directory('test_data_path', target_size=(224, 224), shuffle=False)
true_labels = image_generator.classes
pred_probs = model.predict(image_generator)
preds = pred_probs.argmax(axis=-1)
print (sum(preds[:,0] ==true_labels)/len(true_labels))