Подготовка данных MinDiff

Введение

При реализации MinDiff вам нужно будет принимать сложные решения по мере выбора и формы ввода, прежде чем передавать его в модель. Эти решения во многом будут определять поведение MinDiff в вашей модели.

В этом руководстве будут рассмотрены технические аспекты этого процесса, но не будет обсуждаться, как оценивать модель на предмет справедливости или как определять конкретные срезы и показатели для оценки. Пожалуйста , смотрите руководство Справедливость Индикаторы для подробной информации по этому вопросу .

Чтобы продемонстрировать MinDiff, это руководство использует доход набора данных UCI . Задача модели состоит в том, чтобы предсказать, имеет ли человек доход, превышающий 50 тысяч долларов, на основе различных личных качеств. Это руководство предполагает , что существует проблематичный разрыв в ПЗФЕ (ложный отрицательный) между "Male" и "Female" срезами и владельцем модели (вы) решили применить MinDiff для решения этой проблемы. Для получения дополнительной информации о сценариях , в которых можно было бы выбрать , чтобы применить MinDiff см страницы требования .

MinDiff работает, наказывая разницу в оценках распределения между примерами в двух наборах данных. Это руководство продемонстрирует, как выбрать и построить эти дополнительные наборы MinDiff, а также как упаковать все вместе, чтобы его можно было передать модели для обучения.

Настраивать

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

Исходные данные

В демонстрационных целях и для сокращения времени выполнения в этом руководстве используется только часть выборки набора данных UCI Income. В реальных производственных условиях будет использоваться полный набор данных.

# 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

Преобразование в tf.data.Dataset

MinDiffModel требует , чтобы входной быть tf.data.Dataset . Если вы использовали другой формат ввода до интеграции MinDiff, вам придется преобразовать ваши входные данные.

Используйте tf.data.Dataset.from_tensor_slices для преобразования tf.data.Dataset .

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

См Model.fit документации для получения подробной информации о эквивалентностях между этими двумя методами ввода.

В этом руководстве входные данные загружаются как фрейм данных Pandas и, следовательно, нуждаются в этом преобразовании.

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

Создание данных MinDiff

Во время обучения MinDiff будет стимулировать модель к уменьшению различий в прогнозах между двумя дополнительными наборами данных (которые могут включать примеры из исходного набора данных). Выбор этих двух наборов данных является ключевым решением, которое определит влияние MinDiff на модель.

Два набора данных следует выбирать таким образом, чтобы расхождение в производительности, которое вы пытаетесь исправить, было очевидным и хорошо представлено. Поскольку цель состоит в том, чтобы сократить разрыв в ПЗФЕ между "Male" и "Female" срезами, это означает создание одного набора данных с только положительно мечеными "Male" примерами , а в другом только положительно меченые "Female" примерах; это будут наборы данных MinDiff.

Сначала изучите имеющиеся данные.

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

Совершенно приемлемо создавать наборы данных MinDiff из подмножеств исходного набора данных.

Хотя существует не 5000 или более положительные "Male" примеры , как это рекомендовано в руководстве требований , существует более 2000 , и разумно , чтобы попытаться с этим многими до сбора дополнительных данных.

min_diff_male_ds = df_to_dataset(male_pos)

Положительные "Female" примеры, однако, гораздо более недостаточные на 385. Это, вероятно , слишком мало для хорошей производительности и поэтому потребует потянув дополнительные примеры.

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

Использование полного набора данных более чем утроило количество примеров, которые можно использовать для MinDiff. Он все еще низкий, но его достаточно попробовать в качестве первого прохода.

min_diff_female_ds = df_to_dataset(augmented_female_pos)

Оба набора данных MinDiff значительно меньше рекомендованных 5000 или более примеров. Хотя разумно попытаться применить MinDiff с текущими данными, вам может потребоваться рассмотреть возможность сбора дополнительных данных, если вы наблюдаете низкую производительность или переобучение во время обучения.

Использование tf.data.Dataset.filter

Кроме того , вы можете создать два набора данных MinDiff непосредственно из преобразованного оригинала 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()

Полученные alternate_min_diff_male_ds и alternate_min_diff_female_ds будут эквивалентны в выходе к min_diff_male_ds и min_diff_female_ds соответственно.

Создание набора данных для обучения

В качестве последнего шага три набора данных (два вновь созданных и исходный) необходимо объединить в один набор данных, который можно передать в модель.

Пакетирование наборов данных

Перед объединением наборы данных необходимо объединить в пакет.

  • Исходный набор данных может использовать то же пакетирование, которое использовалось до интеграции MinDiff.
  • Наборы данных MinDiff не обязательно должны иметь тот же размер пакета, что и исходный набор данных. Скорее всего, меньший по размеру подойдет. Хотя им даже не обязательно иметь одинаковый размер пакета, рекомендуется сделать это для лучшей производительности.

Хотя не является строго необходимым, рекомендуется использование drop_remainder=True для двух наборов данных MinDiff как это будет гарантировать , что они имеют согласованные размеры партии.

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)

Упаковка наборов данных с pack_min_diff_data

После подготовки наборов данных упакуйте их в один набор данных, который затем будет передан в модель. Один пакет из результирующего набора данных будет содержать по одному пакету из каждого из трех наборов данных, которые вы подготовили ранее.

Вы можете сделать это, используя прилагаемое utils функцию в tensorflow_model_remediation упаковке:

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)

И это все! Вы сможете использовать другие util функции в пакете для распаковки отдельных партий , если это необходимо.

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)

Теперь, когда ваши вновь сформированные данные готовы к применению MinDiff в вашей модели! Чтобы узнать , как это делается, пожалуйста, посмотрите на другие руководства , начиная с Интегрирование MinDiff с MinDiffModel .

Использование специального формата упаковки (необязательно)

Вы можете решить объединить три набора данных любым способом. Единственное требование - убедиться, что модель знает, как интерпретировать данные. Реализация по умолчанию MinDiffModel предполагает , что данные были упакованы с использованием min_diff.keras.utils.pack_min_diff_data .

Один простой способ форматирования ввода , как вы хотите, чтобы преобразовать данные в качестве конечной стадии после того, как вы использовали 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)

Ваша модель нужно будет знать , как читать этот настроенный вход , как описано в руководстве Настройка 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']

Дополнительные ресурсы

В этом руководстве описывается процесс и процесс принятия решений, которым вы можете следовать при применении MinDiff. Остальные руководства строятся на этой основе. Чтобы упростить эту задачу, логика, представленная в этом руководстве, была вынесена на вспомогательные функции:

  • get_uci_data : Эта функция уже используется в данном руководстве. Она возвращает DataFrame , содержащий данные доходы UCI от указанного разделения сэмпл на любой скорости указывается (100% , если не указано).
  • df_to_dataset : Эта функция преобразует DataFrame в tf.data.Dataset , как подробно описано в данном руководстве с дополнительной функциональностью , чтобы быть в состоянии передать batch_size в качестве параметра.
  • get_uci_with_min_diff_dataset : Эта функция возвращает tf.data.Dataset , содержащее как исходные данные , так и данные MinDiff упакованной вместе с использованием моделью Remediation библиотеки Util функций , как описано в данном руководстве.

Остальные руководства будут построены на их основе, чтобы показать, как использовать другие части библиотеки.