לימוד שפה עמוק מודע לחוסר וודאות עם BERT-SNGP

הצג באתר TensorFlow.org הפעל בגוגל קולאב הצג ב-GitHub הורד מחברת ראה דגם TF Hub

במדריך SNGP , למדת כיצד לבנות מודל SNGP על גבי רשת שיורית עמוקה כדי לשפר את יכולתה לכמת את אי הוודאות שלה. במדריך זה, תחיל SNGP על משימה של הבנת שפה טבעית (NLU) על ידי בנייתה על גבי מקודד BERT עמוק כדי לשפר את היכולת של מודל NLU עמוק בזיהוי שאילתות מחוץ לתחום.

באופן ספציפי, תעשה:

  • בנה את BERT-SNGP, מודל BERT מוגבר ב-SNGP.
  • טען את מערך הנתונים של זיהוי הכוונות של CLINC מחוץ לטווח (OOS) .
  • אימון מודל BERT-SNGP.
  • הערך את הביצועים של מודל BERT-SNGP בכיול אי ודאות וזיהוי מחוץ לתחום.

מעבר ל-CLINC OOS, מודל ה-SNGP יושם על מערכי נתונים בקנה מידה גדול כגון זיהוי רעילות של Jigsaw , ועל מערכי נתונים של תמונות כגון CIFAR-100 ו- ImageNet . לתוצאות בנצ'מרק של SNGP ושיטות אי ודאות אחרות, כמו גם הטמעה באיכות גבוהה עם תסריטי אימון / הערכה מקצה לקצה, אתה יכול לבדוק את מדד בסיס אי הוודאות .

להכין

pip uninstall -y tensorflow tf-text
pip install -U tensorflow-text-nightly
pip install -U tf-nightly
pip install -U tf-models-nightly
import matplotlib.pyplot as plt

import sklearn.metrics
import sklearn.calibration

import tensorflow_hub as hub
import tensorflow_datasets as tfds

import numpy as np
import tensorflow as tf

import official.nlp.modeling.layers as layers
import official.nlp.optimization as optimization
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_addons/utils/ensure_tf_install.py:43: UserWarning: You are currently using a nightly version of TensorFlow (2.9.0-dev20220203). 
TensorFlow Addons offers no support for the nightly versions of TensorFlow. Some things might work, some other might not. 
If you encounter a bug, do not file an issue on GitHub.
  UserWarning,

מדריך זה זקוק ל-GPU כדי לפעול ביעילות. בדוק אם ה-GPU זמין.

tf.__version__
'2.9.0-dev20220203'
gpus = tf.config.list_physical_devices('GPU')
gpus
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
assert gpus, """
  No GPU(s) found! This tutorial will take many hours to run without a GPU.

  You may hit this error if the installed tensorflow package is not
  compatible with the CUDA and CUDNN versions."""

תחילה יש ליישם מסווג BERT סטנדרטי בעקבות טקסט הסיווג עם מדריך BERT . נשתמש במקודד BERT-base , וב- ClassificationHead המובנה כמסווג.

דגם BERT סטנדרטי

בניית מודל SNGP

כדי ליישם מודל BERT-SNGP, אתה רק צריך להחליף את ClassificationHead ב- GaussianProcessClassificationHead המובנה. נורמליזציה ספקטרלית כבר ארוזה מראש בראש הסיווג הזה. כמו במדריך SNGP , הוסף התקשרות לאיפוס שיתופיות למודל, כך שהמודל יאפס אוטומטית את מעריך השונות בתחילת עידן חדש כדי להימנע מספירת אותם נתונים פעמיים.

class ResetCovarianceCallback(tf.keras.callbacks.Callback):

  def on_epoch_begin(self, epoch, logs=None):
    """Resets covariance matrix at the begining of the epoch."""
    if epoch > 0:
      self.model.classifier.reset_covariance_matrix()
class SNGPBertClassifier(BertClassifier):

  def make_classification_head(self, num_classes, inner_dim, dropout_rate):
    return layers.GaussianProcessClassificationHead(
        num_classes=num_classes, 
        inner_dim=inner_dim,
        dropout_rate=dropout_rate,
        gp_cov_momentum=-1,
        temperature=30.,
        **self.classifier_kwargs)

  def fit(self, *args, **kwargs):
    """Adds ResetCovarianceCallback to model callbacks."""
    kwargs['callbacks'] = list(kwargs.get('callbacks', []))
    kwargs['callbacks'].append(ResetCovarianceCallback())

    return super().fit(*args, **kwargs)

טען את מערך הנתונים של CLINC OOS

כעת טען את מערך הנתונים של זיהוי הכוונות של CLINC OOS . מערך נתונים זה מכיל 15000 שאילתות מדוברות של משתמשים שנאספו מעל 150 מחלקות כוונות, הוא מכיל גם 1000 משפטים מחוץ לתחום (OOD) שאינם מכוסים על ידי אף אחת מהמחלקות המוכרות.

