يوم مجتمع ML هو 9 نوفمبر! الانضمام إلينا للحصول على التحديثات من TensorFlow، JAX، وأكثر معرفة المزيد

دراسة حالة نموذجية للعلاج

في دفتر الملاحظات هذا ، سنقوم بتدريب مصنف نصوص لتحديد المحتوى المكتوب الذي يمكن اعتباره سامًا أو ضارًا ، وسنطبق MinDiff لمعالجة بعض مخاوف الإنصاف. في سير العمل لدينا ، سوف نقوم بما يلي:

  1. قم بتقييم أداء النموذج الأساسي الخاص بنا على النص الذي يحتوي على مراجع لمجموعات حساسة.
  2. قم بتحسين الأداء في أي مجموعة ضعيفة الأداء من خلال التدريب باستخدام MinDiff.
  3. قم بتقييم أداء النموذج الجديد على المقياس الذي اخترناه.

هدفنا هو إظهار استخدام تقنية MinDiff بأقل قدر من سير العمل ، وليس لوضع نهج مبدئي للعدالة في التعلم الآلي. على هذا النحو ، سيركز تقييمنا فقط على فئة حساسة واحدة ومقياس واحد. كما أننا لا نعالج أوجه القصور المحتملة في مجموعة البيانات ، ولا نضبط تكويناتنا. في بيئة الإنتاج ، قد ترغب في التعامل مع كل منها بصرامة. لمزيد من المعلومات حول التقييم من أجل الإنصاف ، راجع هذا الدليل .

يثبت

نبدأ بتثبيت مؤشرات الإنصاف و TensorFlow Model Remediation.

التثبيتات

استيراد جميع المكونات الضرورية ، بما في ذلك MinDiff ومؤشرات الإنصاف للتقييم.

الواردات

نستخدم وظيفة الأداة المساعدة لتنزيل البيانات المعالجة مسبقًا وإعداد الملصقات لتتناسب مع شكل إخراج النموذج. تقوم الوظيفة أيضًا بتنزيل البيانات كسجلات TFR لجعل التقييم اللاحق أسرع. بدلاً من ذلك ، يمكنك تحويل Pandas DataFrame إلى سجلات TFR مع أي وظيفة تحويل فائدة متاحة.

# We use a helper utility to preprocessed data for convenience and speed.
data_train, data_validate, validate_tfrecord_file, labels_train, labels_validate = min_diff_keras_utils.download_and_process_civil_comments_data()
Downloading data from https://storage.googleapis.com/civil_comments_dataset/train_df_processed.csv
345702400/345699197 [==============================] - 8s 0us/step
Downloading data from https://storage.googleapis.com/civil_comments_dataset/validate_df_processed.csv
229974016/229970098 [==============================] - 5s 0us/step
Downloading data from https://storage.googleapis.com/civil_comments_dataset/validate_tf_processed.tfrecord
324943872/324941336 [==============================] - 9s 0us/step

نحدد بعض الثوابت المفيدة. سنقوم بتدريب النموذج على ميزة 'comment_text' ، مع تسمية هدفنا باسم 'toxicity' . لاحظ أنه يتم اختيار حجم الدُفعة هنا بشكل عشوائي ، ولكن في إعداد الإنتاج ، ستحتاج إلى ضبطه للحصول على أفضل أداء.

TEXT_FEATURE = 'comment_text'
LABEL = 'toxicity'
BATCH_SIZE = 512

ضع بذور عشوائية. (لاحظ أن هذا لا يؤدي إلى استقرار النتائج بشكل كامل).

بذور

تحديد النموذج الأساسي وتدريبه

لتقليل وقت التشغيل ، نستخدم نموذجًا تم اختباره مسبقًا بشكل افتراضي. إنه نموذج تسلسلي بسيط من Keras مع طبقات التضمين والالتفاف الأولي ، مما ينتج عنه تنبؤ بالسمية. إذا كنت تفضل ذلك ، يمكنك تغيير هذا والتدريب من نقطة الصفر باستخدام وظيفة الأداة المساعدة الخاصة بنا لإنشاء النموذج. (لاحظ أنه نظرًا لأنه من المحتمل أن تكون بيئتك مختلفة عن بيئتنا ، فستحتاج إلى تخصيص عتبات الضبط والتقييم.)

