يوم مجتمع ML هو 9 نوفمبر! الانضمام إلينا للحصول على التحديثات من TensorFlow، JAX، وأكثر معرفة المزيد

صقل نموذج بيرت

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر انظر نموذج TF Hub

في هذا المثال ، سنعمل من خلال ضبط نموذج BERT باستخدام حزمة PIP لنماذج tensorflow.

نموذج بيرت pretrained ويستند هذا البرنامج التعليمي على متاح في أيضا TensorFlow محور ، لمعرفة كيفية استخدامها الرجوع إلى محور الملحق

اقامة

قم بتثبيت حزمة TensorFlow Model Garden pip

  • tf-models-official غير مستقرة نموذج حديقة الحزمة. ملاحظة أنه قد لا تتضمن التغييرات الأخيرة في tensorflow_models الريبو جيثب. لتضمين أحدث التغييرات، يمكنك تثبيت tf-models-nightly ، والذي هو حزمة نموذج حديقة ليلا إنشاؤها يوميا تلقائيا.
  • سيقوم pip بتثبيت جميع النماذج والاعتماديات تلقائيًا.
pip install -q -U tensorflow-text
pip install -q tf-models-official==2.4.0

الواردات

import os

import numpy as np
import matplotlib.pyplot as plt

import tensorflow as tf

import tensorflow_hub as hub
import tensorflow_datasets as tfds
tfds.disable_progress_bar()

from official.modeling import tf_utils
from official import nlp
from official.nlp import bert

# Load the required submodules
import official.nlp.optimization
import official.nlp.bert.bert_models
import official.nlp.bert.configs
import official.nlp.bert.run_classifier
import official.nlp.bert.tokenization
import official.nlp.data.classifier_data_lib
import official.nlp.modeling.losses
import official.nlp.modeling.models
import official.nlp.modeling.networks
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_addons/utils/ensure_tf_install.py:67: UserWarning: Tensorflow Addons supports using Python ops for all Tensorflow versions above or equal to 2.3.0 and strictly below 2.6.0 (nightly versions are not supported). 
 The versions of TensorFlow you are currently using is 2.6.0 and is not supported. 
Some things might work, some things might not.
If you were to encounter a bug, do not file an issue.
If you want to make sure you're using a tested and supported configuration, either change the TensorFlow version or the TensorFlow Addons's version. 
You can find the compatibility matrix in TensorFlow Addon's readme:
https://github.com/tensorflow/addons
  UserWarning,

موارد

يحتوي هذا الدليل على التكوين والمفردات ونقطة تفتيش سابقة التدريب المستخدمة في هذا البرنامج التعليمي:

gs_folder_bert = "gs://cloud-tpu-checkpoints/bert/v3/uncased_L-12_H-768_A-12"
tf.io.gfile.listdir(gs_folder_bert)
['bert_config.json',
 'bert_model.ckpt.data-00000-of-00001',
 'bert_model.ckpt.index',
 'vocab.txt']

يمكنك الحصول على المدربين قبل بيرت التشفير من TensorFlow المحور :

hub_url_bert = "https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/3"

البيانات

في هذا المثال استخدمنا بيانات GLUE MRPC من TFDS .

لم يتم إعداد مجموعة البيانات هذه بحيث يمكن إدخالها مباشرةً في نموذج BERT ، لذلك يتعامل هذا القسم أيضًا مع المعالجة المسبقة اللازمة.

احصل على مجموعة البيانات من مجموعات بيانات TensorFlow

مجموعة Microsoft Research Paraphrase Corpus (Dolan & Brockett ، 2005) عبارة عن مجموعة من أزواج الجمل المستخرجة تلقائيًا من مصادر الأخبار عبر الإنترنت ، مع التعليقات التوضيحية البشرية حول ما إذا كانت الجمل في الزوج متكافئة لغويًا.

  • عدد الملصقات: 2.
  • حجم مجموعة بيانات التدريب: 3668.
  • حجم مجموعة بيانات التقييم: 408.
  • الحد الأقصى لطول التسلسل لمجموعة بيانات التدريب والتقييم: 128.
