【问题标题】:How to perform prediction using predict_generator on unlabeled test data in Keras?如何在 Keras 中使用 predict_generator 对未标记的测试数据执行预测?
【发布时间】: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 文件夹中的图像文件进行预测?

【问题讨论】:

    标签: python tensorflow keras classification


    【解决方案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 请检查我已添加说明的编辑
    • 我能问一个关于这个的问题吗?我在这里问了完整的问题:stackoverflow.com/questions/71125533/…。但是我有一个名为 all_classes 的目录,它是一组来自两个类的图像,我想将其用作我的模型的测试集。当我按照上面@today 的回答时,它只返回一个 0 的 numpy 数组。有人可以解释我的问题(可能最容易链接到完整问题),我在这里看不到我做的任何不同的事情吗?
    猜你喜欢
    • 1970-01-01
    • 2017-10-23
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-06
    • 2020-10-30
    • 2019-01-04
    相关资源
    最近更新 更多