use_pretrained_model = True

if use_pretrained_model:
  URL = 'https://storage.googleapis.com/civil_comments_model/baseline_model.zip'
  BASE_PATH = tempfile.mkdtemp()
  ZIP_PATH = os.path.join(BASE_PATH, 'baseline_model.zip')
  MODEL_PATH = os.path.join(BASE_PATH, 'tmp/baseline_model')

  r = requests.get(URL, allow_redirects=True)
  open(ZIP_PATH, 'wb').write(r.content)

  with zipfile.ZipFile(ZIP_PATH, 'r') as zip_ref:
    zip_ref.extractall(BASE_PATH)
  baseline_model = tf.keras.models.load_model(
      MODEL_PATH, custom_objects={'KerasLayer' : hub.KerasLayer})
else:
  optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
  loss = tf.keras.losses.BinaryCrossentropy()

  baseline_model = min_diff_keras_utils.create_keras_sequential_model()

  baseline_model.compile(optimizer=optimizer, loss=loss, metrics=['accuracy'])

  baseline_model.fit(x=data_train[TEXT_FEATURE],
                     y=labels_train,
                     batch_size=BATCH_SIZE,
                     epochs=20)

نحفظ النموذج لتقييمه باستخدام مؤشرات الإنصاف .

base_dir = tempfile.mkdtemp(prefix='saved_models')
baseline_model_location = os.path.join(base_dir, 'model_export_baseline')
baseline_model.save(baseline_model_location, save_format='tf')
INFO:tensorflow:Assets written to: /tmp/saved_models867b8d74/model_export_baseline/assets
INFO:tensorflow:Assets written to: /tmp/saved_models867b8d74/model_export_baseline/assets

بعد ذلك نقوم بتشغيل مؤشرات الإنصاف. للتذكير ، سنقوم فقط بإجراء تقييم شرائح للتعليقات التي تشير إلى فئة واحدة ، المجموعات الدينية . في بيئة الإنتاج ، نوصي باتباع نهج مدروس لتحديد الفئات والمقاييس التي يجب التقييم من خلالها.

لحساب أداء النموذج ، تقوم وظيفة الأداة المساعدة ببعض الخيارات المريحة للمقاييس والشرائح وعتبات المصنف.

# We use a helper utility to hide the evaluation logic for readability.
base_dir = tempfile.mkdtemp(prefix='eval')
eval_dir = os.path.join(base_dir, 'tfma_eval_result')
eval_result = fi_util.get_eval_results(
    baseline_model_location, eval_dir, validate_tfrecord_file)
