web-dev-qa-db-fra.com

Keras: Comment utiliser fit_generator avec plusieurs sorties de type différent

Dans un modèle Keras avec l'API fonctionnelle, j'ai besoin d'appeler fit_generator pour s'entraîner sur les données d'images augmentées à l'aide d'un ImageDataGenerator. Le problème est que mon modèle a deux sorties: le masque que j'essaie de prédire et une valeur binaire que je veux évidemment augmenter uniquement l'entrée et la sortie du masque et non la valeur binaire. Comment puis-je atteindre cet objectif?

17
Mike

L'exemple ci-dessous pourrait être explicite! Le modèle "factice" prend 1 entrée (image) et génère 2 valeurs. Le modèle calcule le MSE pour chaque sortie.

x = Convolution2D(8, 5, 5, subsample=(1, 1))(image_input)
x = Activation('relu')(x)
x = Flatten()(x)
x = Dense(50, W_regularizer=l2(0.0001))(x)
x = Activation('relu')(x)

output1 = Dense(1, activation='linear', name='output1')(x)
output2 = Dense(1, activation='linear', name='output2')(x)

model = Model(input=image_input, output=[output1, output2])
model.compile(optimizer='adam', loss={'output1': 'mean_squared_error', 'output2': 'mean_squared_error'})

La fonction ci-dessous génère des lots pour alimenter le modèle pendant l'entraînement. Il prend les données d'entraînement x et l'étiquette y où y = [y1, y2]

batch_generator(x, y, batch_size, is_train):
    sample_idx = 0
    while True:
       X = np.zeros((batch_size, input_height, input_width, n_channels), dtype='float32')
       y1 = np.zeros((batch_size, mask_height, mask_width), dtype='float32')
       y2 = np.zeros((batch_size, 1), dtype='float32')

       # fill up the batch
       for row in range(batch_sz):
           image = x[sample_idx]
           mask = y[0][sample_idx]
           binary_value = y[1][sample_idx]
           # transform/preprocess image
           image = cv2.resize(image, (input_width, input_height))
           if is_train:
               image, mask = my_data_augmentation_function(image, mask)
           X_batch[row, ;, :, :] = image
           y1_batch[row, :, :] = mask
           y2_batch[row, 0] = binary_value
           sample_idx += 1

       # Normalize inputs
       X_batch = X_batch/255.
       yield(X_batch, {'output1': y1_batch, 'output2': y2_batch} ))

Enfin, nous appelons fit_generator ()

    model.fit_generator(batch_generator(X_train, y_train, batch_size, is_train=1))
28
JMarc

Si vous avez séparé le masque et la valeur binaire, vous pouvez essayer quelque chose comme ceci:

generator = ImageDataGenerator(rotation_range=5.,
                                width_shift_range=0.1, 
                                height_shift_range=0.1, 
                                horizontal_flip=True,  
                                vertical_flip=True)

def generate_data_generator(generator, X, Y1, Y2):
    genX = generator.flow(X, seed=7)
    genY1 = generator.flow(Y1, seed=7)
    while True:
            Xi = genX.next()
            Yi1 = genY1.next()
            Yi2 = function(Y2)
            yield Xi, [Yi1, Yi2]

Donc, vous utilisez le même générateur pour l'entrée et le masque avec la même valeur de départ pour définir la même opération. Vous pouvez modifier la valeur binaire ou non en fonction de vos besoins (Y2). Ensuite, vous appelez fit_generator ():

model.fit_generator(generate_data_generator(generator, X, Y1, Y2),
                epochs=epochs)
10
Jose L

La meilleure façon d'y parvenir semble être de créer une nouvelle classe de générateur développant celle fournie par Keras qui analyse les données en augmentant uniquement les images et en produisant toutes les sorties.

0
Mike