Personalización de MinDiffModel

Introducción

En la mayoría de casos, el uso MinDiffModel directamente como se describe en la "Integración MinDiff con MinDiffModel" guía es suficiente. Sin embargo, es posible que necesite un comportamiento personalizado. Las dos razones principales de esto son:

  • El keras.Model que está utilizando tiene un comportamiento personalizado que desea conservar.
  • Desea que el MinDiffModel comportarse de manera diferente de la predeterminada.

En cualquiera de los casos, tendrá que subclase MinDiffModel para lograr los resultados deseados.

Configuración

pip install -q --upgrade tensorflow-model-remediation
import tensorflow as tf
tf.get_logger().setLevel('ERROR')  # Avoid TF warnings.
from tensorflow_model_remediation import min_diff
from tensorflow_model_remediation.tools.tutorials_utils import uci as tutorials_utils

Primero, descargue los datos. Por concisión, la lógica de preparación de entrada ha sido factorizada hacia helper funciones como se describe en la guía de preparación de entrada . Puede leer la guía completa para obtener detalles sobre este proceso.

# Original Dataset for training, sampled at 0.3 for reduced runtimes.
train_df = tutorials_utils.get_uci_data(split='train', sample=0.3)
train_ds = tutorials_utils.df_to_dataset(train_df, batch_size=128)

# Dataset needed to train with MinDiff.
train_with_min_diff_ds = (
    tutorials_utils.get_uci_with_min_diff_dataset(split='train', sample=0.3))

Conservación de las personalizaciones del modelo original

tf.keras.Model está diseñado para personalizar fácilmente a través de subclases como se describe aquí . Si el modelo ha personalizado implementaciones que desea preservar al aplicar MinDiff, tendrá que subclase MinDiffModel .

Modelo personalizado original

Para ver cómo se puede conservar las personalizaciones, crear un modelo personalizado que establece un atributo a True cuando su costumbre train_step se llama. Esta no es una personalización útil, pero servirá para ilustrar el comportamiento.

class CustomModel(tf.keras.Model):

  # Customized train_step
  def train_step(self, *args, **kwargs):
    self.used_custom_train_step = True  # Marker that we can check for.
    return super(CustomModel, self).train_step(*args, **kwargs)

El entrenamiento de un modelo de este tipo sería lo mismo que una normal, Sequential modelo.

model = tutorials_utils.get_uci_model(model_class=CustomModel)  # Use CustomModel.

model.compile(optimizer='adam', loss='binary_crossentropy')

_ = model.fit(train_ds.take(1), epochs=1, verbose=0)

# Model has used the custom train_step.
print('Model used the custom train_step:')
print(hasattr(model, 'used_custom_train_step'))  # True
Model used the custom train_step:
True

Subclasificación de MinDiffModel

Si se va a tratar de utilizar MinDiffModel directamente, el modelo no usaría la costumbre train_step .

model = tutorials_utils.get_uci_model(model_class=CustomModel)
model = min_diff.keras.MinDiffModel(model, min_diff.losses.MMDLoss())

model.compile(optimizer='adam', loss='binary_crossentropy')

_ = model.fit(train_with_min_diff_ds.take(1), epochs=1, verbose=0)

# Model has not used the custom train_step.
print('Model used the custom train_step:')
print(hasattr(model, 'used_custom_train_step'))  # False
Model used the custom train_step:
False

Con el fin de utilizar la correcta train_step método, necesita una clase personalizada que subclases tanto MinDiffModel y CustomModel .

class CustomMinDiffModel(min_diff.keras.MinDiffModel, CustomModel):
  pass  # No need for any further implementation.

El entrenamiento de este modelo utilizará el train_step de CustomModel .

model = tutorials_utils.get_uci_model(model_class=CustomModel)

model = CustomMinDiffModel(model, min_diff.losses.MMDLoss())

model.compile(optimizer='adam', loss='binary_crossentropy')

_ = model.fit(train_with_min_diff_ds.take(1), epochs=1, verbose=0)

# Model has used the custom train_step.
print('Model used the custom train_step:')
print(hasattr(model, 'used_custom_train_step'))  # True
Model used the custom train_step:
True

Personalización de comportamientos predeterminados de MinDiffModel

