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

في دفتر الملاحظات هذا ، سنقوم بتدريب مصنف نصوص لتحديد المحتوى المكتوب الذي يمكن اعتباره سامًا أو ضارًا ، وسنقوم بتطبيق 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 . نحن نستخدم 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. نظرًا للتحسينات التي لاحظناها والأداء القوي المستمر لمجموعة الأغلبية ، فقد حققنا كلا الهدفين. اعتمادًا على المنتج ، قد يكون من الضروري إجراء مزيد من التحسينات ، ولكن هذا النهج جعل نموذجنا أقرب خطوة إلى الأداء العادل لجميع المستخدمين.