Caso di studio sulla riparazione del modello

In questo quaderno, formeremo un classificatore di testo per identificare i contenuti scritti che potrebbero essere considerati tossici o dannosi e applicheremo MinDiff per rimediare ad alcuni problemi di equità. Nel nostro flusso di lavoro:

  1. Valuta le prestazioni del nostro modello di base sul testo contenente riferimenti a gruppi sensibili.
  2. Migliora le prestazioni su tutti i gruppi con prestazioni inferiori allenandoti con MinDiff.
  3. Valuta le prestazioni del nuovo modello sulla metrica scelta.

Il nostro scopo è dimostrare l'utilizzo della tecnica MinDiff con un flusso di lavoro molto minimo, non definire un approccio di principio all'equità nell'apprendimento automatico. Pertanto, la nostra valutazione si concentrerà solo su una categoria sensibile e una singola metrica. Inoltre, non affrontiamo potenziali carenze nel set di dati, né perfezioniamo le nostre configurazioni. In un ambiente di produzione, vorresti affrontare ciascuno di questi con rigore. Per ulteriori informazioni sulla valutazione di equità, consultare questa guida .

Impostare

Iniziamo installando gli indicatori di equità e TensorFlow Model Remediation.

Installa

Importa tutti i componenti necessari, inclusi MinDiff e Fairness Indicators per la valutazione.

Importazioni

Utilizziamo una funzione di utilità per scaricare i dati preelaborati e preparare le etichette in modo che corrispondano alla forma di output del modello. La funzione scarica anche i dati come TFRecords per rendere più rapida la valutazione successiva. In alternativa, puoi convertire Pandas DataFrame in TFRecords con qualsiasi funzione di conversione di utilità disponibile.

# 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

Definiamo alcune costanti utili. Noi addestrare il modello sul 'comment_text' caratteristica, con la nostra etichetta di destinazione come 'toxicity' . Si noti che la dimensione del batch qui viene scelta arbitrariamente, ma in un'impostazione di produzione è necessario ottimizzarla per ottenere le migliori prestazioni.

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

Imposta semi casuali. (Si noti che questo non stabilizza completamente i risultati.)

Semi

Definire e addestrare il modello di base

Per ridurre il tempo di esecuzione, utilizziamo un modello preaddestrato per impostazione predefinita. È un semplice modello sequenziale Keras con un'inclusione iniziale e strati di convoluzione, che generano una previsione di tossicità. Se preferisci, puoi modificarlo e allenarti da zero utilizzando la nostra funzione di utilità per creare il modello. (Tieni presente che, poiché il tuo ambiente è probabilmente diverso dal nostro, dovrai personalizzare le soglie di ottimizzazione e valutazione.)

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)

Salviamo il modello al fine di valutare con Fairness indicatori .

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

Quindi eseguiamo gli indicatori di equità. Come promemoria, stiamo solo andando a svolgere la valutazione a fette per i commenti fanno riferimento a una categoria, i gruppi religiosi. In un ambiente di produzione, consigliamo di adottare un approccio ponderato per determinare in quali categorie e metriche valutare.

Per calcolare le prestazioni del modello, la funzione di utilità effettua alcune scelte utili per metriche, sezioni e soglie del classificatore.

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

Risultati della valutazione del rendering

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

Diamo un'occhiata ai risultati della valutazione. Prova a selezionare il tasso metrico di falsi positivi (FPR) con soglia 0,450. Possiamo vedere che il modello non funziona bene per alcuni gruppi religiosi come per altri, mostrando un FPR molto più alto. Nota gli ampi intervalli di confidenza su alcuni gruppi perché hanno troppo pochi esempi. Ciò rende difficile affermare con certezza che ci sia una differenza significativa nelle prestazioni per queste fette. Potremmo voler raccogliere più esempi per affrontare questo problema. Possiamo, tuttavia, tentare di applicare MinDiff per i due gruppi che confidiamo abbiano prestazioni inferiori.

Abbiamo scelto di concentrarci su FPR, perché un FPR più alto significa che i commenti che fanno riferimento a questi gruppi di identità hanno maggiori probabilità di essere erroneamente contrassegnati come tossici rispetto ad altri commenti. Ciò potrebbe portare a risultati iniqui per gli utenti che si impegnano nel dialogo sulla religione, ma tieni presente che le disparità in altre metriche possono causare altri tipi di danni.

Definire e addestrare il modello MinDiff

Ora cercheremo di migliorare l'FPR per i gruppi religiosi con prestazioni inferiori. Cercheremo di farlo utilizzando MinDiff , una tecnica di bonifica che cerca di equilibrare i tassi di errore attraverso fette di dati da parte di penalizzare le disparità in termini di prestazioni durante l'allenamento. Quando applichiamo MinDiff, le prestazioni del modello potrebbero diminuire leggermente su altre sezioni. Pertanto, i nostri obiettivi con MinDiff saranno:

  • Prestazioni migliorate per i gruppi con prestazioni inferiori
  • Degrado limitato per altri gruppi e prestazioni complessive