glue, info = tfds.load('glue/mrpc', with_info=True,
                       # It's small, load the whole dataset
                       batch_size=-1)
WARNING:tensorflow:From /home/kbuilder/.local/lib/python3.7/site-packages/tensorflow_datasets/core/dataset_builder.py:622: get_single_element (from tensorflow.python.data.experimental.ops.get_single_element) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.data.Dataset.get_single_element()`.
2021-08-19 11:26:56.046711: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-19 11:26:56.055242: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-19 11:26:56.056228: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-19 11:26:56.057937: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2021-08-19 11:26:56.058570: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-19 11:26:56.059629: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-19 11:26:56.060526: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-19 11:26:56.661471: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-19 11:26:56.662451: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-19 11:26:56.663279: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-19 11:26:56.664195: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1510] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 14648 MB memory:  -> device: 0, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:05.0, compute capability: 7.0
WARNING:tensorflow:From /home/kbuilder/.local/lib/python3.7/site-packages/tensorflow_datasets/core/dataset_builder.py:622: get_single_element (from tensorflow.python.data.experimental.ops.get_single_element) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.data.Dataset.get_single_element()`.
2021-08-19 11:26:57.012380: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:185] None of the MLIR Optimization Passes are enabled (registered 2)
list(glue.keys())
['train', 'validation', 'test']

و info يصف كائن مجموعة البيانات وانها الميزات:

info.features
FeaturesDict({
    'idx': tf.int32,
    'label': ClassLabel(shape=(), dtype=tf.int64, num_classes=2),
    'sentence1': Text(shape=(), dtype=tf.string),
    'sentence2': Text(shape=(), dtype=tf.string),
})

الفئتان هما:

info.features['label'].names
['not_equivalent', 'equivalent']

فيما يلي مثال واحد من مجموعة التدريب:

glue_train = glue['train']

for key, value in glue_train.items():
  print(f"{key:9s}: {value[0].numpy()}")
idx      : 1680
label    : 0
sentence1: b'The identical rovers will act as robotic geologists , searching for evidence of past water .'
sentence2: b'The rovers act as robotic geologists , moving on six wheels .'

رمز BERT

لضبط نموذج تم تدريبه مسبقًا ، يجب أن تتأكد من أنك تستخدم نفس الترميز والمفردات وتخطيط الفهرس تمامًا كما استخدمته أثناء التدريب.

تمت كتابة رمز BERT المستخدم في هذا البرنامج التعليمي بلغة Python الخالصة (لم يتم إنشاؤه من عمليات TensorFlow). لذلك لا يمكن إلا أن تركبه في نموذج ك keras.layer مثل يمكنك مع preprocessing.TextVectorization .

يعيد الكود التالي إنشاء الرمز المميز الذي تم استخدامه بواسطة النموذج الأساسي:

# Set up tokenizer to generate Tensorflow dataset
tokenizer = bert.tokenization.FullTokenizer(
    vocab_file=os.path.join(gs_folder_bert, "vocab.txt"),
     do_lower_case=True)

print("Vocab size:", len(tokenizer.vocab))
Vocab size: 30522

قم بترميز جملة:

tokens = tokenizer.tokenize("Hello TensorFlow!")
print(tokens)
ids = tokenizer.convert_tokens_to_ids(tokens)
print(ids)
['hello', 'tensor', '##flow', '!']
[7592, 23435, 12314, 999]

المعالجة المسبقة للبيانات

قام القسم بمعالجة مجموعة البيانات يدويًا مسبقًا بالتنسيق الذي يتوقعه النموذج.

مجموعة البيانات هذه صغيرة ، لذا يمكن إجراء المعالجة المسبقة بسرعة وسهولة في الذاكرة. لمجموعات البيانات الكبيرة و tf_models تتضمن مكتبة بعض الأدوات لتجهيزها وإعادة تسلسل واحد البيانات. انظر الملحق: إعادة ترميز بيانات كبيرة للحصول على التفاصيل.

تشفير الجمل