(clinc_train, clinc_test, clinc_test_oos), ds_info = tfds.load(
    'clinc_oos', split=['train', 'test', 'test_oos'], with_info=True, batch_size=-1)

הכינו את הרכבת ונתוני בדיקה.

train_examples = clinc_train['text']
train_labels = clinc_train['intent']

# Makes the in-domain (IND) evaluation data.
ind_eval_data = (clinc_test['text'], clinc_test['intent'])

צור מערך הערכת OOD. לשם כך, שלבו את נתוני הבדיקה בתוך הדומיין clinc_test ו-out-of-domain data clinc_test_oos . נקצה גם תווית 0 לדוגמאות בתוך הדומיין, ותווית 1 לדוגמאות מחוץ לדומיין.

test_data_size = ds_info.splits['test'].num_examples
oos_data_size = ds_info.splits['test_oos'].num_examples

# Combines the in-domain and out-of-domain test examples.
oos_texts = tf.concat([clinc_test['text'], clinc_test_oos['text']], axis=0)
oos_labels = tf.constant([0] * test_data_size + [1] * oos_data_size)

# Converts into a TF dataset.
ood_eval_dataset = tf.data.Dataset.from_tensor_slices(
    {"text": oos_texts, "label": oos_labels})

לאמן ולהעריך

תחילה הגדר את תצורות האימון הבסיסיות.

TRAIN_EPOCHS = 3
TRAIN_BATCH_SIZE = 32
EVAL_BATCH_SIZE = 256

optimizer = bert_optimizer(learning_rate=1e-4)
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
metrics = tf.metrics.SparseCategoricalAccuracy()
fit_configs = dict(batch_size=TRAIN_BATCH_SIZE,
                   epochs=TRAIN_EPOCHS,
                   validation_batch_size=EVAL_BATCH_SIZE, 
                   validation_data=ind_eval_data)
sngp_model = SNGPBertClassifier()
sngp_model.compile(optimizer=optimizer, loss=loss, metrics=metrics)
sngp_model.fit(train_examples, train_labels, **fit_configs)
Epoch 1/3
469/469 [==============================] - 219s 427ms/step - loss: 1.0725 - sparse_categorical_accuracy: 0.7870 - val_loss: 0.4358 - val_sparse_categorical_accuracy: 0.9380
Epoch 2/3
469/469 [==============================] - 198s 422ms/step - loss: 0.0885 - sparse_categorical_accuracy: 0.9797 - val_loss: 0.2424 - val_sparse_categorical_accuracy: 0.9518
Epoch 3/3
469/469 [==============================] - 199s 424ms/step - loss: 0.0259 - sparse_categorical_accuracy: 0.9951 - val_loss: 0.1927 - val_sparse_categorical_accuracy: 0.9642
<keras.callbacks.History at 0x7fe24c0a7090>

הערכת ביצועי OOD

הערך עד כמה המודל יכול לזהות את השאילתות הלא מוכרות מחוץ לדומיין. להערכה קפדנית, השתמש במערך הנתונים להערכת OOD ood_eval_dataset שנבנה קודם לכן.

מחשב את ההסתברויות של OOD בתור \(1 - p(x)\), כאשר \(p(x)=softmax(logit(x))\) הוא ההסתברות הניבוי.

sngp_probs, ood_labels = oos_predict(sngp_model, ood_eval_dataset)
ood_probs = 1 - sngp_probs

כעת הערך עד כמה ציון אי הוודאות של המודל ood_probs מנבא את התווית מחוץ לתחום. תחילה חשב את השטח תחת עקומת זכירה מדויקת (AUPRC) עבור הסתברות OOD לעומת דיוק זיהוי OOD.

precision, recall, _ = sklearn.metrics.precision_recall_curve(ood_labels, ood_probs)
auprc = sklearn.metrics.auc(recall, precision)
print(f'SNGP AUPRC: {auprc:.4f}')
SNGP AUPRC: 0.9039

זה תואם את ביצועי ה-SNGP שדווחו במדד CLINC OOS תחת קווי בסיס אי הוודאות .

לאחר מכן, בחנו את איכות המודל בכיול אי-ודאות , כלומר האם ההסתברות החזויה של המודל תואמת את דיוק הניבוי שלו. מודל מכויל היטב נחשב ראוי לאמון, שכן, למשל, ההסתברות הניבוי שלו \(p(x)=0.8\) פירושה שהמודל נכון ב-80% מהמקרים.

prob_true, prob_pred = sklearn.calibration.calibration_curve(
    ood_labels, ood_probs, n_bins=10, strategy='quantile')
plt.plot(prob_pred, prob_true)

plt.plot([0., 1.], [0., 1.], c='k', linestyle="--")
plt.xlabel('Predictive Probability')
plt.ylabel('Predictive Accuracy')
plt.title('Calibration Plots, SNGP')

plt.show()

png

משאבים וקריאה נוספת