Prepara i tuoi dati

Per utilizzare MinDiff, creiamo due ulteriori suddivisioni di dati:

  • Una divisione per esempi non tossici che fanno riferimento a gruppi minoritari: nel nostro caso, questo includerà commenti con riferimenti ai nostri termini di identità sottoperformanti. Non includiamo alcuni dei gruppi perché ci sono troppo pochi esempi, il che porta a una maggiore incertezza con ampi intervalli di intervallo di confidenza.
  • Una divisione per esempi non tossici che fanno riferimento al gruppo di maggioranza.

È importante disporre di esempi sufficienti appartenenti alle classi con prestazioni inferiori. In base all'architettura del modello, alla distribuzione dei dati e alla configurazione di MinDiff, la quantità di dati necessaria può variare in modo significativo. Nelle applicazioni precedenti, abbiamo visto MinDiff funzionare bene con 5.000 esempi in ogni suddivisione dei dati.

Nel nostro caso, i gruppi nelle divisioni di minoranza hanno quantità esemplificative di 9.688 e 3.906. Nota gli squilibri di classe nel set di dati; in pratica, questo potrebbe essere motivo di preoccupazione, ma non cercheremo di affrontarli in questo quaderno poiché la nostra intenzione è solo quella di dimostrare MinDiff.

Selezioniamo solo esempi negativi per questi gruppi, in modo che MinDiff possa ottimizzare per ottenere questi esempi correttamente. Può sembrare controintuitivo per ritagliarsi serie di esempi negativi di verità a terra, se ci riguarda in primo luogo con la disparità di tasso di falsi positivi, ma ricordate che una previsione falso positivo è un esempio verità a terra negativa che è erroneamente classificato come positivo, che è la rilasciamo stai cercando di affrontare.

Crea frame di dati 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]

Abbiamo anche bisogno di convertire i nostri Pandas DataFrame in Tensorflow Dataset per l'input MinDiff. Si noti che, a differenza dell'API del modello Keras per Pandas DataFrames, l'utilizzo di set di dati significa che è necessario fornire le funzionalità di input e le etichette del modello insieme in un set di dati. Qui forniamo la 'comment_text' come una caratteristica di ingresso e rimodellare l'etichetta in modo che corrisponda l'uscita prevista del modello.

Anche in questa fase viene eseguito il batch del set di dati, poiché MinDiff richiede set di dati in batch. Si noti che ottimizziamo la selezione della dimensione del batch nello stesso modo in cui viene ottimizzata per il modello di base, tenendo conto della velocità di addestramento e delle considerazioni sull'hardware e bilanciando le prestazioni del modello. Qui abbiamo scelto la stessa dimensione batch per tutti e tre i set di dati, ma questo non è un requisito, sebbene sia buona norma che le due dimensioni batch MinDiff siano equivalenti.

Crea set di dati 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)

Addestrare e valutare il modello

Per allenarsi con MinDiff, semplicemente prendere il modello originale e avvolgerlo in un MinDiffModel con una corrispondente loss e loss_weight . Stiamo usando 1.5 come predefinito loss_weight , ma questo è un parametro che deve essere sintonizzato per il vostro caso d'uso, dal momento che dipende dalla vostra requisiti di modello e di prodotto. Puoi provare a modificare il valore per vedere come influisce sul modello, notando che aumentandolo spinge le prestazioni dei gruppi di minoranza e maggioranza più vicini, ma può comportare compromessi più pronunciati.

Quindi compiliamo il modello normalmente (usando la normale perdita non MinDiff) e lo adattiamo all'allenamento.

Treno 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

Successivamente valutiamo i risultati.

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

Per assicurarci di valutare correttamente un nuovo modello, dobbiamo selezionare una soglia nello stesso modo in cui faremmo il modello di base. In un ambiente di produzione, ciò significherebbe garantire che le metriche di valutazione soddisfino gli standard di lancio. Nel nostro caso, sceglieremo la soglia che si traduce in un FPR complessivo simile al modello di base. Questa soglia potrebbe essere diversa da quella selezionata per il modello di base. Prova a selezionare il tasso di falsi positivi con soglia 0,400. (Si noti che i sottogruppi con esempi di quantità molto basse hanno intervalli di confidenza molto ampi e non hanno risultati prevedibili.)

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

Esaminando questi risultati, potresti notare che gli FPR per i nostri gruppi target sono migliorati. Il divario tra il nostro gruppo con il rendimento più basso e il gruppo di maggioranza è migliorato da .024 a .006. Dati i miglioramenti che abbiamo osservato e le continue ottime prestazioni per il gruppo di maggioranza, abbiamo soddisfatto entrambi i nostri obiettivi. A seconda del prodotto, potrebbero essere necessari ulteriori miglioramenti, ma questo approccio ha avvicinato il nostro modello a prestazioni eque per tutti gli utenti.