Préparation des données MinDiff

introduction

Lors de la mise en œuvre de MinDiff, vous devrez prendre des décisions complexes lorsque vous choisissez et façonnez votre entrée avant de la transmettre au modèle. Ces décisions détermineront en grande partie le comportement de MinDiff dans votre modèle.

Ce guide couvrira les aspects techniques de ce processus, mais ne discutera pas de la façon d'évaluer un modèle pour l'équité, ou comment identifier des tranches et des mesures particulières pour l'évaluation. S'il vous plaît voir le guidage des indicateurs d' équité pour plus de détails à ce sujet .

Pour démontrer mindiff, ce guide utilise l' ensemble de données sur le revenu UCI . La tâche du modèle consiste à prédire si un individu a un revenu supérieur à 50 000 $, en fonction de divers attributs personnels. Ce guide suppose qu'il existe un écart problématique dans le FNR (faux taux de négatif) entre "Male" et "Female" tranches et le propriétaire du modèle (vous) a décidé d'appliquer mindiff pour résoudre le problème. Pour plus d' informations sur les scénarios dans lesquels on peut choisir d'appliquer mindiff, consultez la page exigences .

MinDiff fonctionne en pénalisant la différence de scores de distribution entre les exemples dans deux ensembles de données. Ce guide montrera comment choisir et construire ces ensembles MinDiff supplémentaires ainsi que comment tout regrouper afin qu'il puisse être transmis à un modèle pour la formation.

Installer

pip install -q --upgrade tensorflow-model-remediation
import tensorflow as tf
from tensorflow_model_remediation import min_diff
from tensorflow_model_remediation.tools.tutorials_utils import uci as tutorials_utils

Données d'origine

À des fins de démonstration et pour réduire les temps d'exécution, ce guide n'utilise qu'un échantillon de l'ensemble de données UCI Income. Dans un environnement de production réel, l'ensemble de données complet serait utilisé.

# Sampled at 0.3 for reduced runtimes.
train = tutorials_utils.get_uci_data(split='train', sample=0.3)

print(len(train), 'train examples')
9768 train examples

Conversion en tf.data.Dataset

MinDiffModel exige que l'entrée soit un tf.data.Dataset . Si vous utilisiez un format d'entrée différent avant d'intégrer MinDiff, vous devrez convertir vos données d'entrée.

Utilisez tf.data.Dataset.from_tensor_slices pour convertir à tf.data.Dataset .

dataset = tf.data.Dataset.from_tensor_slices((x, y, weights))
dataset.shuffle(...)  # Optional.
dataset.batch(batch_size)

Voir Model.fit documentation pour plus de détails sur les équivalences entre les deux méthodes d'entrée.

Dans ce guide, l'entrée est téléchargée en tant que Pandas DataFrame et nécessite donc cette conversion.

# Function to convert a DataFrame into a tf.data.Dataset.
def df_to_dataset(dataframe, shuffle=True):
  dataframe = dataframe.copy()
  labels = dataframe.pop('target')
  ds = tf.data.Dataset.from_tensor_slices((dict(dataframe), labels))
  if shuffle:
    ds = ds.shuffle(buffer_size=5000)  # Reasonable but arbitrary buffer_size.
  return ds

# Convert the train DataFrame into a Dataset.
original_train_ds = df_to_dataset(train)

Création de données MinDiff

Pendant la formation, MinDiff encouragera le modèle à réduire les différences de prédictions entre deux ensembles de données supplémentaires (qui peuvent inclure des exemples de l'ensemble de données d'origine). La sélection de ces deux ensembles de données est la décision clé qui déterminera l'effet de MinDiff sur le modèle.

Les deux ensembles de données doivent être choisis de telle sorte que la disparité de performances que vous essayez de corriger soit évidente et bien représentée. Étant donné que l'objectif est de réduire un écart entre FNR "Male" et "Female" tranches, ce moyen de créer un jeu de données avec seulement marqué positivement "Male" exemples et une autre avec seulement marqué positivement "Female" exemples; ce seront les jeux de données MinDiff.

