How do I combine two keras generator functions

2020-03-26 08:40发布

I am trying to implement a Siamese network in Keras and I want to apply image transformations to the 2 input images using Keras Image Data Generators. As per the example in the docs- https://keras.io/preprocessing/image/, I've tried to implement it like this-

datagen_args = dict(rotation_range=10,
                    width_shift_range=0.1,
                    height_shift_range=0.1,
                    horizontal_flip=True)

in_gen1 = ImageDataGenerator(**datagen_args)
in_gen2 = ImageDataGenerator(**datagen_args)

train_generator = zip(in_gen1, in_gen2)

model.fit(train_generator.flow([pair_df[:, 0,::],pair_df[:, 1,::]],
                          y_train,batch_size=16), epochs, verbose = 1)

But this code throws this error:

TypeError: zip argument #1 must support iteration

I've tried using itertools.izip as suggested in Keras - Generator for large dataset of Images and Masks but this throws the same error.

How do I resolve this?

EDIT: In case anyone is interested, this worked finally-

datagen_args = dict(
    featurewise_center=False,
    rotation_range=10,
    width_shift_range=0.1,
    height_shift_range=0.1,
    horizontal_flip=True)

in_gen1 = ImageDataGenerator(**datagen_args)
in_gen2 = ImageDataGenerator(**datagen_args)

in_gen1 = in_gen1.flow(pair_df[:, 0,::], y_train, batch_size = 16, shuffle = False)
in_gen2 = in_gen2.flow(pair_df[:, 1,::], y_train, batch_size = 16, shuffle = False)

for e in range(epochs):
    batches = 0
    for x1, x2 in itertools.izip(in_gen1,in_gen2):
    # x1, x2 are tuples returned by the generator, check whether targets match
        assert sum(x1[1] != x2[1]) == 0  
        model.fit([x1[0], x2[0]], x1[1], verbose = 1)
        batches +=1
        if(batches >= len(pair_df)/16):
            break

3条回答
放我归山
2楼-- · 2020-03-26 09:08

Using zip() to combine generators leads to generation of an infinite iterator. Use this instead:

def combine_generator(gen1, gen2):
    while True:
        yield(next(gen1), next(gen2))

Modified code would look something like this:

datagen_args = dict(rotation_range=10,
                    width_shift_range=0.1,
                    height_shift_range=0.1,
                    horizontal_flip=True)

in_gen1 = ImageDataGenerator(**datagen_args)
in_gen2 = ImageDataGenerator(**datagen_args)

def combine_generator(gen1, gen2):
    while True:
        yield(next(gen1), next(gen2))

train_generator = combine_generator(in_gen1, in_gen2)

model.fit(train_generator.flow([pair_df[:, 0,::],pair_df[:, 1,::]],
                          y_train,batch_size=16), epochs, verbose = 1)

See this thread for further reference.

查看更多
ら.Afraid
3楼-- · 2020-03-26 09:08

While the answers provided work well, if you want to place yourself in a thread-safe multiprocessing fitting, you need to implement a Sequence that will merge the 2 generators.


from keras.utils import  Sequence


class MergedGenerators(Sequence):
    def __init__(self, *generators):
        self.generators = generators
        # TODO add a check to verify that all generators have the same length

    def __len__(self):
        return len(self.generators[0])

    def __getitem__(self, index):
        return [generator[index] for generator in self.generators]

datagen_args = dict(
    featurewise_center=False,
    rotation_range=10,
    width_shift_range=0.1,
    height_shift_range=0.1,
    horizontal_flip=True)

in_gen1 = ImageDataGenerator(**datagen_args)
in_gen2 = ImageDataGenerator(**datagen_args)

in_gen1 = in_gen1.flow(pair_df[:, 0,::], y_train, batch_size = 16, shuffle = False)
in_gen2 = in_gen2.flow(pair_df[:, 1,::], y_train, batch_size = 16, shuffle = False)

train_merged_generator = MergedGenerators(in_gen1, in_gen2)

model.fit(train_merged_generator, epochs, verbose=1, use_multiprocessing=True)

I think in this case it doesn't make much of a difference since the data is already in memory. This would have to be tested.

查看更多
家丑人穷心不美
4楼-- · 2020-03-26 09:33

You need to first convert them to something iterable using the flow method.

Try the following:

datagen_args = dict(rotation_range=10,
                    width_shift_range=0.1,
                    height_shift_range=0.1,
                    horizontal_flip=True)

in_gen1 = ImageDataGenerator(**datagen_args)
in_gen2 = ImageDataGenerator(**datagen_args)

gen1_flow = in_gen1.flow(X_train[:,0, ::],y_train, batch_size=16)
gen2_flow = in_gen2.flow(X_train[:,1, ::],y_train, batch_size=16)

train_generator = zip(gen1_flow, gen2_flow)

model.fit_generator(train_generator,
                    steps_per_epoch=len(X_train)/16,
                    epochs=epochs)
查看更多
登录 后发表回答