דוגמה לאופטימיזציה מוגבלת של TensorFlow באמצעות מערך נתונים של CelebA

הצג באתר TensorFlow.org הפעל בגוגל קולאב הצג ב-GitHub הורד מחברת

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

  • רכבת פשוטה, מודל רשת עצבית מאולצת לזהות חיוך של אדם תמונות באמצעות tf.keras ואת CelebFaces בקנה מידה גדול מאפיינים ( CelebA במערך).
  • הערך את ביצועי המודל מול מדד הוגנות נפוץ בין קבוצות גיל, באמצעות מדדי הוגנות.
  • הגדר בעיית אופטימיזציה מוגבלת פשוטה כדי להשיג ביצועים הוגנים יותר בקבוצות גיל.
  • שוב על תבנית חברה המוגבלת והערכה של ביצועים שוב, להבטיח כי מדד ההגינות הנבחרת שלנו השתפר.

עדכון אחרון: 3/11 בפברואר 2020

הַתקָנָה

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

שים לב שבפעם הראשונה שאתה מפעיל את התקנות ה-pip, ייתכן שתתבקש להפעיל מחדש את זמן הריצה בגלל חבילות לא מעודכנות שהותקנו מראש. לאחר שתעשה זאת, נעשה שימוש בחבילות הנכונות.

התקנת Pip

שים לב שבהתאם למועד הפעלת התא למטה, ייתכן שתקבל אזהרה על גירסת ברירת המחדל של TensorFlow ב-Colab שעוברת ל-TensorFlow 2.X בקרוב. אתה יכול להתעלם בבטחה מהאזהרה הזו שכן מחברת זו תוכננה להיות תואמת ל-TensorFlow 1.X ו-2.X.

ייבוא ​​מודולים

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

למרות ש-TFCO תואם לביצוע להוט ולביצוע גרפים, מחברת זו מניחה שביצוע להוט מופעל כברירת מחדל כפי שהוא ב-TensorFlow 2.x. כדי להבטיח ששום דבר לא יישבר, הפעלה להוט תתאפשר בתא שלמטה.

אפשר ביצוע להוט וגרסאות הדפסה

Eager execution enabled by default.
TensorFlow 2.8.0-rc0
TFMA 0.36.0
TFDS 4.4.0
FI 0.36.0

מערך נתונים של CelebA