يتوقع النموذج أن تكون جمل المدخلات متسلسلة معًا. ومن المتوقع أن تبدأ مع هذه المدخلات [CLS] "هذه هي مشكلة تصنيف" رمزية، ويجب أن تنتهي كل جملة مع [SEP] "فاصل" رمز:

tokenizer.convert_tokens_to_ids(['[CLS]', '[SEP]'])
[101, 102]

تبدأ من خلال ترميز كل الجمل في حين إلحاق [SEP] رمز، وتعبئتها في-التنسورات خشنة:

def encode_sentence(s):
   tokens = list(tokenizer.tokenize(s.numpy()))
   tokens.append('[SEP]')
   return tokenizer.convert_tokens_to_ids(tokens)

sentence1 = tf.ragged.constant([
    encode_sentence(s) for s in glue_train["sentence1"]])
sentence2 = tf.ragged.constant([
    encode_sentence(s) for s in glue_train["sentence2"]])
print("Sentence1 shape:", sentence1.shape.as_list())
print("Sentence2 shape:", sentence2.shape.as_list())
Sentence1 shape: [3668, None]
Sentence2 shape: [3668, None]

الآن أرفقت [CLS] رمز، وسلسلة من التنسورات خشنة لتشكيل واحد input_word_ids موتر لكل المثال. RaggedTensor.to_tensor() صفر منصات لأطول تسلسل.

cls = [tokenizer.convert_tokens_to_ids(['[CLS]'])]*sentence1.shape[0]
input_word_ids = tf.concat([cls, sentence1, sentence2], axis=-1)
_ = plt.pcolormesh(input_word_ids.to_tensor())

بي إن جي

نوع القناع والمدخلات

يتوقع النموذج مدخلين إضافيين:

  • قناع الإدخال
  • نوع الإدخال

يسمح القناع للنموذج بالتمييز بشكل واضح بين المحتوى والحشو. قناع لديه نفس شكل input_word_ids ، ويحتوي على 1 في أي مكان input_word_ids لا الحشو.

input_mask = tf.ones_like(input_word_ids).to_tensor()

plt.pcolormesh(input_mask)
<matplotlib.collections.QuadMesh at 0x7f05206b9790>

بي إن جي

"نوع إدخال" أيضا لديه نفس الشكل، ولكن داخل المنطقة غير مبطن، ويحتوي على 0 أو 1 يشير إلى الذي حكم الرمز المميز هو جزء من.

type_cls = tf.zeros_like(cls)
type_s1 = tf.zeros_like(sentence1)
type_s2 = tf.ones_like(sentence2)
input_type_ids = tf.concat([type_cls, type_s1, type_s2], axis=-1).to_tensor()

plt.pcolormesh(input_type_ids)
<matplotlib.collections.QuadMesh at 0x7f0520116d90>

بي إن جي

ضعها سوية

جمع ما سبق توزيع التعليمات البرمجية النصية إلى وظيفة واحدة، وتطبيقه على كل انقسام glue/mrpc البيانات.

def encode_sentence(s, tokenizer):
   tokens = list(tokenizer.tokenize(s))
   tokens.append('[SEP]')
   return tokenizer.convert_tokens_to_ids(tokens)

def bert_encode(glue_dict, tokenizer):
  num_examples = len(glue_dict["sentence1"])

  sentence1 = tf.ragged.constant([
      encode_sentence(s, tokenizer)
      for s in np.array(glue_dict["sentence1"])])
  sentence2 = tf.ragged.constant([
      encode_sentence(s, tokenizer)
       for s in np.array(glue_dict["sentence2"])])

  cls = [tokenizer.convert_tokens_to_ids(['[CLS]'])]*sentence1.shape[0]
  input_word_ids = tf.concat([cls, sentence1, sentence2], axis=-1)

  input_mask = tf.ones_like(input_word_ids).to_tensor()

  type_cls = tf.zeros_like(cls)
  type_s1 = tf.zeros_like(sentence1)
  type_s2 = tf.ones_like(sentence2)
  input_type_ids = tf.concat(
      [type_cls, type_s1, type_s2], axis=-1).to_tensor()

  inputs = {
      'input_word_ids': input_word_ids.to_tensor(),
      'input_mask': input_mask,
      'input_type_ids': input_type_ids}

  return inputs
