Estoy tratando de entrenar un modelo de Keras que incorpore el aumento de datos en el propio modelo. La entrada al modelo son imágenes de diferentes clases, y se supone que el modelo genera un modelo de aumento para cada clase que debe usarse para el proceso de aumento. Mi código se parece aproximadamente a esto:

from keras.models import Model
from keras.layers import Input
...further imports...

def get_main_model(input_shape, n_classes):
    encoder_model = get_encoder_model()
    input = Input(input_shape, name="input")
    label_input = Input((1,), name="label_input")
    aug_models = [get_augmentation_model() for i in range(n_classes)]
    augmentation = aug_models[label_input](input)
    x = encoder_model(input)
    y = encoder_model(augmentation)
    model = Model(inputs=[input, label_input], outputs=[x, y])
    model.add_loss(custom_loss_function(x, y))
    return model 

Entonces me gustaría pasar lotes de datos a través del modelo que consisten en una matriz de imágenes (pasadas a input) y una matriz correspondiente de etiquetas (pasadas a label_input). Sin embargo, esto no funciona ya que lo que se ingresa en label_input se convierte en un tensor por Tensorflow y no se puede usar para indexar en lo siguiente. Lo que he probado es lo siguiente:

  • augmentation = aug_models[int(label_input)](input) -> no funciona porque label_input is a tensor
  • augmentation = aug_models[tf.make_ndarray(label_input)](input) -> la transmisión no funciona (supongo que porque label_input es un tensor simbólico)
  • tf.gather(aug_models, label_input) -> no funciona porque el resultado de la operación es una instancia del modelo de Keras que Tensorflow intenta convertir en un tensor (que obviamente falla)

¿Existe algún tipo de truco en Tensorflow que me permita pasar un parámetro al modelo durante el entrenamiento que no se convierta en un tensor o de una manera diferente en la que pueda decirle al modelo qué modelo de aumento seleccionar? ¡Gracias por adelantado!

2
benebrue 21 ene. 2021 a las 17:34

1 respuesta

La mejor respuesta

Para aplicar un aumento diferente a cada elemento del tensor input (por ejemplo, condicionado a label_input), deberá:

  1. Primero, calcule cada posible aumento para cada elemento del lote.
  2. En segundo lugar, seleccione los aumentos deseados de acuerdo con la etiqueta.

Desafortunadamente, la indexación es imposible porque los tensores input y label_input son multidimensionales (por ejemplo, si aplicara el mismo aumento a cada elemento del lote, entonces será posible utilizar cualquier declaración de flujo tensorial condicional como tf.case).


Aquí hay un ejemplo de trabajo mínimo que muestra cómo puede lograr esto:

input = tf.ones((3, 1))  # Shape=(bs, 1)
label_input = tf.constant([3, 2, 1])  # Shape=(bs, 1)
aug_models = [lambda x: x, lambda x: x * 2, lambda x: x * 3, lambda x: x * 4]
nb_classes = len(aug_models)

augmented_data = tf.stack([aug_model(input) for aug_model in aug_models])  # Shape=(nb_classes, bs, 1)
selector = tf.transpose(tf.one_hot(label_input, depth=nb_classes))  # Shape=(nb_classes, bs)
augmentation = tf.reduce_sum(selector[..., None] * augmented_data, axis=0)  # Shape=(bs, 1) 
print(augmentation)

# prints:
# tf.Tensor(
# [[4.]
#  [3.]
#  [2.]], shape=(3, 1), dtype=float32)

NOTA: Es posible que deba ajustar estas operaciones en un Keras capa Lambda.

2
rvinas 30 ene. 2021 a las 16:07