הכנת הנתונים של MinDiff

מבוא

בעת יישום MinDiff, תצטרך לקבל החלטות מורכבות תוך כדי בחירתך ולעצב את הקלט שלך לפני שתעביר אותו למודל. החלטות אלו יקבעו במידה רבה את ההתנהגות של MinDiff בתוך המודל שלך.

מדריך זה יכסה את ההיבטים הטכניים של תהליך זה, אך לא ידון כיצד להעריך מודל להוגנות, או כיצד לזהות פרוסות ומדדים מסוימים להערכה. עיין הדרכת מחווני גינות לפרטים על זה.

כדי להדגים MinDiff, מדריך זה עושה שימוש במערך הכנסת UCI . משימת המודל היא לחזות אם לאדם יש הכנסה העולה על 50 אלף דולר, בהתבסס על תכונות אישיות שונות. מדריך זה מניח קיים פער בעייתי FNR (שיעור שלילי כוזב) בין "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 תיעוד לפרטים על equivalences בין שתי השיטות של קלט.

במדריך זה, הקלט מורד כ-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 תעודד את המודל לצמצם הבדלים בתחזיות בין שני מערכי נתונים נוספים (שעשויים לכלול דוגמאות ממערך הנתונים המקורי). הבחירה של שני מערכי הנתונים הללו היא ההחלטה המרכזית שתקבע את ההשפעה של MinDiff על המודל.

יש לבחור את שני מערכי הנתונים כך שהפער בביצועים שאתה מנסה לתקן ברור ומיוצג היטב. מאחר והמטרה היא לצמצם פער FNR בין "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" דוגמאות, אך הם הרבה scarcer ב 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 קטנים משמעותית מ-5,000 הדוגמאות המומלצות או יותר. למרות שזה סביר לנסות להחיל את 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 פונקציות כמתואר במדריך זה.

שאר המדריכים יבנו מהם כדי להראות כיצד להשתמש בחלקים אחרים של הספרייה.