glue_train = bert_encode(glue['train'], tokenizer)
glue_train_labels = glue['train']['label']

glue_validation = bert_encode(glue['validation'], tokenizer)
glue_validation_labels = glue['validation']['label']

glue_test = bert_encode(glue['test'], tokenizer)
glue_test_labels  = glue['test']['label']

تم تحويل كل مجموعة فرعية من البيانات إلى قاموس ميزات ومجموعة من التسميات. كل ميزة في قاموس الإدخال لها نفس الشكل ، ويجب أن يتطابق عدد التسميات مع:

for key, value in glue_train.items():
  print(f'{key:15s} shape: {value.shape}')

print(f'glue_train_labels shape: {glue_train_labels.shape}')
input_word_ids  shape: (3668, 103)
input_mask      shape: (3668, 103)
input_type_ids  shape: (3668, 103)
glue_train_labels shape: (3668,)

الموديل

بناء النموذج

تتمثل الخطوة الأولى في تنزيل التكوين للنموذج المدرب مسبقًا.

import json

bert_config_file = os.path.join(gs_folder_bert, "bert_config.json")
config_dict = json.loads(tf.io.gfile.GFile(bert_config_file).read())

bert_config = bert.configs.BertConfig.from_dict(config_dict)

config_dict
{'attention_probs_dropout_prob': 0.1,
 'hidden_act': 'gelu',
 'hidden_dropout_prob': 0.1,
 'hidden_size': 768,
 'initializer_range': 0.02,
 'intermediate_size': 3072,
 'max_position_embeddings': 512,
 'num_attention_heads': 12,
 'num_hidden_layers': 12,
 'type_vocab_size': 2,
 'vocab_size': 30522}

و config يحدد جوهر بيرت النموذجي، الذي هو نموذج للتنبؤ Keras مخرجات num_classes من المدخلات مع أقصى تسلسل طول max_seq_length .

تقوم هذه الوظيفة بإرجاع كل من المشفر والمصنف.

bert_classifier, bert_encoder = bert.bert_models.classifier_model(
    bert_config, num_labels=2)

يحتوي المصنف على ثلاثة مدخلات ومخرج واحد:

tf.keras.utils.plot_model(bert_classifier, show_shapes=True, dpi=48)

بي إن جي

قم بتشغيله على مجموعة اختبار من البيانات 10 أمثلة من مجموعة التدريب. الإخراج هو سجلات الفئتين:

glue_batch = {key: val[:10] for key, val in glue_train.items()}

bert_classifier(
    glue_batch, training=True
).numpy()
array([[-0.2307785 ,  0.14490062],
       [-0.09524915,  0.1295139 ],
       [-0.14503807,  0.19079085],
       [-0.2493319 ,  0.29745924],
       [-0.25108814, -0.09775029],
       [-0.02554443, -0.07443134],
       [-0.34417343,  0.00068308],
       [-0.13155738,  0.10524555],
       [-0.39608416, -0.14741066],
       [-0.2702508 , -0.02493864]], dtype=float32)

و TransformerEncoder في وسط المصنف سبق هو bert_encoder .

يتفقد التشفير، ونحن نرى المكدس من Transformer طبقات متصلة نفس تلك ثلاثة مداخل:

tf.keras.utils.plot_model(bert_encoder, show_shapes=True, dpi=48)

بي إن جي

قم باستعادة أوزان جهاز التشفير

عند إنشاء جهاز التشفير يتم تهيئته بشكل عشوائي. استعادة أوزان جهاز التشفير من نقطة التفتيش:

checkpoint = tf.train.Checkpoint(encoder=bert_encoder)
checkpoint.read(
    os.path.join(gs_folder_bert, 'bert_model.ckpt')).assert_consumed()
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f047c7d6e50>

قم بإعداد المُحسِّن

بيرت يتبنى محسن آدم مع الوزن الاضمحلال (ويعرف أيضا باسم " AdamW "). كما أنه يستخدم جدول معدل التعلم الذي يسخن أولاً من 0 ثم يتحلل إلى 0.

