Przygotowanie danych MinDiff

Wstęp

Podczas wdrażania MinDiff będziesz musiał podejmować złożone decyzje podczas wybierania i kształtowania danych wejściowych przed przekazaniem ich do modelu. Decyzje te w dużej mierze zdeterminują zachowanie MinDiff w twoim modelu.

W tym przewodniku zostaną omówione techniczne aspekty tego procesu, ale nie zostaną omówione, jak ocenić model pod kątem rzetelności ani jak zidentyfikować poszczególne wycinki i metryki do oceny. Proszę zobaczyć wskazówki Fairness Wskaźniki szczegółowe informacje na ten temat.

Aby zademonstrować MinDiff, ten poradnik wykorzystuje dochodowego zestawu danych UCI . Zadaniem modelu jest przewidywanie, czy dana osoba ma dochód przekraczający 50 tys. USD, na podstawie różnych cech osobistych. Podręcznik ten zakłada, jest problematyczne luka w FNR (false wskaźnik ujemny) pomiędzy "Male" i "Female" plasterki i właściciel modelu (ty) zdecydowała się na zastosowanie MinDiff w celu rozwiązania problemu. Aby uzyskać więcej informacji na temat scenariuszy, w których można się wybrać do zastosowania MinDiff, zobacz stronę wymagania .

MinDiff działa poprzez karanie różnicy w wynikach dystrybucji między przykładami w dwóch zestawach danych. Ten przewodnik pokaże, jak wybrać i skonstruować te dodatkowe zestawy MinDiff, a także jak spakować wszystko razem, aby można je było przekazać do modelu do treningu.

Ustawiać

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

Oryginalne dane

W celach demonstracyjnych i w celu skrócenia czasu działania, w tym przewodniku wykorzystano tylko część próbki zbioru danych UCI Income. W rzeczywistym środowisku produkcyjnym wykorzystany byłby pełny zestaw danych.

# 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

Konwersja do tf.data.Dataset

MinDiffModel wymaga, że wejście będzie tf.data.Dataset . Jeśli przed integracją MinDiff używałeś innego formatu danych wejściowych, będziesz musiał przekonwertować swoje dane wejściowe.

Stosować tf.data.Dataset.from_tensor_slices przekonwertować do tf.data.Dataset .

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

Zobacz Model.fit dokumentacji szczegóły na temat równoważności tych dwóch metod wejścia.

W tym przewodniku dane wejściowe są pobierane jako Pandas DataFrame i dlatego wymagają tej konwersji.

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

Tworzenie danych MinDiff

Podczas szkolenia MinDiff zachęci model do zmniejszenia różnic w przewidywaniach między dwoma dodatkowymi zestawami danych (które mogą zawierać przykłady z oryginalnego zestawu danych). Wybór tych dwóch zbiorów danych jest kluczową decyzją, która określi wpływ MinDiff na model.

Te dwa zestawy danych powinny być wybrane w taki sposób, aby rozbieżność w wydajności, którą próbujesz zaradzić, była ewidentna i dobrze reprezentowana. Ponieważ celem jest zmniejszenie luki w FNR między "Male" i "Female" plasterki, oznacza to utworzenie jednego zestawu danych z tylko pozytywnie oznakowanych "Male" przykładów, aw drugim tylko pozytywnie oznakowanych "Female" przykładów; będą to zbiory danych MinDiff.

Najpierw zbadaj obecne dane.

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

Całkowicie dopuszczalne jest tworzenie zestawów danych MinDiff z podzbiorów oryginalnego zestawu danych.

Chociaż nie są 5000 lub bardziej pozytywne "Male" przykłady jak zalecane w wytycznych wymagań , istnieje ponad 2000 i to jest rozsądne, aby spróbować się, że wiele przed zebraniem większej ilości danych.

min_diff_male_ds = df_to_dataset(male_pos)

Pozytywne "Female" przykłady są jednak znacznie rzadziej na 385. Jest to prawdopodobnie zbyt mały dla dobrych osiągów i tak będzie wymagało ciągnięcie dodatkowych przykładach.

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

Korzystanie z pełnego zestawu danych zwiększyło ponad trzykrotnie liczbę przykładów, które można wykorzystać w MinDiff. Nadal jest niski, ale wystarczy spróbować jako pierwszy przejazd.

min_diff_female_ds = df_to_dataset(augmented_female_pos)

