【问题标题】:Joining two DirectoryIterators in Keras在 Keras 中加入两个 DirectoryIterator
【发布时间】:2019-12-03 22:30:08
【问题描述】:

假设我有如下内容:

image_data_generator = ImageDataGenerator(rescale=1./255)

train_generator = image_data_generator.flow_from_directory(
  'my_directory',
  target_size=(28, 28),
  batch_size=32,
  class_mode='categorical'
)

然后我的train_generator 填充了来自my_directory 的数据,其中包含两个子文件夹,将数据分为01 类。

假设我还有另一个目录that_directory,数据也分为01 类。我想用这些额外的数据来扩充我的train_generator

运行train_generator = image_data_generator.flow_from_directory('that_directory', ...) 会从my_directory 中删除先前的数据。

有没有办法在不改变文件夹结构本身的情况下将两组数据扩充或附加到一个生成器或像DirectoryIterator 一样运行的对象中?

【问题讨论】:

    标签: python machine-learning keras generator


    【解决方案1】:

    只需将生成器组合到另一个生成器中,可以选择使用不同的增强配置:

    idg1 = ImageDataGenerator(**idg1_configs)
    idg2 = ImageDataGenerator(**idg2_configs)
    
    g1 = idg1.flow_from_directory('idg1_dir',...)
    g2 = idg2.flow_from_directory('idg2_dir',...)
    
    def combine_gen(*gens):
        while True:
            for g in gens:
                yield next(g)
    
    # ...
    model.fit_generator(combine_gen(g1, g2), steps_per_epoch=len(g1)+len(g2), ...)
    

    这将交替从g1g2 生成批次。

    请注意,有人可能会建议使用itertools.chain,但是您不能在这里使用它,因为ImageDataGenerators 生成器是永无止境的,并且会不断生成一批数据。这对于您传递给 fit_generator 方法的生成器是预期的。来自Keras doc

    ...生成器将无限期地循环其数据。当模型看到steps_per_epoch 批次时,一个纪元结束。

    steps_per_epoch 如果未设置,则默认为len(generator),其中generator 是您传递给fit_generator 方法的生成器。 ImageDataGenerator 生成器可以给出它们的长度,因此您不需要手动设置 steps_per_epoch 参数。如果您希望使用上述组合生成器实现相同的功能,则可以改用此解决方案:

    class CombinedGen():
        def __init__(self, *gens):
            self.gens = gens
    
        def generate(self):
            while True:
                for g in self.gens:
                    yield next(g)
    
        def __len__(self):
            return sum([len(g) for g in self.gens])
    
    # usage:
    cg = CombinedGen(g1, g2)
    model.fit_generator(cg.generate(), ...) # no need to set `steps_per_epoch`
    

    如果您有兴趣直接迭代此类的对象(而不是迭代 cg.generate()),还可以将 __next__ 和/或 __iter__ 方法添加到 CombinedGen 类。

    【讨论】:

    • 如果我正在做类似for (data, labels) in my_directory_iterator 的事情,这将如何工作?在我看来, combine_gen 不会有很好的迭代器属性,因为它会永远产生。
    • @Richard "...因为它永远产生" 正如我在最后一句中所说的,这就是 ImageDataGenerator 的工作原理:它只是永无止境地生成数据。所以combine_gen 没有什么不同。此外,如果您仔细阅读代码,您会发现它只是包装了生成器(即它是一个包装器生成器),因此您肯定可以做类似for (data, labels) in combine_gen(*my_generators) 的事情:它的行为方式相同(并且永远不会停止;您有责任以某种方式停止它,例如计算步数)。
    • @Richard 限制是使用 fit_generatorfit_generatorImageDataGenerator 生成器的参数完成的,您也可以将其与 combine_gen() 生成器一起使用。
    • @Richard 我刚刚用不需要手动设置 steps_per_epoch 参数的解决方案更新了我的答案。请看一看。
    • 事实证明我无法对此进行迭代,因为包装器没有 iter 属性,也没有神奇地从底层 DirectoryIterators 继承它。这似乎也很棘手,因为 cg.generate() 在 Python 中返回生成器对象,我不确定如何解决。不过,这基本上让我完成了 90% 的工作,而且我认为它可以与更多的补丁和更多的谷歌搜索一起使用。谢谢!
    猜你喜欢
    • 2021-02-19
    • 1970-01-01
    • 2018-06-26
    • 1970-01-01
    • 1970-01-01
    • 2018-06-20
    • 1970-01-01
    • 2016-01-24
    • 2014-10-14
    相关资源
    最近更新 更多