Keras ImageDataGenerator用于多个输入和基于图像的目标输出

时间:2019-12-26 19:53:50

标签: tensorflow keras tensorflow-datasets tf.keras

我有一个模型,该模型将两个图像作为输入,并生成一个图像作为目标输出。

我所有的训练图像数据都在以下子文件夹中:

  • input1
  • input2
  • 目标

我可以在keras中使用ImageDataGenerator类和方法flow_from_directorymodel.fit_generator来训练网络吗?

我该怎么做?由于我遇到的大多数示例都涉及单个输入和基于标签的目标输出。

就我而言,我有一个非分类目标输出数据和多个输入。

请帮忙,因为您的建议可能会很有帮助。

3 个答案:

答案 0 :(得分:1)

一种可能性是将三个ImageDataGenerator合并为一个,使用class_mode=None(这样他们就不会返回任何目标),并使用shuffle=False(重要)。确保每个输入都使用相同的batch_size,并确保每个输入都位于不同的目录中,并且目标也位于不同的目录中,并且每个目录中的图像数量完全相同。 / p>

idg1 = ImageDataGenerator(...choose params...)
idg2 = ImageDataGenerator(...choose params...)
idg3 = ImageDataGenerator(...choose params...)

gen1 = idg1.flow_from_directory('input1_dir',
                                shuffle=False,
                                class_mode=None)
gen2 = idg2.flow_from_directory('input2_dir',
                                shuffle=False,
                                class_mode=None)
gen3 = idg3.flow_from_directory('target_dir',
                                shuffle=False,
                                class_mode=None)

创建自定义生成器:

class JoinedGen(tf.keras.utils.Sequence):
    def __init__(self, input_gen1, input_gen2, target_gen):
        self.gen1 = input_gen1
        self.gen2 = input_gen2
        self.gen3 = target_gen

        assert len(input_gen1) == len(input_gen2) == len(target_gen)

    def __len__(self):
        return len(self.gen1)

    def __getitem__(self, i):
        x1 = self.gen1[i]
        x2 = self.gen2[i]
        y = self.gen3[i]

        return [x1, x2], y

    def on_epoch_end(self):
        self.gen1.on_epoch_end()
        self.gen2.on_epoch_end()
        self.gen3.on_epoch_end()

使用此生成器进行训练:

my_gen = JoinedGen(gen1, gen2, gen3)
model.fit_generator(my_gen, ...)

或创建一个自定义生成器。上面显示了其所有结构。

答案 1 :(得分:1)

DanielMöller帖子中显示的自定义类JoinedGen如果不需要(或不需要)改组训练示例,则效果很好。然而,对于每个学习过程而言,在每个时期的末尾进行改组是非常合乎需要的。幸运的是,这也可以轻松实现。首先,三个ImageDataGenerators应该使用shuffle = True(重要)。

idg1 = ImageDataGenerator(...choose params...)
idg2 = ImageDataGenerator(...choose params...)
idg3 = ImageDataGenerator(...choose params...)

gen1 = idg1.flow_from_directory('input1_dir',
                                shuffle=True,
                                class_mode=None)
gen2 = idg2.flow_from_directory('input2_dir',
                                shuffle=True,
                                class_mode=None)
gen3 = idg3.flow_from_directory('target_dir',
                                shuffle=True,
                                class_mode=None)

如果不执行其他任何操作,则三个生成器将在第一个纪元后不同步,因为它们各自在第一个纪元结束时将以不同的方式重新排列。为了使它们保持同步,需要在函数on_epoch_end(self)的末尾添加两行。即,最后两个生成器应获得与第一个生成器相同的索引数组:

class JoinedGen(tf.keras.utils.Sequence):
    def __init__(self, input_gen1, input_gen2, target_gen):
        self.gen1 = input_gen1
        self.gen2 = input_gen2
        self.gen3 = target_gen

        assert len(input_gen1) == len(input_gen2) == len(target_gen)

    def __len__(self):
        return len(self.gen1)

    def __getitem__(self, i):
        x1 = self.gen1[i]
        x2 = self.gen2[i]
        y = self.gen3[i]

        return [x1, x2], y

    def on_epoch_end(self):
        self.gen1.on_epoch_end()
        self.gen2.on_epoch_end()
        self.gen3.on_epoch_end()
        self.gen2.index_array = self.gen1.index_array
        self.gen3.index_array = self.gen1.index_array

答案 2 :(得分:0)

您可以创建一个处理整个操作的外部函数。

generator_imgs = ImageDataGenerator(...choose params...)

创建函数

def generate_generator_multiple(generator):
    gen1 = generator.flow_from_directory('input1_dir', 
                                          shuffle=False, 
                                          class_mode=None,
                                          batch_size=32)

    gen2 = generator.flow_from_directory('input2_dir', 
                                          shuffle=False, 
                                          class_mode=None,
                                          batch_size=32)

    gen3 = generator.flow_from_directory('target_dir', 
                                          shuffle=False, 
                                          class_mode=None,
                                          batch_size=32)
    while True:
        x1 = gen1.next()
        x2 = gen2.next()
        y  = gen3.next()
        
        yield [x1, x2], y

现在只需调用生成函数:

my_gen = generate_generator_multiple(generator_imgs)
model.fit_generator(my_gen, ...)