CelebA הוא פרצוף בקנה מידה גדול מייחס במערך עם יותר מ 200,000 תמונות הסלבריטאים, כל אחד עם 40 ביאורים תכונה (כגון סוג שיער, אביזרי אופנה, תווי פנים, וכו ') ו 5 מקומות ציון דרך (העיניים, הפה ואת האף עמדות). לפרטים נוספים יסתכלו בעיתון . עם אישור של בעלי, יש לנו מאוחסן במערך זה ב- Google Cloud Storage ובעיקר לגשת אליו באמצעות TensorFlow מערכי נתונים ( tfds ) .

במחברת זו:

  • המודל שלנו ינסה לסווג אם הנושא של התמונה הוא מחייך, כפי שהוא מיוצג על ידי * תכונה "מחייכת".
  • גודל התמונות ישתנה מ-218x178 ל-28x28 כדי לצמצם את זמן הביצוע והזיכרון בזמן האימון.
  • ביצועי המודל שלנו יוערכו על פני קבוצות גיל, באמצעות התכונה הבינארית "צעיר". נכנה זאת במחברת זו "קבוצת גיל".

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

gcs_base_dir = "gs://celeb_a_dataset/"
celeb_a_builder = tfds.builder("celeb_a", data_dir=gcs_base_dir, version='2.0.0')

celeb_a_builder.download_and_prepare()

num_test_shards_dict = {'0.3.0': 4, '2.0.0': 2} # Used because we download the test dataset separately
version = str(celeb_a_builder.info.version)
print('Celeb_A dataset version: %s' % version)
Celeb_A dataset version: 2.0.0

בדוק את פונקציות העזר של מערך הנתונים

אזהרות

לפני שמתקדמים קדימה, יש לזכור מספר שיקולים בשימוש ב- CelebA:

  • למרות שבאופן עקרוני המחברת הזו יכולה להשתמש בכל מערך נתונים של תמונות פנים, CelebA נבחרה מכיוון שהיא מכילה תמונות ברשות הרבים של אישי ציבור.
  • כל ההערות לתכונות ב- CelebA מופעלות כקטגוריות בינאריות. לדוגמה, התכונה "צעיר" (כפי שנקבע על ידי תוויות מערך הנתונים) מסומנת כנוכחת או נעדרת בתמונה.
  • הסיווגים של CelebA אינם משקפים מגוון אנושי אמיתי של תכונות.
  • למטרות מחברת זו, התכונה המכילה את התכונה "צעיר" מכונה "קבוצת גיל", כאשר הנוכחות של התכונה "צעיר" בתמונה מסומנת כחבר בקבוצת הגיל "צעיר" ו- היעדר התכונה "צעיר" מתויג כחבר בקבוצת הגיל "לא צעיר". אלו הן ההנחות כפי מידע זה אינו מוזכר במאמר המקורי .
  • ככזה, הביצועים במודלים שהוכשרו במחברת זו קשורים לדרכים שבהן התכונות הופעלו והוסרו על ידי מחברי CelebA.
  • מודל זה לא אמור לשמש למטרות מסחריות כמו אשר יפר את הסכם המחקר לא המסחרי של CelebA .

הגדרת פונקציות קלט

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

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

הגדר משתנים

הגדר פונקציות עיבוד מוקדם

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

# Train data returning either 2 or 3 elements (the third element being the group)
def celeb_a_train_data_wo_group(batch_size):
  celeb_a_train_data = celeb_a_builder.as_dataset(split='train').shuffle(1024).repeat().batch(batch_size).map(preprocess_input_dict)
  return celeb_a_train_data.map(get_image_and_label)
def celeb_a_train_data_w_group(batch_size):
  celeb_a_train_data = celeb_a_builder.as_dataset(split='train').shuffle(1024).repeat().batch(batch_size).map(preprocess_input_dict)
  return celeb_a_train_data.map(get_image_label_and_group)

# Test data for the overall evaluation
celeb_a_test_data = celeb_a_builder.as_dataset(split='test').batch(1).map(preprocess_input_dict).map(get_image_label_and_group)
# Copy test data locally to be able to read it into tfma
copy_test_files_to_local()

בנה מודל DNN פשוט

בגלל המחברת הזאת מתמקדת TFCO, נוכל להרכיב פשוט, מאולץ tf.keras.Sequential מודל.

אולי נוכל לשפר מאוד את ביצועי המודל על ידי הוספת מורכבות מסוימת (למשל, שכבות מחוברות יותר, חקר פונקציות הפעלה שונות, הגדלת גודל התמונה), אבל זה עשוי להסיח את הדעת מהמטרה להדגים כמה קל ליישם את ספריית TFCO כאשר עובדים עם Keras. מסיבה זו, הדגם יישמר פשוט - אבל תרגישו מעודדים לחקור את החלל הזה.

def create_model():
  # For this notebook, accuracy will be used to evaluate performance.
  METRICS = [
    tf.keras.metrics.BinaryAccuracy(name='accuracy')
  ]

  # The model consists of:
  # 1. An input layer that represents the 28x28x3 image flatten.
  # 2. A fully connected layer with 64 units activated by a ReLU function.
  # 3. A single-unit readout layer to output real-scores instead of probabilities.
  model = keras.Sequential([
      keras.layers.Flatten(input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3), name='image'),
      keras.layers.Dense(64, activation='relu'),
      keras.layers.Dense(1, activation=None)
  ])

  # TFCO by default uses hinge loss — and that will also be used in the model.
  model.compile(
      optimizer=tf.keras.optimizers.Adam(0.001),
      loss='hinge',
      metrics=METRICS)
  return model

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

def set_seeds():
  np.random.seed(121212)
  tf.compat.v1.set_random_seed(212121)

מדדי הוגנות פונקציות עוזרות

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

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

def save_model(model, subdir):
  base_dir = tempfile.mkdtemp(prefix='saved_models')
  model_location = os.path.join(base_dir, subdir)
  model.save(model_location, save_format='tf')
  return model_location

לאחר מכן, אנו מגדירים פונקציות המשמשות לעיבוד מוקדם של הנתונים על מנת להעביר אותם בצורה נכונה ל-TFMA.

פונקציות עיבוד מוקדם של נתונים עבור

לבסוף, אנו מגדירים פונקציה שמעריכה את התוצאות ב-TFMA.