# Set up epochs and steps
epochs = 3
batch_size = 32
eval_batch_size = 32

train_data_size = len(glue_train_labels)
steps_per_epoch = int(train_data_size / batch_size)
num_train_steps = steps_per_epoch * epochs
warmup_steps = int(epochs * train_data_size * 0.1 / batch_size)

# creates an optimizer with learning rate schedule
optimizer = nlp.optimization.create_optimizer(
    2e-5, num_train_steps=num_train_steps, num_warmup_steps=warmup_steps)

هذا إلى ظهور AdamWeightDecay محسن مع مجموعة جدول معدل التعلم:

type(optimizer)
official.nlp.optimization.AdamWeightDecay

لمشاهدة مثال لكيفية تخصيص محسن والجدول الزمني انها، راجع محسن جدول الملحق .

تدريب النموذج

المقياس هو الدقة ونستخدم الانتروبيا المتقطعة المتفرقة كخسارة.

metrics = [tf.keras.metrics.SparseCategoricalAccuracy('accuracy', dtype=tf.float32)]
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

bert_classifier.compile(
    optimizer=optimizer,
    loss=loss,
    metrics=metrics)

bert_classifier.fit(
      glue_train, glue_train_labels,
      validation_data=(glue_validation, glue_validation_labels),
      batch_size=32,
      epochs=epochs)
Epoch 1/3
115/115 [==============================] - 38s 222ms/step - loss: 0.6067 - accuracy: 0.6737 - val_loss: 0.5166 - val_accuracy: 0.7574
Epoch 2/3
115/115 [==============================] - 24s 211ms/step - loss: 0.4362 - accuracy: 0.8062 - val_loss: 0.3850 - val_accuracy: 0.8137
Epoch 3/3
115/115 [==============================] - 24s 211ms/step - loss: 0.2994 - accuracy: 0.8912 - val_loss: 0.3774 - val_accuracy: 0.8309
<keras.callbacks.History at 0x7f04c010b210>

قم الآن بتشغيل النموذج الدقيق على مثال مخصص لترى أنه يعمل.

ابدأ بترميز بعض أزواج الجمل:

my_examples = bert_encode(
    glue_dict = {
        'sentence1':[
            'The rain in Spain falls mainly on the plain.',
            'Look I fine tuned BERT.'],
        'sentence2':[
            'It mostly rains on the flat lands of Spain.',
            'Is it working? This does not match.']
    },
    tokenizer=tokenizer)

نموذج يجب أن التقرير الطبقة 1 "مباراة" لأول مثال والدرجة 0 "عدم تطابق" للمرة الثانية:

result = bert_classifier(my_examples, training=False)

result = tf.argmax(result).numpy()
result
array([1, 0])
np.array(info.features['label'].names)[result]
array(['equivalent', 'not_equivalent'], dtype='<U14')

احفظ النموذج

غالبا ما يكون الهدف من تدريب النموذج هو لاستخدامها لشيء، لذلك تصدير نموذج ومن ثم استعادته للتأكد من أنه يعمل.

export_dir='./saved_model'
tf.saved_model.save(bert_classifier, export_dir=export_dir)
2021-08-19 11:30:12.946332: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
WARNING:absl:Found untraced functions such as self_attention_layer_call_fn, self_attention_layer_call_and_return_conditional_losses, dropout_layer_call_fn, dropout_layer_call_and_return_conditional_losses, self_attention_layer_norm_layer_call_fn while saving (showing 5 of 900). These functions will not be directly callable after loading.
INFO:tensorflow:Assets written to: ./saved_model/assets
INFO:tensorflow:Assets written to: ./saved_model/assets
reloaded = tf.saved_model.load(export_dir)
reloaded_result = reloaded([my_examples['input_word_ids'],
                            my_examples['input_mask'],
                            my_examples['input_type_ids']], training=False)

original_result = bert_classifier(my_examples, training=False)

# The results are (nearly) identical:
print(original_result.numpy())
print()
print(reloaded_result.numpy())
[[-1.1162528   1.014004  ]
 [ 0.9412503  -0.72278297]]

[[-1.1162527  1.0140039]
 [ 0.94125   -0.7227829]]