En otros casos, es posible que desee cambiar comportamientos predeterminados específicos de MinDiffModel . El caso de uso común la mayor parte de esto está cambiando el comportamiento por defecto de desempaquetar manejar adecuadamente sus datos si no se utiliza pack_min_diff_data .

Al empaquetar los datos en un formato personalizado, esto puede aparecer de la siguiente manera.

def _reformat_input(inputs, original_labels):
  min_diff_data = min_diff.keras.utils.unpack_min_diff_data(inputs)
  original_inputs = min_diff.keras.utils.unpack_original_inputs(inputs)

  return ({
      'min_diff_data': min_diff_data,
      'original_inputs': original_inputs}, original_labels)

customized_train_with_min_diff_ds = train_with_min_diff_ds.map(_reformat_input)

Los customized_train_with_min_diff_ds de conjunto de datos devuelve lotes compuestos de tuplas (x, y) donde x es un dict contiene min_diff_data y original_inputs y y es el original_labels .

for x, _ in customized_train_with_min_diff_ds.take(1):
  print('Type of x:', type(x))  # dict
  print('Keys of x:', x.keys())  # 'min_diff_data', 'original_inputs'
Type of x: <class 'dict'>
Keys of x: dict_keys(['min_diff_data', 'original_inputs'])

Este formato de datos no es lo MinDiffModel espera por defecto y que pasa customized_train_with_min_diff_ds a que daría lugar a un comportamiento inesperado. Para solucionar este problema, deberá crear su propia subclase.

class CustomUnpackingMinDiffModel(min_diff.keras.MinDiffModel):

  def unpack_min_diff_data(self, inputs):
    return inputs['min_diff_data']

  def unpack_original_inputs(self, inputs):
    return inputs['original_inputs']

Con esta subclase, puede entrenar como con los otros ejemplos.

model = tutorials_utils.get_uci_model()
model = CustomUnpackingMinDiffModel(model, min_diff.losses.MMDLoss())

model.compile(optimizer='adam', loss='binary_crossentropy')

_ = model.fit(customized_train_with_min_diff_ds, epochs=1)
77/77 [==============================] - 4s 30ms/step - loss: 0.6690 - min_diff_loss: 0.0395

Limitaciones de una personalizada MinDiffModel

Creación de un MinDiffModel ofrece una enorme cantidad de flexibilidad para los casos de uso más complejos. Sin embargo, todavía hay algunos casos extremos que no admitirá.

Preprocesamiento o validación de las entradas antes de call

La mayor limitación para una subclase de MinDiffModel es que requiere la x componente de los datos de entrada (es decir, el primer o único elemento en el lote devuelto por el tf.data.Dataset ) para hacer pasar a través sin preprocesamiento o de validación para call .

Esto es simplemente porque la min_diff_data se embala en la x componente de los datos de entrada. Cualquier procesamiento previo o validación no se esperaría que la estructura adicional que contiene min_diff_data y es probable que se rompa.

Si el preprocesamiento o la validación se puede personalizar fácilmente (por ejemplo, si se incluye en su propio método), esto se puede solucionar fácilmente anulándolo para asegurarse de que maneja la estructura adicional correctamente.

Un ejemplo con validación podría verse así:

class CustomMinDiffModel(min_diff.keras.MinDiffModel, CustomModel):

  # Override so that it correctly handles additional `min_diff_data`.
  def validate_inputs(self, inputs):
    original_inputs = self.unpack_original_inputs(inputs)
    ...  # Optionally also validate min_diff_data
    # Call original validate method with correct inputs
    return super(CustomMinDiffModel, self).validate(original_inputs)

Si el pre-procesamiento o validación no es fácilmente personalizable, a continuación, utilizando MinDiffModel puede no funcionar para usted y tendrá que integrar MinDiff sin ella como se describe en esta guía .

Colisiones de nombres de métodos

Es posible que su modelo tiene métodos cuyos nombres chocar con las implementadas en MinDiffModel (ver la lista completa de los métodos públicos de la documentación de la API ).

Esto solo es problemático si se llamará a estos en una instancia del modelo (en lugar de internamente en algún otro método). Aunque muy poco probable, si se encuentra en esta situación tendrá que cambiar el nombre de cualquiera de anulación y algunos métodos o, si no es posible, puede que tenga que considerar la integración de MinDiff sin MinDiffModel como se describe en esta guía sobre el tema .

Recursos adicionales