WARNING:absl:Tensorflow version (2.5.0) found. Note that TFMA support for TF 2.0 is currently in beta
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: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:113: 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:113: 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)`

تقديم نتائج التقييم

widget_view.render_fairness_indicator(eval_result)
FairnessIndicatorViewer(slicingMetrics=[{'sliceValue': 'Overall', 'slice': 'Overall', 'metrics': {'accuracy': …

لنلق نظرة على نتائج التقييم. حاول تحديد المعدل المتري الإيجابي الخاطئ (FPR) مع عتبة 0.450. يمكننا أن نرى أن النموذج لا يعمل بشكل جيد بالنسبة لبعض المجموعات الدينية كما هو الحال بالنسبة للآخرين ، حيث يظهر معدل FPR أعلى بكثير. لاحظ فترات الثقة الواسعة في بعض المجموعات لأن الأمثلة قليلة جدًا. هذا يجعل من الصعب القول على وجه اليقين أن هناك فرقًا كبيرًا في أداء هذه الشرائح. قد نرغب في جمع المزيد من الأمثلة لمعالجة هذه المشكلة. ومع ذلك ، يمكننا محاولة تطبيق MinDiff على المجموعتين اللتين نثق أنهما أقل أداءً.

لقد اخترنا التركيز على FPR ، لأن FPR أعلى يعني أن التعليقات التي تشير إلى مجموعات الهوية هذه من المرجح أن يتم تمييزها بشكل غير صحيح على أنها سامة من التعليقات الأخرى. قد يؤدي هذا إلى نتائج غير عادلة للمستخدمين الذين يشاركون في حوار حول الدين ، لكن لاحظ أن التباينات في المقاييس الأخرى يمكن أن تؤدي إلى أنواع أخرى من الضرر.

تحديد وتدريب نموذج MinDiff

الآن ، سنحاول تحسين FPR للجماعات الدينية ذات الأداء الضعيف. سنحاول القيام بذلك باستخدام MinDiff ، وهي تقنية معالجة تسعى إلى موازنة معدلات الخطأ عبر شرائح بياناتك من خلال معاقبة التفاوتات في الأداء أثناء التدريب. عندما نطبق MinDiff ، قد يتدهور أداء النموذج قليلاً على الشرائح الأخرى. على هذا النحو ، ستكون أهدافنا مع MinDiff هي:

  • تحسين الأداء للمجموعات ضعيفة الأداء
  • تدهور محدود للمجموعات الأخرى والأداء العام

جهز بياناتك

لاستخدام MinDiff ، نقوم بإنشاء تقسيمين إضافيين للبيانات:

  • تقسيم للأمثلة غير السامة التي تشير إلى مجموعات الأقليات: في حالتنا ، سيتضمن هذا التعليقات مع إشارات إلى شروط الهوية لدينا ضعيفة الأداء. لا نقوم بتضمين بعض المجموعات نظرًا لوجود عدد قليل جدًا من الأمثلة ، مما يؤدي إلى ارتفاع مستوى عدم اليقين مع نطاقات فاصل ثقة واسعة.
  • تقسيم للأمثلة غير السامة تشير إلى مجموعة الأغلبية.

من المهم أن يكون لديك أمثلة كافية تنتمي إلى الفئات ضعيفة الأداء. استنادًا إلى بنية النموذج وتوزيع البيانات وتكوين MinDiff ، يمكن أن يختلف مقدار البيانات المطلوبة بشكل كبير. في التطبيقات السابقة ، رأينا MinDiff يعمل بشكل جيد مع 5000 مثال في كل تقسيم بيانات.

في حالتنا ، المجموعات في انشقاقات الأقلية لديها أمثلة على الكميات من 9،688 و 3،906. لاحظ اختلالات الفئة في مجموعة البيانات ؛ في الممارسة العملية ، قد يكون هذا مدعاة للقلق ، لكننا لن نسعى لمعالجتها في هذا دفتر الملاحظات لأن هدفنا هو فقط إظهار MinDiff.

نختار فقط الأمثلة السلبية لهذه المجموعات ، حتى يتمكن MinDiff من تحسين الحصول على هذه الأمثلة بشكل صحيح. قد يبدو من غير المنطقي استنباط مجموعات من الأمثلة السلبية للحقيقة الأساسية إذا كنا مهتمين في المقام الأول بالتفاوتات في المعدل الإيجابي الخاطئ ، لكن تذكر أن التنبؤ الإيجابي الخاطئ هو مثال سلبي للحقيقة الأساسية يتم تصنيفه بشكل غير صحيح على أنه إيجابي ، وهي القضية التي نحن تحاول معالجة.

إنشاء MinDiff DataFrames

# Create masks for the sensitive and nonsensitive groups
minority_mask = data_train.religion.apply(
    lambda x: any(religion in x for religion in ('jewish', 'muslim')))
majority_mask = data_train.religion.apply(lambda x: x == "['christian']")

# Select nontoxic examples, so MinDiff will be able to reduce sensitive FP rate.
true_negative_mask = data_train['toxicity'] == 0

data_train_main = copy.copy(data_train)
data_train_sensitive = data_train[minority_mask & true_negative_mask]
data_train_nonsensitive = data_train[majority_mask & true_negative_mask]

نحتاج أيضًا إلى تحويل إطارات بيانات Pandas الخاصة بنا إلى مجموعات بيانات Tensorflow لإدخال MinDiff. لاحظ أنه على عكس واجهة برمجة تطبيقات نموذج Keras لـ Pandas DataFrames ، فإن استخدام مجموعات البيانات يعني أننا بحاجة إلى توفير ميزات الإدخال والتسميات الخاصة بالنموذج معًا في مجموعة بيانات واحدة. نقدم هنا 'comment_text' كميزة إدخال ونعيد تشكيل التسمية لمطابقة الإخراج المتوقع للنموذج.

نقوم بتجميع مجموعة البيانات في هذه المرحلة أيضًا ، نظرًا لأن MinDiff يتطلب مجموعات بيانات مجمعة. لاحظ أننا قمنا بضبط تحديد حجم الدُفعة بنفس الطريقة التي يتم ضبطها بها للنموذج الأساسي ، مع مراعاة سرعة التدريب واعتبارات الأجهزة أثناء الموازنة مع أداء النموذج. هنا اخترنا نفس حجم الدُفعة لجميع مجموعات البيانات الثلاث ولكن هذا ليس مطلبًا ، على الرغم من أنه من الممارسات الجيدة أن يكون حجم الدفعة MinDiff متساويين.

إنشاء مجموعات بيانات MinDiff

# Convert the pandas DataFrames to Datasets.
dataset_train_main = tf.data.Dataset.from_tensor_slices(
    (data_train_main['comment_text'].values, 
     data_train_main.pop(LABEL).values.reshape(-1,1) * 1.0)).batch(BATCH_SIZE)
dataset_train_sensitive = tf.data.Dataset.from_tensor_slices(
    (data_train_sensitive['comment_text'].values, 
     data_train_sensitive.pop(LABEL).values.reshape(-1,1) * 1.0)).batch(BATCH_SIZE)
dataset_train_nonsensitive = tf.data.Dataset.from_tensor_slices(
    (data_train_nonsensitive['comment_text'].values, 
     data_train_nonsensitive.pop(LABEL).values.reshape(-1,1) * 1.0)).batch(BATCH_SIZE)

تدريب وتقييم النموذج

للتدريب مع MinDiff ، ما عليك سوى أخذ النموذج الأصلي ولفه في MinDiffModel مع loss loss_weight loss loss_weight . نحن نستخدم الإصدار 1.5 باعتباره loss_weight ، ولكن هذه معلمة يجب ضبطها لحالة الاستخدام الخاصة بك ، نظرًا لأنها تعتمد على نموذجك ومتطلبات المنتج. يمكنك تجربة تغيير القيمة لمعرفة كيفية تأثيرها على النموذج ، مع ملاحظة أن زيادتها تدفع أداء الأقلية ومجموعات الأغلبية إلى التقارب معًا ولكنها قد تأتي بمقايضات أكثر وضوحًا.

ثم نقوم بتجميع النموذج بشكل طبيعي (باستخدام خسارة MinDiff العادية) ونصلح للتدريب.

تدريب MinDiffModel

use_pretrained_model = True

base_dir = tempfile.mkdtemp(prefix='saved_models')
min_diff_model_location = os.path.join(base_dir, 'model_export_min_diff')

if use_pretrained_model:
  BASE_MIN_DIFF_PATH = tempfile.mkdtemp()
  MIN_DIFF_URL = 'https://storage.googleapis.com/civil_comments_model/min_diff_model.zip'
  ZIP_PATH = os.path.join(BASE_PATH, 'min_diff_model.zip')
  MIN_DIFF_MODEL_PATH = os.path.join(BASE_MIN_DIFF_PATH, 'tmp/min_diff_model')
  DIRPATH = '/tmp/min_diff_model'

  r = requests.get(MIN_DIFF_URL, allow_redirects=True)
  open(ZIP_PATH, 'wb').write(r.content)

  with zipfile.ZipFile(ZIP_PATH, 'r') as zip_ref:
    zip_ref.extractall(BASE_MIN_DIFF_PATH)
  min_diff_model = tf.keras.models.load_model(
      MIN_DIFF_MODEL_PATH, custom_objects={'KerasLayer' : hub.KerasLayer})

  min_diff_model.save(min_diff_model_location, save_format='tf')

else:
  min_diff_weight = 1.5

  # Create the dataset that will be passed to the MinDiffModel during training.
  dataset = md.keras.utils.input_utils.pack_min_diff_data(
      dataset_train_main, dataset_train_sensitive, dataset_train_nonsensitive)

  # Create the original model.
  original_model = min_diff_keras_utils.create_keras_sequential_model()

  # Wrap the original model in a MinDiffModel, passing in one of the MinDiff
  # losses and using the set loss_weight.
  min_diff_loss = md.losses.MMDLoss()
  min_diff_model = md.keras.MinDiffModel(original_model,
                                         min_diff_loss,
                                         min_diff_weight)

  # Compile the model normally after wrapping the original model.  Note that
  # this means we use the baseline's model's loss here.
  optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
  loss = tf.keras.losses.BinaryCrossentropy()
  min_diff_model.compile(optimizer=optimizer, loss=loss, metrics=['accuracy'])

  min_diff_model.fit(dataset, epochs=20)

  min_diff_model.save_original_model(min_diff_model_location, save_format='tf')
INFO:tensorflow:Assets written to: /tmp/saved_modelsb3zkcos_/model_export_min_diff/assets
INFO:tensorflow:Assets written to: /tmp/saved_modelsb3zkcos_/model_export_min_diff/assets

بعد ذلك نقوم بتقييم النتائج.

min_diff_eval_subdir = os.path.join(base_dir, 'tfma_eval_result')
min_diff_eval_result = fi_util.get_eval_results(
    min_diff_model_location,
    min_diff_eval_subdir,
    validate_tfrecord_file,
    slice_selection='religion')
WARNING:absl:Tensorflow version (2.5.0) found. Note that TFMA support for TF 2.0 is currently in beta

للتأكد من أننا نقيم نموذجًا جديدًا بشكل صحيح ، نحتاج إلى تحديد عتبة بنفس الطريقة التي نختار بها النموذج الأساسي. في إعداد الإنتاج ، قد يعني هذا التأكد من أن مقاييس التقييم تلبي معايير الإطلاق. في حالتنا ، سوف نختار الحد الذي ينتج عنه FPR إجمالي مماثل للنموذج الأساسي. قد يختلف هذا الحد عن الحد الذي حددته للنموذج الأساسي. حاول اختيار معدل إيجابي خاطئ مع عتبة 0.400. (لاحظ أن المجموعات الفرعية التي تحتوي على أمثلة كمية منخفضة جدًا لها فترات ثقة واسعة جدًا وليس لها نتائج يمكن التنبؤ بها.)

widget_view.render_fairness_indicator(min_diff_eval_result)
FairnessIndicatorViewer(slicingMetrics=[{'sliceValue': 'Overall', 'slice': 'Overall', 'metrics': {'accuracy': …

بمراجعة هذه النتائج ، قد تلاحظ أن معدلات FPR لمجموعاتنا المستهدفة قد تحسنت. تحسنت الفجوة بين مجموعتنا ذات الأداء المنخفض ومجموعة الأغلبية من .024 إلى .006. نظرًا للتحسينات التي لاحظناها والأداء القوي المستمر لمجموعة الأغلبية ، فقد حققنا كلا الهدفين. اعتمادًا على المنتج ، قد يكون من الضروري إجراء مزيد من التحسينات ، ولكن هذا النهج جعل نموذجنا أقرب خطوة إلى الأداء العادل لجميع المستخدمين.