Studi Kasus Remediasi Model

Dalam buku catatan ini, kami akan melatih pengklasifikasi teks untuk mengidentifikasi konten tertulis yang dapat dianggap beracun atau berbahaya, dan menerapkan MinDiff untuk memulihkan beberapa masalah keadilan. Dalam alur kerja kami, kami akan:

  1. Evaluasi kinerja model dasar kami pada teks yang berisi referensi ke grup sensitif.
  2. Tingkatkan kinerja pada grup yang berkinerja buruk dengan berlatih bersama MinDiff.
  3. Evaluasi kinerja model baru pada metrik pilihan kami.

Tujuan kami adalah untuk mendemonstrasikan penggunaan teknik MinDiff dengan alur kerja yang sangat minimal, bukan untuk menerapkan pendekatan prinsip keadilan dalam pembelajaran mesin. Dengan demikian, evaluasi kami hanya akan fokus pada satu kategori sensitif dan satu metrik. Kami juga tidak mengatasi potensi kekurangan dalam kumpulan data, atau menyesuaikan konfigurasi kami. Dalam pengaturan produksi, Anda ingin mendekati masing-masing dengan ketelitian. Untuk informasi lebih lanjut tentang evaluasi untuk keadilan, lihat panduan ini .

Mempersiapkan

Kita mulai dengan memasang Indikator Kewajaran dan Remediasi Model TensorFlow.

Menginstal

Impor semua komponen yang diperlukan, termasuk MinDiff dan Indikator Kewajaran untuk evaluasi.

Impor

Kami menggunakan fungsi utilitas untuk mengunduh data yang telah diproses sebelumnya dan menyiapkan label agar sesuai dengan bentuk keluaran model. Fungsi ini juga mengunduh data sebagai TFRecords untuk membuat evaluasi selanjutnya lebih cepat. Atau, Anda dapat mengonversi Pandas DataFrame menjadi TFRecords dengan fungsi konversi utilitas apa pun yang tersedia.

# 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

Kami mendefinisikan beberapa konstanta yang berguna. Kami akan melatih model pada 'comment_text' fitur, dengan label target kami sebagai 'toxicity' . Perhatikan bahwa ukuran batch di sini dipilih secara sewenang-wenang, tetapi dalam pengaturan produksi Anda perlu menyetelnya untuk kinerja terbaik.

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

Tetapkan benih acak. (Perhatikan bahwa ini tidak sepenuhnya menstabilkan hasil.)

Biji

Tentukan dan latih model dasar

Untuk mengurangi waktu proses, kami menggunakan model yang telah dilatih secara default. Ini adalah model sekuensial Keras sederhana dengan embedding awal dan lapisan konvolusi, menghasilkan prediksi toksisitas. Jika Anda mau, Anda dapat mengubah ini dan berlatih dari awal menggunakan fungsi utilitas kami untuk membuat model. (Perhatikan bahwa karena lingkungan Anda mungkin berbeda dari lingkungan kami, Anda perlu menyesuaikan ambang batas penyetelan dan evaluasi.)

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)

Kami menyimpan model untuk mengevaluasi menggunakan Keadilan Indikator .

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

Selanjutnya kita menjalankan Indikator Kewajaran. Sebagai pengingat, kita hanya akan melakukan evaluasi iris untuk komentar referensi satu kategori, kelompok agama. Dalam lingkungan produksi, sebaiknya ambil pendekatan yang bijaksana untuk menentukan kategori dan metrik mana yang akan dievaluasi.

Untuk menghitung kinerja model, fungsi utilitas membuat beberapa pilihan yang mudah untuk metrik, irisan, dan ambang pengklasifikasi.

# 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)`

Render Hasil Evaluasi

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

Mari kita lihat hasil evaluasinya. Coba pilih metrik tingkat positif palsu (FPR) dengan ambang batas 0,450. Kita dapat melihat bahwa model tersebut tidak berkinerja baik untuk beberapa kelompok agama seperti yang lain, menampilkan FPR yang jauh lebih tinggi. Perhatikan interval kepercayaan yang lebar pada beberapa kelompok karena mereka memiliki terlalu sedikit contoh. Hal ini membuat sulit untuk mengatakan dengan pasti bahwa ada perbedaan kinerja yang signifikan untuk irisan ini. Kami mungkin ingin mengumpulkan lebih banyak contoh untuk mengatasi masalah ini. Namun, kami dapat mencoba menerapkan MinDiff untuk dua grup yang kami yakini berkinerja buruk.

Kami telah memilih untuk fokus pada FPR, karena FPR yang lebih tinggi berarti bahwa komentar yang merujuk pada kelompok identitas ini cenderung salah ditandai sebagai beracun daripada komentar lainnya. Hal ini dapat menyebabkan hasil yang tidak adil bagi pengguna yang terlibat dalam dialog tentang agama, tetapi perhatikan bahwa perbedaan dalam metrik lain dapat menyebabkan jenis bahaya lainnya.

Tentukan dan Latih Model MinDiff

Sekarang, kami akan mencoba meningkatkan FPR untuk kelompok agama yang berkinerja buruk. Kami akan mencoba untuk melakukannya dengan menggunakan MinDiff , teknik remediasi yang berusaha untuk menyeimbangkan tingkat kesalahan di iris data Anda dengan menghukum kesenjangan dalam kinerja selama pelatihan. Saat kami menerapkan MinDiff, kinerja model mungkin sedikit menurun pada irisan lainnya. Dengan demikian, tujuan kami dengan MinDiff adalah:

  • Peningkatan kinerja untuk kelompok yang berkinerja buruk
  • Degradasi terbatas untuk grup lain dan kinerja keseluruhan

