इस पेज का अनुवाद Cloud Translation API से किया गया है.
Switch to English

Fine-tuning a BERT model

TensorFlow.org पर देखें Google Colab में चलाएं GitHub पर स्रोत देखें नोटबुक डाउनलोड करें

इस उदाहरण में, हम टेंसरफ़्लो-मॉडल पीआईपी पैकेज का उपयोग करके एक बीईआरटी मॉडल को ठीक-ट्यूनिंग के माध्यम से काम करेंगे।

इस ट्यूटोरियल पर आधारित BERT मॉडल TensorFlow हब पर भी उपलब्ध है, यह देखने के लिए कि इसे हब परिशिष्ट के संदर्भ में कैसे उपयोग किया जाए।

सेट अप

TensorFlow मॉडल गार्डन पाइप पैकेज स्थापित करें

  • tf-models-nightly model tf-models-nightly रात्रि मॉडल गार्डन पैकेज है जो रोजाना स्वचालित रूप से बनाया जाता है।
  • पाइप स्वचालित रूप से सभी मॉडल और निर्भरता स्थापित करेगा।
pip install -q tf-nightly
pip install -q tf-models-nightly

आयात

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.6/site-packages/tensorflow_addons/utils/ensure_tf_install.py:44: UserWarning: You are currently using a nightly version of TensorFlow (2.3.0-dev20200623). 
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,

साधन

इस निर्देशिका में कॉन्फ़िगरेशन, शब्दावली और इस ट्यूटोरियल में उपयोग की जाने वाली पूर्व-प्रशिक्षित चौकी है:

gs_folder_bert = "gs://cloud-tpu-checkpoints/bert/keras_bert/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 से एक पूर्व प्रशिक्षित BERT एनकोडर प्राप्त कर सकते हैं:

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

आँकड़े

इस उदाहरण के लिए हमने TFDS से GLUE MRPC डेटासेट का उपयोग किया।

यह डेटासेट सेट नहीं किया गया है ताकि इसे सीधे BERT मॉडल में खिलाया जा सके, इसलिए यह अनुभाग आवश्यक प्रीप्रोसेसिंग को भी हैंडल करता है।

TensorFlow Datasets से डेटासेट प्राप्त करें

Microsoft अनुसंधान 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)
Downloading and preparing dataset glue/mrpc/1.0.0 (download: 1.43 MiB, generated: Unknown size, total: 1.43 MiB) to /home/kbuilder/tensorflow_datasets/glue/mrpc/1.0.0...

/usr/lib/python3/dist-packages/urllib3/connectionpool.py:860: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  InsecureRequestWarning)
/usr/lib/python3/dist-packages/urllib3/connectionpool.py:860: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  InsecureRequestWarning)
/usr/lib/python3/dist-packages/urllib3/connectionpool.py:860: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  InsecureRequestWarning)

Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/glue/mrpc/1.0.0.incomplete1RTRDK/glue-train.tfrecord
Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/glue/mrpc/1.0.0.incomplete1RTRDK/glue-validation.tfrecord
Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/glue/mrpc/1.0.0.incomplete1RTRDK/glue-test.tfrecord
Dataset glue downloaded and prepared to /home/kbuilder/tensorflow_datasets/glue/mrpc/1.0.0. Subsequent calls will reuse this data.

list(glue.keys())
['test', 'train', 'validation']

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 टोकन टोकन शुद्ध पायथन में लिखा गया है (यह TensorFlow op से बाहर नहीं बनाया गया है)। तो आप इसे अपने मॉडल में एक keras.layer रूप में प्लग नहीं कर सकते हैं जैसे कि आप preprocessing.TextVectorization कर सकते हैं। keras.layer

निम्न कोड उस टोकनर का पुनर्निर्माण करता है जो आधार मॉडल द्वारा उपयोग किया गया था:

# 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 टेन्सर बनाने के लिए input_word_idsRaggedTensor.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())

png

मास्क और इनपुट प्रकार

मॉडल को दो अतिरिक्त इनपुट की उम्मीद है:

  • इनपुट मास्क
  • इनपुट प्रकार

मुखौटा सामग्री और गद्दी के बीच के अंतर को साफ करने की अनुमति देता है। मास्क का आकार input_word_ids के 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 0x7f82246c0cf8>

png

"इनपुट प्रकार" का आकार भी एक समान होता है, लेकिन गैर-गद्देदार क्षेत्र के अंदर, 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 0x7f8224668438>

png

इसे एक साथ रखें

उपरोक्त टेक्स्ट पार्सिंग कोड को किसी एकल फ़ंक्शन में इकट्ठा करें, और इसे 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 कोर BERT मॉडल को परिभाषित करता है, जो कि अधिकतम अनुक्रम लंबाई max_seq_length साथ इनपुट से num_classes के आउटपुट की भविष्यवाणी करने के लिए एक Keras मॉडल है।

यह फ़ंक्शन एनकोडर और क्लासिफायरियर दोनों को लौटाता है।

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)

png

प्रशिक्षण सेट से डेटा 10 उदाहरणों के एक परीक्षण बैच पर इसे चलाएं। आउटपुट दो वर्गों के लिए लॉग है:

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

bert_classifier(
    glue_batch, training=True
).numpy()
array([[ 0.05488977, -0.26042116],
       [ 0.11358108, -0.09727937],
       [ 0.14350253, -0.2465629 ],
       [ 0.2775127 , -0.09028438],
       [ 0.3606584 , -0.17138724],
       [ 0.3287397 , -0.14672714],
       [ 0.18621178, -0.13080403],
       [ 0.21898738,  0.10716071],
       [ 0.18413854, -0.13491377],
       [ 0.20307963, -0.05396855]], dtype=float32)

