Intégration de MinDiff sans MinDiffModel

introduction

Il est possible d'intégrer MinDiff directement dans l'implémentation de votre modèle. Bien que cela ne crée pas la possibilité d'utiliser MinDiffModel , cette option offre le plus haut niveau de contrôle qui peut être particulièrement utile lorsque votre modèle est une sous - classe de tf.keras.Model .

Ce guide montre comment vous pouvez intégrer mindiff directement dans la mise en œuvre d'un modèle personnalisé en ajoutant à la train_step méthode.

Installer

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

Tout d'abord, téléchargez les données. Pour la concision, la logique de préparation d'entrée a été pris en compte dans des fonctions auxiliaires , comme décrit dans le guide de préparation d'entrée . Vous pouvez lire le guide complet pour plus de détails sur ce processus.

# 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))

Personnalisations originales du modèle personnalisé

tf.keras.Model est conçu pour être facilement personnalisé via le sous - classement. Cela implique généralement de changer ce qui se passe dans l'appel à fit comme décrit ici .

Ce guide utilise une implémentation personnalisée où le train_step ressemble étroitement à la valeur par défaut tf.keras.Model.train_step . Normalement, il n'y aurait aucun avantage à le faire, mais ici, cela aidera à montrer comment intégrer MinDiff.

class CustomModel(tf.keras.Model):

  def train_step(self, data):
    # Unpack the data.
    x, y, sample_weight = tf.keras.utils.unpack_x_y_sample_weight(data)

    with tf.GradientTape() as tape:
      y_pred = self(x, training=True)  # Forward pass.
      loss = self.compiled_loss(
          y, y_pred, sample_weight, regularization_losses=self.losses)
      # Compute the loss value.
      loss = self.compiled_loss(
          y, y_pred, sample_weight, regularization_losses=self.losses)

    # Compute gradients and update weights.
    self.optimizer.minimize(loss, self.trainable_variables, tape=tape)
    # Update and return metrics.
    self.compiled_metrics.update_state(y, y_pred, sample_weight)
    return {m.name: m.result() for m in self.metrics}

Former le modèle comme vous un typique Model en utilisant l'API fonctionnelle.

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

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

_ = model.fit(train_ds, epochs=1)
77/77 [==============================] - 3s 22ms/step - loss: 0.7273

Intégrer MinDiff directement dans votre modèle

Ajout mindiff au train_step

Pour intégrer mindiff, vous devrez ajouter quelques lignes à la CustomModel qui est renommé ici comme CustomModelWithMinDiff .

Pour plus de clarté, ce guide utilise un drapeau booléen appelé apply_min_diff . Tout le code correspondant à mindiff ne sera exécuté si elle est réglée sur True . Si la valeur False alors le modèle se comporte exactement les mêmes que CustomModel .

min_diff_loss_fn = min_diff.losses.MMDLoss()  # Hard coded for convenience.
min_diff_weight = 2  # Arbitrary number for example, hard coded for convenience.
apply_min_diff = True  # Flag to help show where the additional lines are.

class CustomModelWithMinDiff(tf.keras.Model):

  def train_step(self, data):
    # Unpack the data.
    x, y, sample_weight = tf.keras.utils.unpack_x_y_sample_weight(data)

    # Unpack the MinDiff data.
    if apply_min_diff:
      min_diff_data = min_diff.keras.utils.unpack_min_diff_data(x)
      min_diff_x, membership, min_diff_sample_weight = (
          tf.keras.utils.unpack_x_y_sample_weight(min_diff_data))
      x = min_diff.keras.utils.unpack_original_inputs(x)

    with tf.GradientTape() as tape:
      y_pred = self(x, training=True)  # Forward pass.
      loss = self.compiled_loss(
          y, y_pred, sample_weight, regularization_losses=self.losses)
      # Compute the loss value.
      loss = self.compiled_loss(
          y, y_pred, sample_weight, regularization_losses=self.losses)

      # Calculate and add the min_diff_loss. This must be done within the scope
      # of tf.GradientTape().
      if apply_min_diff:
        min_diff_predictions = self(min_diff_x, training=True)
        min_diff_loss = min_diff_weight * min_diff_loss_fn(
            min_diff_predictions, membership, min_diff_sample_weight)
        loss += min_diff_loss

    # Compute gradients and update weights.
    self.optimizer.minimize(loss, self.trainable_variables, tape=tape)
    # Update and return metrics.
    self.compiled_metrics.update_state(y, y_pred, sample_weight)
    return {m.name: m.result() for m in self.metrics}

L'entraînement avec ce modèle ressemble exactement au précédent à l'exception de l'ensemble de données utilisé.

model = tutorials_utils.get_uci_model(model_class=CustomModelWithMinDiff)

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

_ = model.fit(train_with_min_diff_ds, epochs=1)
77/77 [==============================] - 4s 30ms/step - loss: 0.7799

Remodeler votre entrée (facultatif)

Étant donné que cette approche offre un contrôle total, vous pouvez profiter de cette opportunité pour remodeler l'entrée dans une forme légèrement plus propre. Lors de l' utilisation MinDiffModel , le min_diff_data doit être emballé dans le premier composant de chaque lot. Tel est le cas avec le train_with_min_diff_ds ensemble de données.

for x, y in train_with_min_diff_ds.take(1):
  print('Type of x:', type(x))  # MinDiffPackedInputs
  print('Type of y:', type(y))  # Tensor (original labels)
Type of x: <class 'tensorflow_model_remediation.min_diff.keras.utils.input_utils.MinDiffPackedInputs'>
Type of y: <class 'tensorflow.python.framework.ops.EagerTensor'>

Une fois cette exigence levée, vous pouvez réorganiser les données dans une structure légèrement plus intuitive avec les données d'origine et MinDiff clairement séparées.

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)
  original_data = (original_inputs, original_labels)

  return {
      'min_diff_data': min_diff_data,
      'original_data': original_data}

customized_train_with_min_diff_ds = train_with_min_diff_ds.map(_reformat_input)

Cette étape est totalement facultative mais peut être utile pour mieux organiser les données. Si vous le faites, la seule différence dans la façon dont vous implémentez CustomModelWithMinDiff sera comment déballer des data au début.

class CustomModelWithMinDiff(tf.keras.Model):

  def train_step(self, data):
    # Unpack the MinDiff data from the custom structure.
    if apply_min_diff:
      min_diff_data = data['min_diff_data']
      min_diff_x, membership, min_diff_sample_weight = (
          tf.keras.utils.unpack_x_y_sample_weight(min_diff_data))
      data = data['original_data']

    ... # possible preprocessing or validation on data before unpacking.

    x, y, sample_weight = tf.keras.utils.unpack_x_y_sample_weight(data)

    ...

Avec cette dernière étape, vous pouvez contrôler entièrement à la fois le format d'entrée et la façon dont il est utilisé dans le modèle pour appliquer MinDiff.

Ressources additionnelles

  • Pour une discussion approfondie sur l' évaluation de l' équité voir les conseils indicateurs d' équité
  • Pour des informations générales sur l' assainissement et mindiff, consultez la liste de remise en état .
  • Pour plus de détails sur les exigences entourant mindiff voir ce guide .
  • Pour voir un tutoriel de bout en bout sur l' utilisation mindiff dans Keras, consultez ce tutoriel .