如何在 Keras 中使用 predict_generator 对未标记的测试数据执行预测?

Posted

技术标签:

【中文标题】如何在 Keras 中使用 predict_generator 对未标记的测试数据执行预测?【英文标题】:How to perform prediction using predict_generator on unlabeled test data in Keras? 【发布时间】:2019-12-22 07:24:00 【问题描述】:

我正在尝试构建图像分类模型。这是一个 4 类图像分类。这是我构建图像生成器和运行训练的代码:

train_datagen = ImageDataGenerator(rescale=1./255.,
                               rotation_range=30,
                               horizontal_flip=True,
                               validation_split=0.1)


train_generator = image_gen.flow_from_directory(train_dir, target_size=(299, 299), 
                                                class_mode='categorical', batch_size=20,
                                                subset='training')

validation_generator = image_gen.flow_from_directory(train_dir, target_size=(299, 299), 
                                                class_mode='categorical', batch_size=20,
                                                subset='validation')

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

model.fit_generator(train_generator, steps_per_epoch=int(440/20), epochs=20, 
                              validation_data=validation_generator, 
                              validation_steps=int(42/20))

我能够完美地完成训练和验证工作,因为 train 目录中的图像存储在每个班级的单独文件夹中。但是,如下所示,test 目录有 100 个图像,其中没有文件夹。它也没有任何标签,只包含图像文件。

如何使用 Keras 对 test 文件夹中的图像文件进行预测?

【问题讨论】:

【参考方案1】:

如果您只对执行预测感兴趣,您可以像这样通过简单的 hack 加载图像:

test_datagen = ImageDataGenerator(rescale=1/255.)

test_generator = test_datagen('PATH_TO_DATASET_DIR/Dataset',
                              # only read images from `test` directory
                              classes=['test'],
                              # don't generate labels
                              class_mode=None,
                              # don't shuffle
                              shuffle=False,
                              # use same size as in training
                              target_size=(299, 299))

preds = model.predict_generator(test_generator)

您可以访问test_generator.filenames 以获取相应文件名的列表,以便您可以将它们映射到相应的预测。


更新(根据 cmets 部分的要求):如果要将预测的类映射到文件名,首先必须找到预测的类。如果您的模型是分类模型,那么它可能有一个 softmax 层作为分类器。所以preds 中的值是概率。使用np.argmax方法查找概率最高的索引:

preds_cls_idx = preds.argmax(axis=-1)

因此,这为您提供了预测类别的索引。现在我们需要将索引映射到它们的字符串标签(即“汽车”、“自行车”等),这些标签由class_indices 属性中的训练生成器提供:

import numpy as np

idx_to_cls = v: k for k, v in train_generator.class_indices.items()
preds_cls = np.vectorize(idx_to_cls.get)(preds_cls_idx)
filenames_to_cls = list(zip(test_generator.filenames, preds_cls))

【讨论】:

我应该使用"PATH_TO_DATASET_DIR/Dataset/test"(或)""PATH_TO_DATASET_DIR/Dataset"吗?我问这个是因为测试文件在 test 文件夹中。 @user_12 不,您应该使用PATH_TO_DATASET_DIR/Dataset,然后使用classes=['test'] 限制它。这实际上就是我所指的 hack。 好的。非常感谢。我会测试它并返回。如果可能的话,您能否提供一些示例代码,说明如何使用预测名称(即汽车或自行车等)并将其映射到它们的文件名? @user_12 哎呀!是的,我错过了。我刚刚编辑了我的答案并添加了它。 @user_12 不,它的价值并不重要(除了效率,即使用所有可用资源)。默认批量大小为 32。【参考方案2】:

您的文件夹结构类似于testfolder/folderofallclassfiles

你可以使用

test_generator = test_datagen.flow_from_directory(
    directory=pred_dir,
    class_mode=None,
    shuffle=False
)

在预测之前我也会使用重置来避免不需要的输出

编辑:

出于您的目的,您需要知道哪个图像与哪个预测相关联。问题在于,每次我们使用生成器时,数据生成器都会从数据集中的不同位置开始,因此每次都会给我们不同的输出。因此,为了在每次调用 predict_generator() 时在数据集的开头重新开始,您需要将迭代和批次的数量与数据集大小完全匹配。 遇到这种情况有多种方式

a) 您可以使用生成器的batch_index 查看内部批处理计数器 b) 在每次调用predict_generator()之前创建一个新的数据生成器 c) 有一种更好更简单的方法,就是在生成器上调用reset(),如果你在flow_from_directory 中设置了shuffle=False,那么它应该从数据集的开头重新开始,并给出完全相同的输出每次,所以现在testgen.filenamestestgen.classes 的顺序匹配

test_generator.reset()

预测

prediction = model.predict_generator(test_generator,verbose=1,steps=numberofimages/batch_size)

用预测映射文件名

predict_generator 以概率形式给出输出,所以首先我们需要将它们转换为类号,例如 0,1..

predicted_class = np.argmax(prediction,axis=1)

下一步是将这些班级编号转换为实际班级名称

l = dict((v,k) for k,v in training_set.class_indices.items())
prednames = [l[k] for k in predicted_classes]

获取文件名

filenames = test_generator.filenames

最后创建 df

finaldf = pd.DataFrame('Filename': filenames,'Prediction': prednames)

【讨论】:

为什么我们必须使用test_generator.reset()?我没有明白你所说的不需要的输出是什么意思?我们只会得到正确的概率, @user_12 请检查我已添加说明的编辑 我能问一个关于这个的问题吗?我在这里问了完整的问题:***.com/questions/71125533/…。但是我有一个名为 all_classes 的目录,它是一组来自两个类的图像,我想将其用作我的模型的测试集。当我按照上面@today 的回答时,它只返回一个 0 的 numpy 数组。有人可以解释我的问题(可能最容易链接到完整问题),我在这里看不到我做的任何不同的事情吗?

以上是关于如何在 Keras 中使用 predict_generator 对未标记的测试数据执行预测?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 keras 分类器中使用交叉验证

如何在 Keras 中使用张量板显示输入张量

如何让 Keras 在 Anaconda 中使用 Tensorflow 后端?

如何在具有使用@tf.keras.utils.register_keras_serializable 注册的自定义函数的 Tensorflow Serving 中提供模型?

Keras:如何在损失函数中使用层的权重?

如何在 Keras 中使用预训练的 CNN 实现连体网络?