ในสมุดบันทึกนี้ เราจะฝึกตัวแยกประเภทข้อความเพื่อระบุเนื้อหาที่เป็นลายลักษณ์อักษรที่อาจถือว่าเป็นพิษหรือเป็นอันตราย และใช้ MinDiff เพื่อแก้ไขข้อกังวลด้านความเป็นธรรมบางประการ ในขั้นตอนการทำงานของเรา เราจะ:
- ประเมินประสิทธิภาพของโมเดลพื้นฐานของเราในข้อความที่มีการอ้างอิงถึงกลุ่มที่มีความละเอียดอ่อน
- ปรับปรุงประสิทธิภาพในกลุ่มที่มีประสิทธิภาพต่ำโดยการฝึกอบรมกับ MinDiff
- ประเมินประสิทธิภาพของโมเดลใหม่กับเมตริกที่เราเลือก
จุดประสงค์ของเราคือเพื่อสาธิตการใช้เทคนิค MinDiff กับขั้นตอนการทำงานที่น้อยที่สุด ไม่ใช่เพื่อวางแนวทางหลักเพื่อความเป็นธรรมในการเรียนรู้ของเครื่อง ด้วยเหตุนี้ การประเมินของเราจะเน้นที่หมวดหมู่ที่ละเอียดอ่อนเพียงหมวดหมู่เดียวและตัวชี้วัดเดียวเท่านั้น เราไม่แก้ไขข้อบกพร่องที่อาจเกิดขึ้นในชุดข้อมูล หรือปรับแต่งการกำหนดค่าของเรา ในสภาพแวดล้อมการผลิต คุณจะต้องเข้าหาสิ่งเหล่านี้อย่างเข้มงวด สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการประเมินผลเพื่อความเป็นธรรมให้ดูที่ คำแนะนำนี้
ติดตั้ง
เราเริ่มต้นด้วยการติดตั้ง Fairness Indicators และ TensorFlow Model Remediation
การติดตั้ง
pip install --upgrade tensorflow-model-remediation
pip install --upgrade fairness-indicators
นำเข้าส่วนประกอบที่จำเป็นทั้งหมด รวมถึง MinDiff และตัวบ่งชี้ความเป็นธรรมเพื่อการประเมิน
นำเข้า
import copy
import os
import requests
import tempfile
import zipfile
import tensorflow_model_remediation.min_diff as md
from tensorflow_model_remediation.tools.tutorials_utils import min_diff_keras_utils
from fairness_indicators.tutorial_utils import util as fi_util
import numpy as np
import tensorflow as tf
import tensorflow_hub as hub
from tensorflow_model_analysis.addons.fairness.view import widget_view
เราใช้ฟังก์ชันยูทิลิตี้เพื่อดาวน์โหลดข้อมูลที่ประมวลผลล่วงหน้าและเตรียมฉลากให้ตรงกับรูปร่างเอาต์พุตของโมเดล ฟังก์ชันนี้ยังดาวน์โหลดข้อมูลเป็น TFRecords เพื่อให้การประเมินในภายหลังเร็วขึ้น หรือคุณอาจแปลง Pandas DataFrame เป็น TFRecords ด้วยฟังก์ชันการแปลงยูทิลิตี้ที่มีอยู่
# 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
ตั้งเมล็ดสุ่ม (โปรดทราบว่าการดำเนินการนี้ไม่ได้ทำให้ผลลัพธ์มีเสถียรภาพเต็มที่)
เมล็ดพันธุ์
np.random.seed(1)
tf.random.set_seed(1)
กำหนดและฝึกโมเดลพื้นฐาน
เพื่อลดรันไทม์ เราใช้โมเดลที่ได้รับการฝึกมาล่วงหน้าโดยค่าเริ่มต้น เป็นแบบจำลองลำดับ 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 ทำงานได้ดีกับตัวอย่าง 5,000 รายการในแต่ละข้อมูลแยก
ในกรณีของเรา กลุ่มในการแบ่งส่วนน้อยมีปริมาณตัวอย่าง 9,688 และ 3,906 สังเกตความไม่สมดุลของคลาสในชุดข้อมูล ในทางปฏิบัติ การทำเช่นนี้อาจทำให้เกิดข้อกังวลได้ แต่เราจะไม่พยายามแก้ไขในสมุดบันทึกนี้ เนื่องจากเราตั้งใจจะแสดง MinDiff เท่านั้น
เราเลือกเฉพาะตัวอย่างเชิงลบสำหรับกลุ่มเหล่านี้ เพื่อให้ MinDiff สามารถเพิ่มประสิทธิภาพในการทำให้ตัวอย่างเหล่านี้ถูกต้อง มันอาจจะดูเหมือน counterintuitive ที่จะตัดออกชุดตัวอย่างเชิงลบความจริงพื้นดินถ้าเรากำลังกังวลเกี่ยวเนื่องกับความแตกต่างในอัตราบวกปลอม แต่จำไว้ว่าการคาดการณ์ในเชิงบวกเท็จเป็นตัวอย่างจริงพื้นดินเชิงลบที่จัดไม่ถูกต้องเป็นบวกซึ่งเป็นปัญหาที่เรา กำลังพยายามที่จะอยู่
สร้าง 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 DataFrames เป็นชุดข้อมูล Tensorflow สำหรับอินพุต MinDiff โปรดทราบว่าไม่เหมือนกับ Keras model API สำหรับ 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 จากการปรับปรุงที่เราสังเกตเห็นและผลงานที่แข็งแกร่งอย่างต่อเนื่องสำหรับกลุ่มคนส่วนใหญ่ เราจึงบรรลุเป้าหมายทั้งสองของเรา ทั้งนี้ขึ้นอยู่กับผลิตภัณฑ์ การปรับปรุงเพิ่มเติมอาจมีความจำเป็น แต่วิธีการนี้ทำให้โมเดลของเราเข้าใกล้การทำงานอย่างเท่าเทียมกันสำหรับผู้ใช้ทั้งหมดอีกขั้นหนึ่ง