モデル修復のケーススタディ

このノートブックでは、有毒または有害と見なされる可能性のある書かれたコンテンツを識別するためにテキスト分類子をトレーニングし、MinDiffを適用して公平性の懸念を修正します。ワークフローでは、次のことを行います。

  1. 機密グループへの参照を含むテキストに対するベースラインモデルのパフォーマンスを評価します。
  2. MinDiffを使用してトレーニングすることにより、パフォーマンスの低いグループのパフォーマンスを向上させます。
  3. 選択したメトリックで新しいモデルのパフォーマンスを評価します。

私たちの目的は、機械学習の公平性に対する原則的なアプローチを提示することではなく、最小限のワークフローでMinDiff手法の使用法を示すことです。そのため、私たちの評価は、1つの機密カテゴリと1つのメトリックにのみ焦点を当てます。また、データセットの潜在的な欠点に対処したり、構成を調整したりすることもありません。プロダクション環境では、これらのそれぞれに厳密にアプローチする必要があります。公平性を評価する方法の詳細については、参照このガイドを

設定

まず、公平性インジケーターとTensorFlowモデル修復をインストールします。

インストール

評価用のMinDiffおよびFairnessIndicatorsを含むすべての必要なコンポーネントをインポートします。

輸入

ユーティリティ関数を使用して、前処理されたデータをダウンロードし、モデルの出力形状に一致するようにラベルを準備します。この関数は、データをTFRecordとしてダウンロードして、後の評価を迅速化します。または、使用可能なユーティリティ変換関数を使用して、PandasDataFrameを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

ランダムシードを設定します。 (これは結果を完全に安定させるわけではないことに注意してください。)

シード

ベースラインモデルを定義してトレーニングする

実行時間を短縮するために、デフォルトで事前トレーニング済みモデルを使用します。これは、初期の埋め込み層と畳み込み層を備えた単純な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

次に、公平性インジケーターを実行します。念のため、私たちは1つのカテゴリだけで、宗教団体を参照するコメントをスライスした評価を行うつもりです。実稼働環境では、評価するカテゴリとメトリックを決定するために慎重なアプローチを取ることをお勧めします。

モデルのパフォーマンスを計算するために、効用関数は、メトリック、スライス、および分類子のしきい値についていくつかの便利な選択を行います。

# 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': …

評価結果を見てみましょう。しきい値が0.450のメトリック偽陽性率(FPR)を選択してみてください。このモデルは、一部の宗教グループでは他のグループほどうまく機能せず、はるかに高いFPRを示していることがわかります。例が少なすぎるため、一部のグループの信頼区間が広いことに注意してください。これにより、これらのスライスのパフォーマンスに大きな違いがあることを確実に言うことは困難になります。この問題に対処するために、さらに多くの例を収集することをお勧めします。ただし、パフォーマンスが低いと確信している2つのグループにMinDiffを適用することはできます。

FPRが高いということは、これらのIDグループを参照するコメントが、他のコメントよりも誤って有毒であるとフラグが立てられる可能性が高いことを意味するため、FPRに焦点を当てることを選択しました。これは、宗教についての対話に従事するユーザーにとって不公平な結果につながる可能性がありますが、他の指標の不一致は他の種類の害につながる可能性があることに注意してください。

MinDiffモデルの定義とトレーニング

今度は、業績の悪い宗教団体のFPRを改善しようとします。私たちは、使用してそうしようとしますMinDiff 、トレーニング中にパフォーマンスの格差を不利にして、データのスライス間で誤り率を両立しようと修復技術を。 MinDiffを適用すると、他のスライスでモデルのパフォーマンスがわずかに低下する可能性があります。そのため、MinDiffの目標は次のとおりです。

  • パフォーマンスの低いグループのパフォーマンスが向上
  • 他のグループの限定的な劣化と全体的なパフォーマンス

データを準備する

MinDiffを使用するために、2つの追加のデータ分割を作成します。

  • マイノリティグループを参照する非毒性の例の分割:私たちの場合、これには、パフォーマンスの低いID用語への参照を含むコメントが含まれます。例が少なすぎるため、一部のグループを含めません。これにより、信頼区間の範囲が広くなり、不確実性が高くなります。
  • 多数派グループを参照する非毒性の例の分割。

パフォーマンスの低いクラスに属する十分な例を用意することが重要です。モデルアーキテクチャ、データ分散、およびMinDiff構成に基づいて、必要なデータの量は大幅に異なる可能性があります。過去のアプリケーションでは、MinDiffが各データ分割で5,000の例でうまく機能することを確認しました。

私たちの場合、少数派のグループの例の数量は9,688と3,906です。データセット内のクラスの不均衡に注意してください。実際には、これは懸念の原因となる可能性がありますが、私たちの意図はMinDiffを示すことだけなので、このノートブックでそれらに対処しようとはしません。

MinDiffがこれらの例を正しく取得するために最適化できるように、これらのグループには否定的な例のみを選択します。問題の我々である、私たちは主に偽陽性率の格差に関係している場合、グランドトゥルース負の例のセットを切り開くために直感に反するように見えるが、偽陽性の予測が誤って陽性と分類されていますグランドトゥルース負の一例であることを覚えているかもしれ対処しようとしています。

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]

また、PandasDataFrameをMinDiff入力用のTensorflowデータセットに変換する必要があります。 Pandas DataFramesのKerasモデルAPIとは異なり、データセットを使用するということは、モデルの入力機能とラベルを1つのデータセットにまとめて提供する必要があることを意味します。ここでは、提供'comment_text'入力機能などを、モデルの予想出力と一致するラベルを作り変えます。

MinDiffはバッチ処理されたデータセットを必要とするため、この段階でもデータセットをバッチ処理します。バッチサイズの選択は、モデルのパフォーマンスとのバランスを取りながら、トレーニング速度とハードウェアの考慮事項を考慮して、ベースラインモデルに合わせて調整するのと同じ方法で調整することに注意してください。ここでは、3つのデータセットすべてに同じバッチサイズを選択しましたが、これは必須ではありませんが、2つの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でラップlossloss_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に改善されました。私たちが観察した改善と多数派グループの継続的な好業績を考えると、私たちは両方の目標を達成しました。製品によっては、さらなる改善が必要な場合がありますが、このアプローチにより、モデルはすべてのユーザーに対して公平に実行できるようになりました。