TransformerEncoder वर्गीकारक के केंद्र में ऊपर है bert_encoder

एनकोडर का निरीक्षण करने पर, हम उन्हीं तीन इनपुटों से जुड़ी Transformer परतों के ढेर को देखते हैं:

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

png

एनकोडर भार को पुनर्स्थापित करें

जब निर्मित एनकोडर को बेतरतीब ढंग से आरंभ किया जाता है। चेकपॉइंट से एन्कोडर के वज़न को पुनर्स्थापित करें:

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

ऑप्टिमाइज़र सेट करें

BERT वजन घटाने (उर्फ " एडमडब्ल्यू ") के साथ एडम ऑप्टिमाइज़र को गोद लेता है। यह एक सीखने की दर अनुसूची को भी नियोजित करता है जो सबसे पहले 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 [==============================] - 25s 218ms/step - loss: 0.7047 - accuracy: 0.6101 - val_loss: 0.5219 - val_accuracy: 0.7181
Epoch 2/3
115/115 [==============================] - 24s 210ms/step - loss: 0.5068 - accuracy: 0.7560 - val_loss: 0.5047 - val_accuracy: 0.7794
Epoch 3/3
115/115 [==============================] - 24s 209ms/step - loss: 0.3812 - accuracy: 0.8332 - val_loss: 0.4839 - val_accuracy: 0.8137

<tensorflow.python.keras.callbacks.History at 0x7f82107c8cf8>

अब एक कस्टम उदाहरण पर ठीक-ट्यून किए गए मॉडल को देखें कि यह काम करता है।

कुछ वाक्य जोड़ियों को इनकोडिंग द्वारा शुरू करें:

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)
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.

Warning:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.

Warning:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.

Warning:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.

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.1238481   0.92107666]
 [ 0.35722053 -0.4061358 ]]

[[-1.1238478   0.9210764 ]
 [ 0.35722044 -0.40613574]]

अनुबंध

बड़े डेटासेट को पुनः एन्कोडिंग

इस ट्यूटोरियल ने आपको स्पष्टता के लिए डेटासेट में मेमोरी को फिर से एनकोड किया है।

यह केवल इसलिए संभव था क्योंकि 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))

अंत में उन TFRecord फ़ाइलों से tf.data इनपुट पाइपलाइन बनाएँ:

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.experimental.AUTOTUNE)
  dataset = dataset.map(
      _select_data_from_record,
      num_parallel_calls=tf.data.experimental.AUTOTUNE)
  dataset = dataset.batch(batch_size, drop_remainder=is_training)
  dataset = dataset.prefetch(tf.data.experimental.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 TFHub पर BERT

आप TFHub से शेल्फ से BERT मॉडल प्राप्त कर सकते हैं। इस hub.KerasLayer शीर्ष पर एक वर्गीकरण सिर जोड़ना मुश्किल नहीं होगा। hub.KerasLayer

# Note: 350MB download.
import tensorflow_hub as hub
hub_encoder = hub.KerasLayer(hub_url_bert, 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=[glue_train['input_word_ids'][:10],
            glue_train['input_mask'][:10],
            glue_train['input_type_ids'][:10],],
    training=False,
)

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

इस बिंदु पर अपने आप को एक वर्गीकरण सिर जोड़ना सरल होगा।

bert_models.classifier_model फ़ंक्शन भी Tensorelive Hub से एनकोडर पर एक क्लासिफायरियर बना सकता है:

hub_classifier, hub_encoder = bert.bert_models.classifier_model(
    # Caution: Most of `bert_config` is ignored if you pass a hub url.
    bert_config=bert_config, hub_module_url=hub_url_bert, num_labels=2)

TFHub से इस मॉडल को लोड करने के लिए एक नकारात्मक पहलू यह है कि आंतरिक केरस परतों की संरचना को बहाल नहीं किया गया है। इसलिए मॉडल का निरीक्षण या संशोधन करना अधिक कठिन है। TransformerEncoder मॉडल अब एक एकल परत है:

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

png

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.TransformerEncoder और nlp.modeling.models.BertClassifier classes पर वास्तव में एक पतली आवरण है। बस याद रखें कि यदि आप वास्तुकला को संशोधित करना शुरू करते हैं तो यह पूर्व-प्रशिक्षित चेकपॉइंट को फिर से लोड करने के लिए सही या संभव नहीं हो सकता है, इसलिए आपको खरोंच से पीछे हटना होगा।

एनकोडर बनाएँ:

transformer_config = config_dict.copy()

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

transformer_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': <tensorflow.python.keras.initializers.initializers_v2.TruncatedNormal at 0x7f81145cb3c8>,
 'max_sequence_length': 512,
 'num_layers': 12}
manual_encoder = nlp.modeling.networks.TransformerEncoder(**transformer_config)

वजन बहाल करें:

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

टेस्ट इसे चलाएं:

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=transformer_config['dropout_rate'],
        initializer=tf.keras.initializers.TruncatedNormal(
          stddev=bert_config.initializer_range))
manual_classifier(my_examples, training=True).numpy()
array([[-0.22512403,  0.07213479],
       [-0.21233292,  0.1311737 ]], dtype=float32)

ऑप्टिमाइज़र और शेड्यूल

मॉडल को प्रशिक्षित करने के लिए उपयोग किए जाने वाले ऑप्टिमाइज़र को 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 0x7f8115ab5320>]

png

यह बदले में, 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 0x7f81150c27f0>]

png

उसके बाद उस अनुसूची का उपयोग करके nlp.optimization.AdamWeightDecay बनाएं, BERT मॉडल के लिए कॉन्फ़िगर किया गया:

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