زائدة

إعادة تشفير مجموعة بيانات كبيرة

هذا البرنامج التعليمي قمت بإعادة تشفير مجموعة البيانات في الذاكرة للتوضيح.

وكان هذا ممكنا فقط لأن glue/mrpc هو مجموعة بيانات صغيرة جدا. للتعامل مع قواعد البيانات الكبيرة tf_models مكتبة تضم بعض الأدوات لمعالجة وإعادة ترميز مجموعة بيانات للتدريب الفعال.

تتمثل الخطوة الأولى في وصف ميزات مجموعة البيانات التي يجب تغييرها:

processor = nlp.data.classifier_data_lib.TfdsProcessor(
    tfds_params="dataset=glue/mrpc,text_key=sentence1,text_b_key=sentence2",
    process_text_fn=bert.tokenization.convert_to_unicode)

ثم قم بتطبيق التحويل لإنشاء ملفات TFRecord جديدة.

# Set up output of training and evaluation Tensorflow dataset
train_data_output_path="./mrpc_train.tf_record"
eval_data_output_path="./mrpc_eval.tf_record"

max_seq_length = 128
batch_size = 32
eval_batch_size = 32

# Generate and save training data into a tf record file
input_meta_data = (
    nlp.data.classifier_data_lib.generate_tf_record_from_data_file(
      processor=processor,
      data_dir=None,  # It is `None` because data is from tfds, not local dir.
      tokenizer=tokenizer,
      train_data_output_path=train_data_output_path,
      eval_data_output_path=eval_data_output_path,
      max_seq_length=max_seq_length))

وأخيرا إنشاء tf.data أنابيب المدخلات من تلك الملفات TFRecord:

training_dataset = bert.run_classifier.get_dataset_fn(
    train_data_output_path,
    max_seq_length,
    batch_size,
    is_training=True)()

evaluation_dataset = bert.run_classifier.get_dataset_fn(
    eval_data_output_path,
    max_seq_length,
    eval_batch_size,
    is_training=False)()

الناتج tf.data.Datasets عودة (features, labels) أزواج، كما هو متوقع من قبل keras.Model.fit :

training_dataset.element_spec
({'input_word_ids': TensorSpec(shape=(32, 128), dtype=tf.int32, name=None),
  'input_mask': TensorSpec(shape=(32, 128), dtype=tf.int32, name=None),
  'input_type_ids': TensorSpec(shape=(32, 128), dtype=tf.int32, name=None)},
 TensorSpec(shape=(32,), dtype=tf.int32, name=None))

قم بإنشاء tf.data.Dataset للتدريب والتقييم

إذا كنت بحاجة إلى تعديل تحميل البيانات ، فإليك بعض التعليمات البرمجية للبدء:

def create_classifier_dataset(file_path, seq_length, batch_size, is_training):
  """Creates input dataset from (tf)records files for train/eval."""
  dataset = tf.data.TFRecordDataset(file_path)
  if is_training:
    dataset = dataset.shuffle(100)
    dataset = dataset.repeat()

  def decode_record(record):
    name_to_features = {
      'input_ids': tf.io.FixedLenFeature([seq_length], tf.int64),
      'input_mask': tf.io.FixedLenFeature([seq_length], tf.int64),
      'segment_ids': tf.io.FixedLenFeature([seq_length], tf.int64),
      'label_ids': tf.io.FixedLenFeature([], tf.int64),
    }
    return tf.io.parse_single_example(record, name_to_features)

  def _select_data_from_record(record):
    x = {
        'input_word_ids': record['input_ids'],
        'input_mask': record['input_mask'],
        'input_type_ids': record['segment_ids']
    }
    y = record['label_ids']
    return (x, y)

  dataset = dataset.map(decode_record,
                        num_parallel_calls=tf.data.AUTOTUNE)
  dataset = dataset.map(
      _select_data_from_record,
      num_parallel_calls=tf.data.AUTOTUNE)
  dataset = dataset.batch(batch_size, drop_remainder=is_training)
  dataset = dataset.prefetch(tf.data.AUTOTUNE)
  return dataset
