Głębokie uczenie się języka z uwzględnieniem niepewności dzięki BERT-SNGP

Zobacz na TensorFlow.org Uruchom w Google Colab Zobacz na GitHub Pobierz notatnik Zobacz model piasty TF

W samouczku SNGP nauczyłeś się, jak zbudować model SNGP na podstawie głębokiej sieci rezydualnej, aby poprawić jej zdolność do ilościowego określania niepewności. W tym samouczku zastosujesz protokół SNGP do zadania rozumienia języka naturalnego (NLU), budując go na bazie kodera głębokiego BERT, aby poprawić zdolność modelu głębokiego NLU do wykrywania zapytań poza zakresem.

W szczególności będziesz:

  • Zbuduj BERT-SNGP, model BERT z rozszerzeniem SNGP.
  • Załaduj zestaw danych wykrywania intencji CLINC poza zakresem (OOS) .
  • Trenuj model BERT-SNGP.
  • Oceń wydajność modelu BERT-SNGP w kalibracji niepewności i detekcji poza domeną.

Poza CLINC OOS model SNGP został zastosowany do zestawów danych na dużą skalę, takich jak wykrywanie toksyczności Jigsaw oraz do zestawów danych obrazów, takich jak CIFAR-100 i ImageNet . Aby uzyskać wyniki porównawcze SNGP i innych metod niepewności, a także wysokiej jakości implementację z kompleksowymi szkoleniami / skryptami oceny, możesz sprawdzić benchmark Uncertainty Baselines .

Ustawiać

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,

Ten samouczek wymaga wydajnego działania GPU. Sprawdź, czy GPU jest dostępny.

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."""

Najpierw zaimplementuj standardowy klasyfikator BERT, postępując zgodnie z klasyfikacją tekstu za pomocą samouczka BERT . Jako klasyfikatora użyjemy kodera BERT-base oraz wbudowanego elementu ClassificationHead .

Standardowy model BERT

Zbuduj model SNGP

Aby zaimplementować model BERT-SNGP, wystarczy zastąpić ClassificationHead wbudowanym GaussianProcessClassificationHead . Normalizacja widmowa jest już wstępnie zapakowana w tę głowicę klasyfikacyjną. Podobnie jak w samouczku SNGP , dodaj wywołanie zwrotne resetowania kowariancji do modelu, aby model automatycznie resetował estymator kowariancji na początku nowej epoki, aby uniknąć dwukrotnego zliczania tych samych danych.

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)

Załaduj zbiór danych CLINC OOS

Teraz załaduj zestaw danych wykrywania zamiarów CLINC OOS . Ten zbiór danych zawiera 15000 wypowiadanych przez użytkownika zapytań zebranych w ponad 150 klasach intencji, zawiera również 1000 zdań spoza domeny (OOD), które nie są objęte żadną ze znanych klas.

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

Zrób pociąg i dane testowe.

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'])

Utwórz zestaw danych ewaluacyjnych OOD. W tym celu połącz dane testowe clinc_test w domenie i dane clinc_test_oos domeny . Przypiszemy również etykietę 0 do przykładów w domenie i etykietę 1 do przykładów spoza domeny.

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})

Trenuj i oceniaj

Najpierw skonfiguruj podstawowe konfiguracje treningowe.

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>

Oceń wydajność OOD

Oceń, jak dobrze model może wykryć nieznane zapytania spoza domeny. Aby uzyskać rygorystyczną ocenę, użyj utworzonego wcześniej zestawu danych oceny OOD ood_eval_dataset .

Oblicza prawdopodobieństwa OOD jako \(1 - p(x)\), gdzie \(p(x)=softmax(logit(x))\) jest prawdopodobieństwem predykcyjnym.

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

Teraz oceń, jak dobrze wynik niepewności modelu ood_probs przewiduje etykietę spoza domeny. Najpierw oblicz obszar pod krzywą przywołania precyzji (AUPC) dla prawdopodobieństwa OOD vs dokładności wykrywania 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

Odpowiada to wydajności SNGP raportowanej w benchmarku CLINC OOS w ramach Uncertainty Baselines .

Następnie zbadaj jakość modelu w kalibracji niepewności , tj. czy prawdopodobieństwo predykcyjne modelu odpowiada jego dokładności predykcyjnej. Dobrze skalibrowany model jest uważany za godny zaufania, ponieważ na przykład jego prawdopodobieństwo predykcyjne \(p(x)=0.8\) oznacza, że ​​model jest poprawny w 80% przypadków.

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

Zasoby i dalsze czytanie