Siapkan data Anda

Untuk menggunakan MinDiff, kami membuat dua pemisahan data tambahan:

  • Perpecahan untuk contoh tidak beracun yang merujuk pada kelompok minoritas: Dalam kasus kami, ini akan mencakup komentar dengan referensi ke istilah identitas kami yang berkinerja buruk. Kami tidak menyertakan beberapa grup karena terlalu sedikit contoh, yang mengarah ke ketidakpastian yang lebih tinggi dengan rentang interval kepercayaan yang lebar.
  • Perpecahan untuk contoh tidak beracun yang merujuk pada kelompok mayoritas.

Sangat penting untuk memiliki cukup contoh milik kelas yang berkinerja buruk. Berdasarkan arsitektur model, distribusi data, dan konfigurasi MinDiff Anda, jumlah data yang dibutuhkan dapat sangat bervariasi. Dalam aplikasi sebelumnya, kami telah melihat MinDiff bekerja dengan baik dengan 5.000 contoh di setiap pemisahan data.

Dalam kasus kami, kelompok-kelompok dalam pecahan minoritas memiliki contoh jumlah 9.688 dan 3.906. Perhatikan ketidakseimbangan kelas dalam dataset; dalam praktiknya, hal ini dapat menimbulkan kekhawatiran, tetapi kami tidak akan membahasnya di buku catatan ini karena tujuan kami hanyalah untuk mendemonstrasikan MinDiff.

Kami hanya memilih contoh negatif untuk grup ini, sehingga MinDiff dapat mengoptimalkan untuk mendapatkan contoh ini dengan benar. Ini mungkin tampak berlawanan dengan intuisi untuk mengukir set contoh negatif ground truth jika kita terutama yang bersangkutan dengan kesenjangan di tingkat positif palsu, tapi ingat bahwa prediksi positif palsu adalah contoh tanah kebenaran negatif yang salah diklasifikasikan sebagai positif, yang merupakan masalah kita sedang mencoba untuk mengatasi.

Buat DataFrames MinDiff

# 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]

Kita juga perlu mengonversi Pandas DataFrames menjadi Tensorflow Datasets untuk input MinDiff. Perhatikan bahwa tidak seperti API model Keras untuk Pandas DataFrames, menggunakan Dataset berarti kita perlu menyediakan fitur dan label input model bersama-sama dalam satu Dataset. Di sini kami menyediakan 'comment_text' sebagai fitur input dan membentuk kembali label untuk mencocokkan output yang diharapkan model.

Kami mengelompokkan Dataset pada tahap ini juga, karena MinDiff membutuhkan Kumpulan Data yang di-batch. Perhatikan bahwa kami menyetel pemilihan ukuran batch dengan cara yang sama seperti penyetelan untuk model dasar, dengan mempertimbangkan kecepatan pelatihan dan pertimbangan perangkat keras sambil menyeimbangkan dengan kinerja model. Di sini kami telah memilih ukuran batch yang sama untuk ketiga kumpulan data tetapi ini bukan persyaratan, meskipun praktik yang baik adalah memiliki dua ukuran batch MinDiff yang setara.

Buat Kumpulan Data 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)

Latih dan evaluasi modelnya

Untuk melatih dengan MinDiff, hanya mengambil model asli dan bungkus dalam MinDiffModel dengan sesuai loss dan loss_weight . Kami menggunakan 1,5 sebagai default loss_weight , tapi ini adalah parameter yang perlu disetel untuk kasus penggunaan Anda, karena tergantung pada model dan produk kebutuhan Anda. Anda dapat bereksperimen dengan mengubah nilai untuk melihat bagaimana pengaruhnya terhadap model, dengan mencatat bahwa peningkatan itu mendorong kinerja kelompok minoritas dan mayoritas lebih dekat, tetapi mungkin datang dengan pengorbanan yang lebih nyata.

Kemudian kami mengkompilasi model secara normal (menggunakan kerugian non-MinDiff biasa) dan cocok untuk dilatih.

Melatih 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

Selanjutnya kita evaluasi hasilnya.

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

Untuk memastikan kami mengevaluasi model baru dengan benar, kami perlu memilih ambang dengan cara yang sama seperti yang kami lakukan pada model dasar. Dalam pengaturan produksi, ini berarti memastikan bahwa metrik evaluasi memenuhi standar peluncuran. Dalam kasus kami, kami akan memilih ambang batas yang menghasilkan FPR keseluruhan yang serupa dengan model dasar. Ambang batas ini mungkin berbeda dari yang Anda pilih untuk model dasar. Coba pilih tingkat positif palsu dengan ambang 0,400. (Perhatikan bahwa subkelompok dengan contoh kuantitas yang sangat rendah memiliki interval rentang kepercayaan yang sangat lebar dan tidak memiliki hasil yang dapat diprediksi.)

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

Meninjau hasil ini, Anda mungkin memperhatikan bahwa FPR untuk kelompok sasaran kami telah meningkat. Kesenjangan antara grup berkinerja terendah dan grup mayoritas telah meningkat dari 0,024 menjadi 0,006. Mengingat peningkatan yang telah kami amati dan kinerja kuat yang berkelanjutan untuk kelompok mayoritas, kami telah memenuhi kedua tujuan kami. Bergantung pada produknya, peningkatan lebih lanjut mungkin diperlukan, tetapi pendekatan ini membuat model kami selangkah lebih dekat untuk berkinerja secara adil bagi semua pengguna.