【问题标题】:Custom keras generator __get_item__() is called more than __len__()自定义 keras 生成器 __get_item__() 被调用多于 __len__()
【发布时间】:2019-07-25 17:06:46
【问题描述】:

我已经构建了一个自定义的 keras generator.function。 它产生一个 img 和相关的 gt。 它适用于带有 predict_generator() 函数的训练阶段。

为了评估我的模型,我在包含 592 张图像的测试集上使用它。我用 predict_generator() 函数调用它。 所以我得到了正确的预测数量(592)。每次调用 get_item() 函数时,我都会将 GT 添加到 self.gt 列表中。

然后,在运行 predict_generator() 之后,我将预测与存储的 GT 进行比较。

我的问题: 每次调用生成器时,我都想将地面实况数组存储在列表中。但最后,我有比 592 个预测更多的 GT_arrays。 所以我无法建立我的混淆矩阵......

这里是生成器的代码:

class DataGenerator(Sequence):
    def __init__(self, data_folders_txt, gen_data_type, batchsize, shuffle=True, classes=None, selected_class=None):

        '''
        - data_fodlers_txt : txt_file containing all the paths to different folders of data
        - gen_type : string : can be either "train", "val" or "test" (correspond to a specific folder)
        - shuffle : Shuffle the dataset at each epoch
        - classes : dict of classes with associated nb (class nb must match the class position on the class axis of the ground truth one-hot-encoded array)
        - selected_class : name of the selected class (128x128x1) in the 128x128x3 ground truth one-hot-encoded array
        '''

        self.gt = []
        self.shuffle = shuffle
        self.gen_data_type = gen_data_type
        self.batchsize = batchsize
        self.data_folders = open(data_folders_txt, "r").readlines()
        self.list_IDs = self.tiles_list_creation(self.data_folders)
        self.samples = len(self.list_IDs)
        self.classes = classes
        self.selected_class = selected_class
        self.index = 0
        self.on_epoch_end()

    def tiles_list_creation(self, list_folders):
        list_IDs = []
        for folder in list_folders:
            samples = glob.glob(folder.rstrip() + self.gen_data_type + '3/tile/*')
            list_IDs += samples
        random.shuffle(list_IDs)
        return list_IDs

    def __len__(self):
        if len(self.list_IDs) % self.batchsize == 0:
            return len(self.list_IDs)//self.batchsize
        else:
            return len(self.list_IDs) // self.batchsize + 1

    def __getitem__(self, index):
        self.index = index
        X = []
        y = []
        # min(...,...) is for taking all the data without being out of range
        for i in range(index*self.batchsize, min(self.samples, (index+1)*self.batchsize)):

            tile = np.load(self.list_IDs[i])

            #If specific class is specified, just take the right channel of the GT_array corresponding to the wanted class 
            if self.classes:
                gt = np.load(self.list_IDs[i].replace("tile", "gt"))[:, :, self.classes[self.selected_class]]
                gt = np.expand_dims(gt, axis=-1)
            else:
                gt = np.load(self.list_IDs[i].replace("tile", "gt"))

            #store ground truth to compare the values between gt and predictions after running predict_generator()
            self.gt.append(gt)

            X.append(tile)
            y.append(gt)

        return np.array(X), np.array(y)

    def on_epoch_end(self):
        if self.shuffle:
            random.shuffle(self.list_IDs)

这就是我所说的:

batchsize = 10

model = load_model(model_path, custom_objects={'jaccard_distance': jaccard_distance, 'auc': auc})

test_gen = DataGenerator("/path/to/data/path/written/in/file.txt",
                         gen_data_type='test',
                         batchsize=batchsize,
                         classes=None,
                         selected_class=None)
y_pred = model.predict_generator(test_gen, steps=None, verbose=1)
y_true = np.array(test_gen.gt)


plot_confusion_matrix(y_true, y_pred, ["Hedgerows", "No Hedgerows"])

这是错误:

60/60 [==============================] - 4s 71ms/step
Traceback (most recent call last):
  File "/work/stages/mathurin/sentinel_segmentation/unet/confusion_matrix.py", line 95, in <module>
    plot_confusion_matrix(y_true, y_pred, ["Hedgrows", "No Hedgerows"], normalize=normalization, title=model_path.split('/')[-1].split('.')[0])
  File "/work/stages/mathurin/sentinel_segmentation/unet/confusion_matrix.py", line 35, in plot_confusion_matrix
    cm = confusion_matrix(y_true, y_pred)
  File "/work/tools/anaconda3/lib/python3.6/site-packages/sklearn/metrics/classification.py", line 253, in confusion_matrix
    y_type, y_true, y_pred = _check_targets(y_true, y_pred)
  File "/work/tools/anaconda3/lib/python3.6/site-packages/sklearn/metrics/classification.py", line 71, in _check_targets
    check_consistent_length(y_true, y_pred)
  File "/work/tools/anaconda3/lib/python3.6/site-packages/sklearn/utils/validation.py", line 235, in check_consistent_length
    " samples: %r" % [int(l) for l in lengths])
ValueError: Found input variables with inconsistent numbers of samples: [702, 592]

当我查看 get_item() 函数的索引号时,它不是预期的数字...应该是 len( ) 函数,但它总是更小。 在这个例子中,进行预测后,self.index 参数值为8。 就像如果它超过然后在 0、1、2 等处重新启动......

编辑:更奇怪! 我只是重新运行,我得到了不同数量的 stored_gt 数组......

60/60 [==============================] - 6s 100ms/step
Traceback (most recent call last):
  File "/work/tools/pycharm-community-2019.1.1/helpers/pydev/pydevd.py", line 1741, in <module>
    main()
  File "/work/tools/pycharm-community-2019.1.1/helpers/pydev/pydevd.py", line 1735, in main
    globals = debugger.run(setup['file'], None, None, is_module)
  File "/work/tools/pycharm-community-2019.1.1/helpers/pydev/pydevd.py", line 1135, in run
    pydev_imports.execfile(file, globals, locals)  # execute the script
  File "/work/tools/pycharm-community-2019.1.1/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "/work/stages/mathurin/sentinel_segmentation/unet/confusion_matrix.py", line 95, in <module>
    plot_confusion_matrix(y_true, y_pred, ["Hedgrows", "No Hedgerows"], normalize=normalization, title=model_path.split('/')[-1].split('.')[0])
  File "/work/stages/mathurin/sentinel_segmentation/unet/confusion_matrix.py", line 35, in plot_confusion_matrix
    cm = confusion_matrix(y_true, y_pred)
  File "/work/tools/anaconda3/lib/python3.6/site-packages/sklearn/metrics/classification.py", line 253, in confusion_matrix
    y_type, y_true, y_pred = _check_targets(y_true, y_pred)
  File "/work/tools/anaconda3/lib/python3.6/site-packages/sklearn/metrics/classification.py", line 71, in _check_targets
    check_consistent_length(y_true, y_pred)
  File "/work/tools/anaconda3/lib/python3.6/site-packages/sklearn/utils/validation.py", line 235, in check_consistent_length
    " samples: %r" % [int(l) for l in lengths])
ValueError: Found input variables with inconsistent numbers of samples: [682, 592]

【问题讨论】:

    标签: python deep-learning tf.keras


    【解决方案1】:

    这并不奇怪,keras 使用多个进程/线程运行生成器以提高性能,特别是用于训练,这就是为什么 fit_generatorpredict_generatorworkersuse_multiprocessing、@ 这样的关键字参数987654325@。所以解决方案是不在生成器实例中存储任何类型的基本事实或状态。

    对于您的具体情况,您可以通过手动调用生成器来使用另一种预测循环:

    labels = []
    preds = []
    for step in range(len(generator)):
        data, label = generator.__getitem__(step)
        pred = model.predict(data)
    
        preds.append(pred)
        labels.append(label)
    

    然后使用predslabels 制作混淆矩阵。

    【讨论】:

      猜你喜欢
      • 2019-03-17
      • 1970-01-01
      • 2018-04-04
      • 2020-12-10
      • 2019-03-16
      • 1970-01-01
      • 2012-06-07
      • 2018-10-23
      • 2019-09-28
      相关资源
      最近更新 更多