# Set up batch sizes
batch_size = 32
eval_batch_size = 32

# Return Tensorflow dataset
training_dataset = create_classifier_dataset(
    train_data_output_path,
    input_meta_data['max_seq_length'],
    batch_size,
    is_training=True)

evaluation_dataset = create_classifier_dataset(
    eval_data_output_path,
    input_meta_data['max_seq_length'],
    eval_batch_size,
    is_training=False)
training_dataset.element_spec
({'input_word_ids': TensorSpec(shape=(32, 128), dtype=tf.int64, name=None),
  'input_mask': TensorSpec(shape=(32, 128), dtype=tf.int64, name=None),
  'input_type_ids': TensorSpec(shape=(32, 128), dtype=tf.int64, name=None)},
 TensorSpec(shape=(32,), dtype=tf.int64, name=None))

TFModels BERT على TFHub

يمكنك الحصول على نموذج بيرت من على الرف من TFHub . فإنه لن يكون من الصعب لإضافة رأس التصنيف على رأس هذه hub.KerasLayer

# Note: 350MB download.
import tensorflow_hub as hub

hub_encoder = hub.KerasLayer(f"https://tfhub.dev/tensorflow/{hub_model_name}/3",
                             trainable=True)

print(f"The Hub encoder has {len(hub_encoder.trainable_variables)} trainable variables")
The Hub encoder has 199 trainable variables

قم باختبار تشغيله على مجموعة من البيانات:

result = hub_encoder(
    inputs=dict(
        input_word_ids=glue_train['input_word_ids'][:10],
        input_mask=glue_train['input_mask'][:10],
        input_type_ids=glue_train['input_type_ids'][:10],),
    training=False,
)

print("Pooled output shape:", result['pooled_output'].shape)
print("Sequence output shape:", result['sequence_output'].shape)
Pooled output shape: (10, 768)
Sequence output shape: (10, 103, 768)

في هذه المرحلة ، سيكون من السهل إضافة رأس تصنيف بنفسك.

و bert_models.classifier_model وظيفة يمكن أيضا بناء المصنف على التشفير من TensorFlow المحور:

hub_classifier = nlp.modeling.models.BertClassifier(
    bert_encoder,
    num_classes=2,
    dropout_rate=0.1,
    initializer=tf.keras.initializers.TruncatedNormal(
        stddev=0.02))

الجانب السلبي الوحيد لتحميل هذا النموذج من TFHub هو عدم استعادة بنية طبقات keras الداخلية. لذلك يصعب فحص النموذج أو تعديله. و BertEncoder النموذج هو الآن طبقة واحدة:

tf.keras.utils.plot_model(hub_classifier, show_shapes=True, dpi=64)

بي إن جي

try:
  tf.keras.utils.plot_model(hub_encoder, show_shapes=True, dpi=64)
  assert False
except Exception as e:
  print(f"{type(e).__name__}: {e}")
AttributeError: 'KerasLayer' object has no attribute 'layers'

بناء نموذج منخفض المستوى

إذا كنت في حاجة الى المزيد من السيطرة على بناء نموذج ومن الجدير بالذكر أن classifier_model وظيفة استخدمت في وقت سابق هو في الحقيقة مجرد غلاف رقيق على nlp.modeling.networks.BertEncoder و nlp.modeling.models.BertClassifier الطبقات. فقط تذكر أنه إذا بدأت في تعديل البنية ، فقد لا يكون صحيحًا أو من الممكن إعادة تحميل نقطة التفتيش المدربة مسبقًا ، لذا ستحتاج إلى إعادة التدريب من نقطة الصفر.

بناء برنامج التشفير:

bert_encoder_config = config_dict.copy()

# You need to rename a few fields to make this work:
bert_encoder_config['attention_dropout_rate'] = bert_encoder_config.pop('attention_probs_dropout_prob')
bert_encoder_config['activation'] = tf_utils.get_activation(bert_encoder_config.pop('hidden_act'))
bert_encoder_config['dropout_rate'] = bert_encoder_config.pop('hidden_dropout_prob')
bert_encoder_config['initializer'] = tf.keras.initializers.TruncatedNormal(
          stddev=bert_encoder_config.pop('initializer_range'))