Oba zestawy danych MinDiff są znacznie mniejsze niż zalecane 5000 lub więcej przykładów. Chociaż rozsądne jest próbowanie zastosowania MinDiff z bieżącymi danymi, może być konieczne rozważenie zebrania dodatkowych danych, jeśli zauważysz słabą wydajność lub nadmierne dopasowanie podczas treningu.

Korzystanie tf.data.Dataset.filter

Alternatywnie, można utworzyć dwa zestawy danych MinDiff bezpośrednio z przebudowanej oryginałem 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()

Powstałe alternate_min_diff_male_ds i alternate_min_diff_female_ds będzie odpowiadać na wyjściu do min_diff_male_ds i min_diff_female_ds odpowiednio.

Konstruowanie zestawu danych treningowych

W ostatnim kroku trzy zestawy danych (dwa nowo utworzone i oryginalny) muszą zostać połączone w jeden zestaw danych, który można przekazać do modelu.

Grupowanie zbiorów danych

Przed scaleniem zestawy danych muszą zostać zgrupowane.

  • Oryginalny zestaw danych może używać tego samego przetwarzania wsadowego, które było używane przed integracją MinDiff.
  • Zestawy danych MinDiff nie muszą mieć tego samego rozmiaru partii, co oryginalny zestaw danych. Najprawdopodobniej mniejszy sprawdzi się równie dobrze. Chociaż nie muszą nawet mieć tej samej wielkości partii, zaleca się, aby to zrobić, aby uzyskać najlepszą wydajność.

O ile nie jest to bezwzględnie konieczne, zaleca się stosowanie drop_remainder=True dla dwóch zestawów danych MinDiff jak to będzie upewnić się, że mają one spójne wielkości partii.

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)

Pakowania zestawów danych przy pack_min_diff_data

Po przygotowaniu zestawów danych spakuj je w jeden zestaw danych, który następnie zostanie przekazany do modelu. Pojedyncza partia z wynikowego zestawu danych będzie zawierać jedną partię z każdego z trzech przygotowanych wcześniej zestawów danych.

Można to zrobić za pomocą dostarczonego utils funkcję w tensorflow_model_remediation opakowaniu:

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)

I to wszystko! Będziesz mógł korzystać z innych util funkcje w pakiecie rozpakować poszczególnych partii w razie potrzeby.

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)

Dzięki nowo utworzonym danym możesz teraz zastosować MinDiff w swoim modelu! Aby dowiedzieć się, jak to zrobić, proszę zapoznać się z innymi przewodnikami zaczynających się Integracja MinDiff z MinDiffModel .

Korzystanie z niestandardowego formatu pakowania (opcjonalnie)

Możesz zdecydować się na spakowanie trzech zestawów danych razem w dowolny sposób. Jedynym wymaganiem jest upewnienie się, że model wie, jak interpretować dane. Domyślna implementacja MinDiffModel zakłada, że dane zostały zapakowane stosując min_diff.keras.utils.pack_min_diff_data .

Jeden prosty sposób formatować dane wejściowe, jak chcesz jest przekształcenie danych w końcowym etapie po użyłeś 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)

Twój model będzie trzeba wiedzieć, jak czytać ten dostosowane wejście jak opisano w przewodniku Dostosowywanie 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']

Dodatkowe zasoby

Ten przewodnik przedstawia proces i podejmowanie decyzji, którymi możesz się kierować za każdym razem, gdy stosujesz MinDiff. Reszta przewodników opiera się na tej strukturze. Aby to ułatwić, logika znaleziona w tym przewodniku została uwzględniona w funkcjach pomocniczych:

  • get_uci_data : Ta funkcja jest już używany w niniejszym przewodniku. Zwraca DataFrame zawierający dane dochody UCI ze wskazanej próbą rozłamu na cokolwiek stawka jest wskazane (100% jeśli nieokreślone).
  • df_to_dataset : Funkcja ta przekształca DataFrame do tf.data.Dataset , jak określono w tym podręczniku dodatkową funkcjonalność jest w stanie przekazać batch_size jako parametr.
  • get_uci_with_min_diff_dataset : powraca Ten funkcyjne a tf.data.Dataset zawierający zarówno oryginalne dane i dane MinDiff pakowane razem stosując model rekultywacją Biblioteka util funkcji opisanych w niniejszej instrukcji.

Pozostałe przewodniki opracują je, aby pokazać, jak korzystać z innych części biblioteki.