MLコミュニティデーは11月9日です! TensorFlow、JAXからの更新のために私たちに参加し、より多くの詳細をご覧ください

MinDiffデータの準備

前書き

MinDiffを実装する場合、モデルに渡す前に、入力を選択して形成するときに複雑な決定を行う必要があります。これらの決定は、主にモデル内のMinDiffの動作を決定します。

このガイドでは、このプロセスの技術的な側面について説明しますが、モデルの公平性を評価する方法や、評価のために特定のスライスとメトリックを特定する方法については説明しません。詳細については、公平性指標のガイダンスを参照してください。

MinDiffを示すために、このガイドではUCI収入データセットを使用します。モデルタスクは、さまざまな個人属性に基づいて、個人の収入が5万ドルを超えるかどうかを予測することです。このガイドでは、 "Male" "Female"スライスと"Female"スライスの間のFNR(偽陰性率)に問題のあるギャップがあり、モデルの所有者(あなた)が問題に対処するためにMinDiffを適用することを決定したと想定しています。 MinDiffの適用を選択する可能性のあるシナリオの詳細については、 要件のページを参照して ください

MinDiffは、2つのデータセットの例間の分布スコアの違いにペナルティを課すことによって機能します。このガイドでは、これらの追加の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収入データセットのサンプル部分のみを使用します。実際の本番環境では、完全なデータセットが利用されます。

# 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へのtf.data.Dataset

MinDiffModel 、入力があることが必要tf.data.Dataset 。 MinDiffを統合する前に別の形式の入力を使用していた場合は、入力データを変換する必要があります。

tf.data.Dataset.from_tensor_slicesを使用して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)

2つの入力方法の同等性の詳細については、 Model.fitドキュメントを参照してください。

このガイドでは、入力はPandas DataFrameとしてダウンロードされるため、この変換が必要です。

# 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は、2つの追加データセット(元のデータセットの例を含む場合があります)間の予測の違いを減らすようにモデルを推奨します。これら2つのデータセットの選択は、MinDiffがモデルに与える影響を決定する重要な決定です。

2つのデータセットは、修正しようとしているパフォーマンスの不一致が明白でよく表されるように選択する必要があります。目標は"Male"スライスと"Female"スライスの間のFNRのギャップを減らすことであるため、これは、ポジティブラベルの"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データセットを作成することは完全に許容されます。

要件ガイダンスで推奨されている5,000以上の肯定的な"Male"例はありませんが、2,000を超えるため、さらにデータを収集する前に、その数を試してみるのが妥当です。

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に使用できる例の数が3倍以上になります。それはまだ低いですが、最初のパスとして試すのに十分です。

min_diff_female_ds = df_to_dataset(augmented_female_pos)

両方のMinDiffデータセットは、推奨される5,000以上の例よりも大幅に小さくなっています。現在のデータでMinDiffを適用することは合理的ですが、トレーニング中にパフォーマンスの低下や過剰適合が見られる場合は、追加のデータの収集を検討する必要があります。

tf.data.Dataset.filterを使用tf.data.Dataset.filter

または、変換された元のDatasetから直接2つのMinDiffデータセットを作成することもできます。

# 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_dsalternate_min_diff_female_dsは、出力がそれぞれmin_diff_male_dsmin_diff_female_dsmin_diff_female_dsます。

トレーニングデータセットの構築

最後のステップとして、3つのデータセット(新しく作成された2つのデータセットと元のデータセット)を、モデルに渡すことができる1つのデータセットにマージする必要があります。

データセットのバッチ処理

マージする前に、データセットをバッチ処理する必要があります。

  • 元のデータセットは、MinDiffを統合する前に使用されたものと同じバッチを使用できます。
  • MinDiffデータセットは、元のデータセットと同じバッチサイズである必要はありません。おそらく、小さい方でも同様に機能します。バッチサイズを同じにする必要はありませんが、最高のパフォーマンスを得るにはそうすることをお勧めします。

厳密には必要ではありませんが、2つのMinDiffデータセットにdrop_remainder=Trueを使用することをお勧めします。これにより、バッチサイズが一貫するようになります。

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たデータセットのpack_min_diff_data

データセットが準備されたら、それらを単一のデータセットにパックし、モデルに渡します。結果のデータセットからの単一のバッチには、前に準備した3つのデータセットのそれぞれからの1つのバッチが含まれます。

これを行うには、 tensorflow_model_remediationパッケージで提供されているutils関数を使用します。

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の統合から始まる他のガイドを見てください。

カスタムパッキングフォーマットの使用(オプション)

選択した方法で、3つのデータセットを一緒にパックすることを決定できます。唯一の要件は、モデルがデータの解釈方法を知っていることを確認する必要があることです。 MinDiffModelのデフォルトの実装では、データがmin_diff.keras.utils.pack_min_diff_dataを使用してパックされていることを前提としています。

入力を必要に応じてフォーマットする簡単な方法の1つは、 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 :この関数はこのガイドですでに使用されています。示されたレート(指定されていない場合は100%)でサンプリングされた、示されたスプリットからのUCI収入データを含むDataFrameを返します。
  • df_to_dataset :この関数は、このガイドで詳しく説明されているDataFrameに、tf.data.DatasetDataFrameに変換し、batch_sizeをパラメーターとして渡すことができる機能を追加します。
  • get_uci_with_min_diff_dataset :この関数は、このガイドで説明されているように、モデル修復ライブラリのutil関数を使用してパックされた元のデータとMinDiffデータの両方を含むtf.data.Datasetを返します。

残りのガイドは、ライブラリの他の部分の使用方法を示すために、これらを基に構築されます。