Tout d'abord, examinez les données présentes.

female_pos = train[(train['sex'] == ' Female') & (train['target'] == 1)]
male_pos = train[(train['sex'] == ' Male') & (train['target'] == 1)]
print(len(female_pos), 'positively labeled female examples')
print(len(male_pos), 'positively labeled male examples')
385 positively labeled female examples
2063 positively labeled male examples

Il est parfaitement acceptable de créer des ensembles de données MinDiff à partir de sous-ensembles de l'ensemble de données d'origine.

Bien qu'il n'y ait pas de 5000 ou plus positifs "Male" exemples comme recommandé dans le guidage des exigences , il y a plus de 2000 , et il est raisonnable d'essayer avec beaucoup d'autres avant que la collecte de plus de données.

min_diff_male_ds = df_to_dataset(male_pos)

Positifs "Female" exemples, cependant, sont beaucoup plus rares à 385. Ceci est probablement trop petit pour une bonne performance et ainsi , il faudra tirer dans d' autres exemples.

full_uci_train = tutorials_utils.get_uci_data(split='train')
augmented_female_pos = full_uci_train[((full_uci_train['sex'] == ' Female') &
                                       (full_uci_train['target'] == 1))]
print(len(augmented_female_pos), 'positively labeled female examples')
1179 positively labeled female examples

L'utilisation de l'ensemble de données complet a plus que triplé le nombre d'exemples pouvant être utilisés pour MinDiff. C'est encore faible mais il suffit d'essayer comme premier passage.

min_diff_female_ds = df_to_dataset(augmented_female_pos)

Les deux ensembles de données MinDiff sont nettement plus petits que les 5 000 exemples ou plus recommandés. Bien qu'il soit raisonnable d'essayer d'appliquer MinDiff avec les données actuelles, vous devrez peut-être envisager de collecter des données supplémentaires si vous observez de mauvaises performances ou un surapprentissage pendant l'entraînement.

L' utilisation tf.data.Dataset.filter

Vous pouvez également créer les deux ensembles de données mindiff directement à partir de l'original converti Dataset .

# Male
def male_predicate(x, y):
  return tf.equal(x['sex'], b' Male') and tf.equal(y, 0)

alternate_min_diff_male_ds = original_train_ds.filter(male_predicate).cache()

# Female
def female_predicate(x, y):
  return tf.equal(x['sex'], b' Female') and tf.equal(y, 0)

full_uci_train_ds = df_to_dataset(full_uci_train)
alternate_min_diff_female_ds = full_uci_train_ds.filter(female_predicate).cache()

Les résultants alternate_min_diff_male_ds et alternate_min_diff_female_ds seront équivalents à la production min_diff_male_ds et min_diff_female_ds respectivement.

Construire votre ensemble de données d'entraînement