def get_eval_results(model_location, eval_subdir):
  base_dir = tempfile.mkdtemp(prefix='saved_eval_results')
  tfma_eval_result_path = os.path.join(base_dir, eval_subdir)

  eval_config_pbtxt = """
        model_specs {
          label_key: "%s"
        }
        metrics_specs {
          metrics {
            class_name: "FairnessIndicators"
            config: '{ "thresholds": [0.22, 0.5, 0.75] }'
          }
          metrics {
            class_name: "ExampleCount"
          }
        }
        slicing_specs {}
        slicing_specs { feature_keys: "%s" }
        options {
          compute_confidence_intervals { value: False }
          disabled_outputs{values: "analysis"}
        }
      """ % (LABEL_KEY, GROUP_KEY)

  eval_config = text_format.Parse(eval_config_pbtxt, tfma.EvalConfig())

  eval_shared_model = tfma.default_eval_shared_model(
        eval_saved_model_path=model_location, tags=[tf.saved_model.SERVING])

  schema_pbtxt = """
        tensor_representation_group {
          key: ""
          value {
            tensor_representation {
              key: "%s"
              value {
                dense_tensor {
                  column_name: "%s"
                  shape {
                    dim { size: 28 }
                    dim { size: 28 }
                    dim { size: 3 }
                  }
                }
              }
            }
          }
        }
        feature {
          name: "%s"
          type: FLOAT
        }
        feature {
          name: "%s"
          type: FLOAT
        }
        feature {
          name: "%s"
          type: BYTES
        }
        """ % (IMAGE_KEY, IMAGE_KEY, IMAGE_KEY, LABEL_KEY, GROUP_KEY)
  schema = text_format.Parse(schema_pbtxt, schema_pb2.Schema())
  coder = tf_example_record.TFExampleBeamRecord(
      physical_format='inmem', schema=schema,
      raw_record_column_name=tfma.ARROW_INPUT_COLUMN)
  tensor_adapter_config = tensor_adapter.TensorAdapterConfig(
    arrow_schema=coder.ArrowSchema(),
    tensor_representations=coder.TensorRepresentations())
  # Run the fairness evaluation.
  with beam.Pipeline() as pipeline:
    _ = (
          tfds_as_pcollection(pipeline, 'celeb_a', 'test')
          | 'ExamplesToRecordBatch' >> coder.BeamSource()
          | 'ExtractEvaluateAndWriteResults' >>
          tfma.ExtractEvaluateAndWriteResults(
              eval_config=eval_config,
              eval_shared_model=eval_shared_model,
              output_path=tfma_eval_result_path,
              tensor_adapter_config=tensor_adapter_config)
    )
  return tfma.load_eval_result(output_path=tfma_eval_result_path)

אימון והערכת מודל בלתי מוגבל

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

הערה כי ריצה מחברת זה TensorFlow <2.0.0 עשויה לגרור אזהרה בזויה עבור np.where . להתעלם מאזהרה זו כפי TensorFlow כתובות זה 2.X באמצעות tf.where במקום np.where .

BATCH_SIZE = 32

# Set seeds to get reproducible results
set_seeds()

model_unconstrained = create_model()
model_unconstrained.fit(celeb_a_train_data_wo_group(BATCH_SIZE), epochs=5, steps_per_epoch=1000)
Epoch 1/5
1000/1000 [==============================] - 12s 6ms/step - loss: 0.5038 - accuracy: 0.7733
Epoch 2/5
1000/1000 [==============================] - 7s 7ms/step - loss: 0.3800 - accuracy: 0.8301
Epoch 3/5
1000/1000 [==============================] - 6s 6ms/step - loss: 0.3598 - accuracy: 0.8427
Epoch 4/5
1000/1000 [==============================] - 25s 25ms/step - loss: 0.3435 - accuracy: 0.8474
Epoch 5/5
1000/1000 [==============================] - 5s 5ms/step - loss: 0.3402 - accuracy: 0.8479
<keras.callbacks.History at 0x7f0f5c476350>

הערכת המודל על נתוני המבחן אמורה להביא לציון דיוק סופי של קצת יותר מ-85%. לא רע לדגם פשוט ללא כוונון עדין.

print('Overall Results, Unconstrained')
celeb_a_test_data = celeb_a_builder.as_dataset(split='test').batch(1).map(preprocess_input_dict).map(get_image_label_and_group)
results = model_unconstrained.evaluate(celeb_a_test_data)
Overall Results, Unconstrained
19962/19962 [==============================] - 50s 2ms/step - loss: 0.2125 - accuracy: 0.8636

עם זאת, ביצועים המוערכים על פני קבוצות גיל עשויים לחשוף כמה חסרונות.

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

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

