הצג באתר 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 סטנדרטי
PREPROCESS_HANDLE = 'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3'
MODEL_HANDLE = 'https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/3'
class BertClassifier(tf.keras.Model):
def __init__(self,
num_classes=150, inner_dim=768, dropout_rate=0.1,
**classifier_kwargs):
super().__init__()
self.classifier_kwargs = classifier_kwargs
# Initiate the BERT encoder components.
self.bert_preprocessor = hub.KerasLayer(PREPROCESS_HANDLE, name='preprocessing')
self.bert_hidden_layer = hub.KerasLayer(MODEL_HANDLE, trainable=True, name='bert_encoder')
# Defines the encoder and classification layers.
self.bert_encoder = self.make_bert_encoder()
self.classifier = self.make_classification_head(num_classes, inner_dim, dropout_rate)
def make_bert_encoder(self):
text_inputs = tf.keras.layers.Input(shape=(), dtype=tf.string, name='text')
encoder_inputs = self.bert_preprocessor(text_inputs)
encoder_outputs = self.bert_hidden_layer(encoder_inputs)
return tf.keras.Model(text_inputs, encoder_outputs)
def make_classification_head(self, num_classes, inner_dim, dropout_rate):
return layers.ClassificationHead(
num_classes=num_classes,
inner_dim=inner_dim,
dropout_rate=dropout_rate,
**self.classifier_kwargs)
def call(self, inputs, **kwargs):
encoder_outputs = self.bert_encoder(inputs)
classifier_inputs = encoder_outputs['sequence_output']
return self.classifier(classifier_inputs, **kwargs)
בניית מודל 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
def bert_optimizer(learning_rate,
batch_size=TRAIN_BATCH_SIZE, epochs=TRAIN_EPOCHS,
warmup_rate=0.1):
"""Creates an AdamWeightDecay optimizer with learning rate schedule."""
train_data_size = ds_info.splits['train'].num_examples
steps_per_epoch = int(train_data_size / batch_size)
num_train_steps = steps_per_epoch * epochs
num_warmup_steps = int(warmup_rate * num_train_steps)
# Creates learning schedule.
lr_schedule = tf.keras.optimizers.schedules.PolynomialDecay(
initial_learning_rate=learning_rate,
decay_steps=num_train_steps,
end_learning_rate=0.0)
return optimization.AdamWeightDecay(
learning_rate=lr_schedule,
weight_decay_rate=0.01,
epsilon=1e-6,
exclude_from_weight_decay=['LayerNorm', 'layer_norm', 'bias'])
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
שנבנה קודם לכן.
def oos_predict(model, ood_eval_dataset, **model_kwargs):
oos_labels = []
oos_probs = []
ood_eval_dataset = ood_eval_dataset.batch(EVAL_BATCH_SIZE)
for oos_batch in ood_eval_dataset:
oos_text_batch = oos_batch["text"]
oos_label_batch = oos_batch["label"]
pred_logits = model(oos_text_batch, **model_kwargs)
pred_probs_all = tf.nn.softmax(pred_logits, axis=-1)
pred_probs = tf.reduce_max(pred_probs_all, axis=-1)
oos_labels.append(oos_label_batch)
oos_probs.append(pred_probs)
oos_probs = tf.concat(oos_probs, axis=0)
oos_labels = tf.concat(oos_labels, axis=0)
return oos_probs, oos_labels
מחשב את ההסתברויות של 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()
משאבים וקריאה נוספת
- עיין במדריך SNGP להדרכה מפורטת על יישום SNGP מאפס.
- ראה קווי בסיס לאי- ודאות ליישום מודל SNGP (ושיטות אי-ודאות רבות אחרות) במגוון רחב של מערכי נתונים בנצ'מרק (למשל, CIFAR , ImageNet , זיהוי רעילות בפאזל וכו').
- להבנה מעמיקה יותר של שיטת SNGP, עיין במאמר Simple and Principled Uncertainty Estimation with Deep Deep Learning דטרמיניסטית באמצעות Distance Awareness .