bert_encoder_config['max_sequence_length'] = bert_encoder_config.pop('max_position_embeddings')
bert_encoder_config['num_layers'] = bert_encoder_config.pop('num_hidden_layers')

bert_encoder_config
{'hidden_size': 768,
 'intermediate_size': 3072,
 'num_attention_heads': 12,
 'type_vocab_size': 2,
 'vocab_size': 30522,
 'attention_dropout_rate': 0.1,
 'activation': <function official.modeling.activations.gelu.gelu(x)>,
 'dropout_rate': 0.1,
 'initializer': <keras.initializers.initializers_v2.TruncatedNormal at 0x7f006c251d10>,
 'max_sequence_length': 512,
 'num_layers': 12}
manual_encoder = nlp.modeling.networks.BertEncoder(**bert_encoder_config)

استعادة الأوزان:

checkpoint = tf.train.Checkpoint(encoder=manual_encoder)
checkpoint.read(
    os.path.join(gs_folder_bert, 'bert_model.ckpt')).assert_consumed()
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f0064723dd0>

قم بإجراء الاختبار:

result = manual_encoder(my_examples, training=True)

print("Sequence output shape:", result[0].shape)
print("Pooled output shape:", result[1].shape)
Sequence output shape: (2, 23, 768)
Pooled output shape: (2, 768)

لفها في مصنف:

manual_classifier = nlp.modeling.models.BertClassifier(
        bert_encoder,
        num_classes=2,
        dropout_rate=bert_encoder_config['dropout_rate'],
        initializer=bert_encoder_config['initializer'])
manual_classifier(my_examples, training=True).numpy()
array([[ 0.19574928, -0.09590703],
       [-0.3455575 ,  0.12091695]], dtype=float32)

Optimizers والجداول

تم إنشاء محسن تستخدم لتدريب نموذج باستخدام nlp.optimization.create_optimizer وظيفة:

optimizer = nlp.optimization.create_optimizer(
    2e-5, num_train_steps=num_train_steps, num_warmup_steps=warmup_steps)

يقوم هذا المجمع عالي المستوى بإعداد جداول معدل التعلم والمحسن.

جدول معدل التعلم الأساسي المستخدم هنا هو انحلال خطي إلى الصفر خلال فترة التدريب:

epochs = 3
batch_size = 32
eval_batch_size = 32

train_data_size = len(glue_train_labels)
steps_per_epoch = int(train_data_size / batch_size)
num_train_steps = steps_per_epoch * epochs
decay_schedule = tf.keras.optimizers.schedules.PolynomialDecay(
      initial_learning_rate=2e-5,
      decay_steps=num_train_steps,
      end_learning_rate=0)

plt.plot([decay_schedule(n) for n in range(num_train_steps)])
[<matplotlib.lines.Line2D at 0x7f0065da3c50>]

بي إن جي

هذا، بدوره ملفوفة في WarmUp الجدول الذي خطيا يزيد من معدل التعلم إلى القيمة المستهدفة خلال أول 10٪ من التدريب:

warmup_steps = num_train_steps * 0.1

warmup_schedule = nlp.optimization.WarmUp(
        initial_learning_rate=2e-5,
        decay_schedule_fn=decay_schedule,
        warmup_steps=warmup_steps)

# The warmup overshoots, because it warms up to the `initial_learning_rate`
# following the original implementation. You can set
# `initial_learning_rate=decay_schedule(warmup_steps)` if you don't like the
# overshoot.
plt.plot([warmup_schedule(n) for n in range(num_train_steps)])
[<matplotlib.lines.Line2D at 0x7f0064d33fd0>]

بي إن جي

ثم خلق nlp.optimization.AdamWeightDecay باستخدام هذا الجدول الزمني، وتهيئتها لنموذج بيرت:

optimizer = nlp.optimization.AdamWeightDecay(
        learning_rate=warmup_schedule,
        weight_decay_rate=0.01,
        epsilon=1e-6,
        exclude_from_weight_decay=['LayerNorm', 'layer_norm', 'bias'])