model_location = save_model(model_unconstrained, 'model_export_unconstrained')
eval_results_unconstrained = get_eval_results(model_location, 'eval_results_unconstrained')
2022-01-07 18:46:05.881112: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/saved_modelswhxcqdry/model_export_unconstrained/assets
INFO:tensorflow:Assets written to: /tmp/saved_modelswhxcqdry/model_export_unconstrained/assets
WARNING:apache_beam.runners.interactive.interactive_environment:Dependencies required for Interactive Beam PCollection visualization are not available, please use: `pip install apache-beam[interactive]` to install necessary dependencies to enable all data visualization features.
WARNING:root:Make sure that locally built Python SDK docker image has Python 3.7 interpreter.
WARNING:apache_beam.io.tfrecordio:Couldn't find python-snappy so the implementation of _TFRecordUtil._masked_crc32c is not as fast as it could be.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_model_analysis/writers/metrics_plots_and_validations_writer.py:107: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.
Instructions for updating:
Use eager execution and: 
`tf.data.TFRecordDataset(path)`
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_model_analysis/writers/metrics_plots_and_validations_writer.py:107: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.
Instructions for updating:
Use eager execution and: 
`tf.data.TFRecordDataset(path)`

כפי שצוין לעיל, אנו מתרכזים בשיעור חיובי כוזב. הגרסה הנוכחית של אינדיקטורים להוגנות (0.1.2) בוחרת שיעור שלילי כוזב כברירת מחדל. לאחר הפעלת השורה למטה, בטל את הבחירה ב-false_negative_rate ובחר ב-false_positive_rate כדי להסתכל על המדד שאנו מעוניינים בו.

