如何在 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.filenames
和testgen.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 在 Anaconda 中使用 Tensorflow 后端?
如何在具有使用@tf.keras.utils.register_keras_serializable 注册的自定义函数的 Tensorflow Serving 中提供模型?