Comme dernière étape, les trois ensembles de données (les deux nouvellement créés et l'original) doivent être fusionnés en un seul ensemble de données qui peut être transmis au modèle.

Battre les jeux de données

Avant de fusionner, les ensembles de données doivent être groupés.

  • L'ensemble de données d'origine peut utiliser le même traitement par lots que celui utilisé avant l'intégration de MinDiff.
  • Les ensembles de données MinDiff n'ont pas besoin d'avoir la même taille de lot que l'ensemble de données d'origine. Selon toute vraisemblance, un plus petit fonctionnera tout aussi bien. Bien qu'ils n'aient même pas besoin d'avoir la même taille de lot les uns que les autres, il est recommandé de le faire pour de meilleures performances.

Bien que pas strictement nécessaire, il est recommandé d'utiliser drop_remainder=True pour les deux ensembles de données mindiff ce qui garantira qu'ils ont des tailles de lots homogènes.

original_train_ds = original_train_ds.batch(128)  # Same as before MinDiff.

# The MinDiff datasets can have a different batch_size from original_train_ds
min_diff_female_ds = min_diff_female_ds.batch(32, drop_remainder=True)
# Ideally we use the same batch size for both MinDiff datasets.
min_diff_male_ds = min_diff_male_ds.batch(32, drop_remainder=True)

Emballage des jeux de données avec pack_min_diff_data

Une fois les jeux de données préparés, regroupez-les dans un seul jeu de données qui sera ensuite transmis au modèle. Un seul lot de l'ensemble de données résultant contiendra un lot de chacun des trois ensembles de données que vous avez préparés précédemment.

Vous pouvez le faire en utilisant la condition utils fonction dans le tensorflow_model_remediation package:

train_with_min_diff_ds = min_diff.keras.utils.pack_min_diff_data(
    original_dataset=original_train_ds,
    sensitive_group_dataset=min_diff_female_ds,
    nonsensitive_group_dataset=min_diff_male_ds)

Et c'est tout! Vous pourrez utiliser d' autres util fonctions dans le paquet de déballer des lots individuels en cas de besoin.

for inputs, original_labels in train_with_min_diff_ds.take(1):
  # Unpacking min_diff_data
  min_diff_data = min_diff.keras.utils.unpack_min_diff_data(inputs)
  min_diff_examples, min_diff_membership = min_diff_data
  # Unpacking original data
  original_inputs = min_diff.keras.utils.unpack_original_inputs(inputs)

Avec vos données nouvellement formées, vous êtes maintenant prêt à appliquer MinDiff dans votre modèle ! Pour savoir comment cela se fait, s'il vous plaît jeter un oeil sur les autres guides commençant par intégration mindiff avec MinDiffModel .

Utilisation d'un format d'emballage personnalisé (facultatif)

Vous pouvez décider de regrouper les trois ensembles de données de la manière que vous choisissez. La seule exigence est que vous devrez vous assurer que le modèle sait comment interpréter les données. L'implémentation par défaut de MinDiffModel suppose que les données ont été emballés à l' aide min_diff.keras.utils.pack_min_diff_data .

Un moyen facile de formater votre entrée que vous voulez est de transformer les données en tant que dernière étape après avoir utilisé min_diff.keras.utils.pack_min_diff_data .

# Reformat input to be a dict.
def _reformat_input(inputs, original_labels):
  unpacked_min_diff_data = min_diff.keras.utils.unpack_min_diff_data(inputs)
  unpacked_original_inputs = min_diff.keras.utils.unpack_original_inputs(inputs)

  return {
      'min_diff_data': unpacked_min_diff_data,
      'original_data': (unpacked_original_inputs, original_labels)}

customized_train_with_min_diff_ds = train_with_min_diff_ds.map(_reformat_input)

Votre modèle devra savoir lire cette entrée sur mesure comme indiqué dans le guide Customizing MinDiffModel .

for batch in customized_train_with_min_diff_ds.take(1):
  # Customized unpacking of min_diff_data
  min_diff_data = batch['min_diff_data']
  # Customized unpacking of original_data
  original_data = batch['original_data']

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 .

Ce guide décrit le processus et la prise de décision que vous pouvez suivre lors de l'application de MinDiff. Le reste des guides s'appuie sur ce cadre. Pour rendre cela plus facile, la logique trouvée dans ce guide a été factorisée dans des fonctions d'aide :

  • get_uci_data : Cette fonction est déjà utilisée dans ce guide. Il renvoie une DataFrame de DataFrame contenant les données sur le revenu UCI de la scission indiqué échantillonné quel que soit le taux est indiqué (100% si non spécifié).
  • df_to_dataset : Cette fonction permet de convertir une DataFrame de tf.data.Dataset DataFrame dans un tf.data.Dataset tel que décrit dans ce guide avec la fonctionnalité supplémentaire d'être en mesure de passer le batch_size en tant que paramètre.
  • get_uci_with_min_diff_dataset : Cette fonction retourne un tf.data.Dataset contenant à la fois les données originales et les données mindiff tassées les unes contre l' aide du modèle d' assainissement bibliothèque util fonctions décrites dans ce guide.

Le reste des guides s'appuiera sur ceux-ci pour montrer comment utiliser d'autres parties de la bibliothèque.