tfma.addons.fairness.view.widget_view.render_fairness_indicator(eval_results_unconstrained)
FairnessIndicatorViewer(slicingMetrics=[{'sliceValue': 'Young', 'slice': 'Young:Young', 'metrics': {'example_c…

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

זה המקום שבו TFCO יכול לעזור על ידי הגבלת השיעור חיובי כוזב להיות בתוך קריטריון מקובל יותר.

הגדרת דגם מוגבל

כפי שתועד הספרייה של TFCO , ישנם מספר עוזרים כי יקלו על מנת להגביל את הבעיה:

  1. tfco.rate_context() - זה מה ישמש בניית אילוץ עבור כל קטגוריה קבוצת גיל.
  2. tfco.RateMinimizationProblem() - ביטוי השיעור כדי למזער כאן יהיה נושא השיעור החיובי הכוזב כדי בקבוצת גיל. במילים אחרות, הביצועים כעת יוערכו על סמך ההבדל בין שיעורי החיוב השגויים של קבוצת הגיל לזה של מערך הנתונים הכולל. עבור הדגמה זו, שיעור חיובי שווא של פחות או שווה ל-5% ייקבע כאילוץ.
  3. tfco.ProxyLagrangianOptimizerV2() - זהו עוזר כי למעשה יפתור את הבעיה אילוץ שיעור.

התא להלן יקרא לעוזרים אלה להקים הכשרה למודלים עם אילוץ ההגינות.

# The batch size is needed to create the input, labels and group tensors.
# These tensors are initialized with all 0's. They will eventually be assigned
# the batch content to them. A large batch size is chosen so that there are
# enough number of "Young" and "Not Young" examples in each batch.
set_seeds()
model_constrained = create_model()
BATCH_SIZE = 32

# Create input tensor.
input_tensor = tf.Variable(
    np.zeros((BATCH_SIZE, IMAGE_SIZE, IMAGE_SIZE, 3), dtype="float32"),
    name="input")

# Create labels and group tensors (assuming both labels and groups are binary).
labels_tensor = tf.Variable(
    np.zeros(BATCH_SIZE, dtype="float32"), name="labels")
groups_tensor = tf.Variable(
    np.zeros(BATCH_SIZE, dtype="float32"), name="groups")

# Create a function that returns the applied 'model' to the input tensor
# and generates constrained predictions.
def predictions():
  return model_constrained(input_tensor)

# Create overall context and subsetted context.
# The subsetted context contains subset of examples where group attribute < 1
# (i.e. the subset of "Not Young" celebrity images).
# "groups_tensor < 1" is used instead of "groups_tensor == 0" as the former
# would be a comparison on the tensor value, while the latter would be a
# comparison on the Tensor object.
context = tfco.rate_context(predictions, labels=lambda:labels_tensor)
context_subset = context.subset(lambda:groups_tensor < 1)

# Setup list of constraints.
# In this notebook, the constraint will just be: FPR to less or equal to 5%.
constraints = [tfco.false_positive_rate(context_subset) <= 0.05]

# Setup rate minimization problem: minimize overall error rate s.t. constraints.
problem = tfco.RateMinimizationProblem(tfco.error_rate(context), constraints)

# Create constrained optimizer and obtain train_op.
# Separate optimizers are specified for the objective and constraints
optimizer = tfco.ProxyLagrangianOptimizerV2(
      optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
      constraint_optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
      num_constraints=problem.num_constraints)

# A list of all trainable variables is also needed to use TFCO.
var_list = (model_constrained.trainable_weights + list(problem.trainable_variables) +
            optimizer.trainable_variables())

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

עכשיו, מכיוון איטרציה האחרונה של המודל המאולץ אינה בהכרח מודל הביצועים הטוב ביותר במונחים של האילוץ המוגדר, ספריית TFCO מגיעה מאובזרת עם tfco.find_best_candidate_index() כי עזרה יכול לבחור את המיטב ומדגיש של אלה שנמצאו לאחר כול תְקוּפָה. תחשוב tfco.find_best_candidate_index() כמו היוריסטיקה הוסיף כי מדרג כל התוצאות מבוסס על דיוק אילוץ הגינות (במקרה זה, שיעור חיובי כוזב על פני קבוצת גיל) בנפרד לגבי הנתונים הכשרה. כך, הוא יכול לחפש פשרה טובה יותר בין הדיוק הכולל לבין מגבלת ההגינות.

התאים הבאים יתחילו את האימון עם אילוצים תוך מציאת המודל בעל הביצועים הטובים ביותר בכל איטרציה.

# Obtain train set batches.

NUM_ITERATIONS = 100  # Number of training iterations.
SKIP_ITERATIONS = 10  # Print training stats once in this many iterations.

# Create temp directory for saving snapshots of models.
temp_directory = tempfile.mktemp()
os.mkdir(temp_directory)

# List of objective and constraints across iterations.
objective_list = []
violations_list = []

# Training iterations.
iteration_count = 0
for (image, label, group) in celeb_a_train_data_w_group(BATCH_SIZE):
  # Assign current batch to input, labels and groups tensors.
  input_tensor.assign(image)
  labels_tensor.assign(label)
  groups_tensor.assign(group)

  # Run gradient update.
  optimizer.minimize(problem, var_list=var_list)

  # Record objective and violations.
  objective = problem.objective()
  violations = problem.constraints()

  sys.stdout.write(
      "\r Iteration %d: Hinge Loss = %.3f, Max. Constraint Violation = %.3f"
      % (iteration_count + 1, objective, max(violations)))

  # Snapshot model once in SKIP_ITERATIONS iterations.
  if iteration_count % SKIP_ITERATIONS == 0:
    objective_list.append(objective)
    violations_list.append(violations)

    # Save snapshot of model weights.
    model_constrained.save_weights(
        temp_directory + "/celeb_a_constrained_" +
        str(iteration_count / SKIP_ITERATIONS) + ".h5")

  iteration_count += 1
  if iteration_count >= NUM_ITERATIONS:
    break

# Choose best model from recorded iterates and load that model.
best_index = tfco.find_best_candidate_index(
    np.array(objective_list), np.array(violations_list))

model_constrained.load_weights(
    temp_directory + "/celeb_a_constrained_" + str(best_index) + ".0.h5")

# Remove temp directory.
os.system("rm -r " + temp_directory)
Iteration 100: Hinge Loss = 0.614, Max. Constraint Violation = 0.268
0

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

model_location = save_model(model_constrained, 'model_export_constrained')
eval_result_constrained = get_eval_results(model_location, 'eval_results_constrained')
INFO:tensorflow:Assets written to: /tmp/saved_modelsbztxt9fy/model_export_constrained/assets
INFO:tensorflow:Assets written to: /tmp/saved_modelsbztxt9fy/model_export_constrained/assets
WARNING:root:Make sure that locally built Python SDK docker image has Python 3.7 interpreter.

כמו בפעם הקודמת שהשתמשנו באינדיקטורים של הוגנות, בטל את הבחירה ב-false_negative_rate ובחר false_positive_rate כדי להסתכל על המדד שאנו מעוניינים בו.

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

eval_results_dict = {
    'constrained': eval_result_constrained,
    'unconstrained': eval_results_unconstrained,
}
tfma.addons.fairness.view.widget_view.render_fairness_indicator(multi_eval_results=eval_results_dict)
FairnessIndicatorViewer(evalName='constrained', evalNameCompare='unconstrained', slicingMetrics=[{'sliceValue'…

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