Halaman ini diterjemahkan oleh Cloud Translation API.
Switch to English

Menyempurnakan model BERT

Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHub Unduh buku catatan Lihat model TF Hub

Dalam contoh ini, kita akan bekerja melalui fine-tuning model BERT menggunakan paket PIP model tensorflow.

Model BERT yang telah dilatih sebelumnya yang menjadi dasar tutorial ini juga tersedia di TensorFlow Hub , untuk mengetahui cara menggunakannya, lihat Lampiran Hub

Mendirikan

Instal paket pip TensorFlow Model Garden

  • tf-models-official adalah paket Model Garden yang stabil. Perhatikan bahwa ini mungkin tidak menyertakan perubahan terbaru dalam repo github tensorflow_models . Untuk menyertakan perubahan terbaru, Anda dapat menginstal tf-models-nightly , yaitu paket Nightly Model Garden yang dibuat setiap hari secara otomatis.
  • pip akan menginstal semua model dan dependensi secara otomatis.
pip install -q tf-models-official==2.3.0
WARNING: You are using pip version 20.2.3; however, version 20.2.4 is available.
You should consider upgrading via the '/tmpfs/src/tf_docs_env/bin/python -m pip install --upgrade pip' command.

Impor

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

Sumber daya

Direktori ini berisi konfigurasi, kosakata, dan pos pemeriksaan terlatih yang digunakan dalam tutorial ini:

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

Anda bisa mendapatkan encoder BERT terlatih dari TensorFlow Hub :

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

Data

Untuk contoh ini kami menggunakan dataset GLUE MRPC dari TFDS .

Dataset ini tidak diatur sehingga dapat langsung dimasukkan ke dalam model BERT, jadi bagian ini juga menangani praproses yang diperlukan.

Dapatkan set data dari Set Data TensorFlow

Microsoft Research Paraphrase Corpus (Dolan & Brockett, 2005) adalah kumpulan pasangan kalimat yang secara otomatis diekstrak dari sumber berita online, dengan anotasi manusia untuk mengetahui apakah kalimat dalam pasangan tersebut setara secara semantik.

  • Jumlah label: 2.
  • Ukuran set data pelatihan: 3668.
  • Ukuran dataset evaluasi: 408.
  • Panjang urutan maksimum set data pelatihan dan evaluasi: 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...
Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/glue/mrpc/1.0.0.incompleteKZIBN9/glue-train.tfrecord
Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/glue/mrpc/1.0.0.incompleteKZIBN9/glue-validation.tfrecord
Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/glue/mrpc/1.0.0.incompleteKZIBN9/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']

Objek info mendeskripsikan kumpulan data dan fiturnya:

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

Kedua kelas tersebut adalah:

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

Berikut adalah salah satu contoh dari set pelatihan:

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

Tokenizer BERT

Untuk menyempurnakan model terlatih, Anda perlu memastikan bahwa Anda menggunakan tokenisasi, kosakata, dan pemetaan indeks yang sama persis seperti yang Anda gunakan selama pelatihan.

Tokenizer BERT yang digunakan dalam tutorial ini ditulis dengan Python murni (Ini tidak dibuat dari operasi TensorFlow). Jadi, Anda tidak bisa begitu saja menghubungkannya ke model Anda sebagai keras.layer seperti yang Anda lakukan dengan preprocessing.TextVectorization .

Kode berikut membangun kembali tokenizer yang digunakan oleh model dasar:

# 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

Tokenkan kalimat:

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

Proses data terlebih dahulu

Bagian tersebut memproses data sebelumnya secara manual ke dalam format yang diharapkan oleh model.

Dataset ini kecil, sehingga preprocessing dapat dilakukan dengan cepat dan mudah di memori. Untuk kumpulan data yang lebih besar, pustaka tf_models menyertakan beberapa alat untuk praproses dan tf_models ulang kumpulan data. Lihat Lampiran: Mengenkode ulang kumpulan data besar untuk detailnya.

Encode kalimatnya

Model ini mengharapkan dua kalimat masukannya digabungkan bersama. Masukan ini diharapkan dimulai dengan token [CLS] "Ini adalah masalah klasifikasi", dan setiap kalimat harus diakhiri dengan token [SEP] "Pemisah":

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

Mulailah dengan mengenkode semua kalimat sambil menambahkan token [SEP] , dan mengemasnya ke dalam tensor ragged:

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]

Sekarang tambahkan token [CLS] , dan input_word_ids tensor compang-camping untuk membentuk tensor input_word_ids tunggal untuk setiap contoh. RaggedTensor.to_tensor() nol pad ke urutan terpanjang.

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

Masker dan tipe masukan

Model mengharapkan dua masukan tambahan:

  • Masker masukan
  • Jenis masukan

Masker memungkinkan model membedakan dengan jelas antara konten dan padding. Topeng memiliki bentuk yang sama dengan input_word_ids , dan berisi 1 mana pun input_word_ids tidak input_word_ids .

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

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

png

"Jenis masukan" juga memiliki bentuk yang sama, tetapi di dalam wilayah tanpa bantalan, berisi 0 atau 1 menunjukkan kalimat yang menjadi bagian dari token.

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 0x7fad143c1710>

png

Gabungkan semuanya

Kumpulkan kode parsing teks di atas menjadi satu fungsi, dan terapkan ke setiap pemisahan glue/mrpc data 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']

Setiap subset data telah dikonversi ke kamus fitur, dan satu set label. Setiap fitur dalam kamus masukan memiliki bentuk yang sama, dan jumlah label harus cocok:

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

Model

Bangun modelnya

Langkah pertama adalah mengunduh konfigurasi untuk model terlatih.

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 mendefinisikan Model BERT inti, yaitu model Keras untuk memprediksi keluaran num_classes dari masukan dengan panjang urutan maksimum max_seq_length .

Fungsi ini mengembalikan encoder dan classifier.

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

Pengklasifikasi memiliki tiga masukan dan satu keluaran:

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

png

Jalankan pada batch uji yang berisi 10 contoh dari set pelatihan. Outputnya adalah logit untuk dua kelas:

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

bert_classifier(
    glue_batch, training=True
).numpy()
array([[ 0.08382261,  0.34465584],
       [ 0.02057236,  0.24053624],
       [ 0.04930754,  0.1117427 ],
       [ 0.17041089,  0.20810834],
       [ 0.21667874,  0.2840511 ],
       [ 0.02325345,  0.33799925],
       [-0.06198866,  0.13532838],
       [ 0.084592  ,  0.20711854],
       [-0.04323687,  0.17096342],
       [ 0.23759182,  0.16801538]], dtype=float32)

TransformerEncoder di tengah classifier di atas adalah bert_encoder .

Memeriksa pembuat enkode, kami melihat tumpukan lapisan Transformer terhubung ke tiga masukan yang sama:

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

png

Pulihkan bobot encoder

Saat dibuat, pembuat enkode diinisialisasi secara acak. Pulihkan bobot pembuat enkode dari pos pemeriksaan:

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 0x7fad4580ffd0>

Siapkan pengoptimal

BERT mengadopsi pengoptimal Adam dengan penurunan berat badan (alias " AdamW "). Ini juga menggunakan jadwal kecepatan pemelajaran yang pertama-tama memanas dari 0 lalu meluruh menjadi 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)

Ini mengembalikan pengoptimal AdamWeightDecay dengan jadwal kecepatan pemelajaran yang disetel:

type(optimizer)
official.nlp.optimization.AdamWeightDecay

Untuk melihat contoh bagaimana menyesuaikan pengoptimal dan jadwalnya, lihat lampiran Jadwal pengoptimal .

Latih modelnya

Metriknya adalah akurasi dan kami menggunakan entropi silang kategoris yang jarang sebagai kerugian.

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 [==============================] - 26s 222ms/step - loss: 0.6151 - accuracy: 0.6611 - val_loss: 0.5462 - val_accuracy: 0.7451
Epoch 2/3
115/115 [==============================] - 24s 212ms/step - loss: 0.4447 - accuracy: 0.8010 - val_loss: 0.4150 - val_accuracy: 0.8309
Epoch 3/3
115/115 [==============================] - 24s 213ms/step - loss: 0.2830 - accuracy: 0.8964 - val_loss: 0.3697 - val_accuracy: 0.8480

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

Sekarang jalankan model yang disetel dengan baik pada contoh khusus untuk melihat bahwa itu berfungsi.

Mulailah dengan menyandikan beberapa pasangan kalimat:

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)

Model harus melaporkan "kecocokan" kelas 1 untuk contoh pertama dan kelas 0 "tidak cocok" untuk contoh kedua:

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

Simpan modelnya

Seringkali tujuan melatih model adalah menggunakannya untuk sesuatu, jadi ekspor model tersebut lalu pulihkan untuk memastikan model tersebut berfungsi.

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())
[[-0.95450354  1.1227685 ]
 [ 0.40344787 -0.58954155]]

[[-0.95450354  1.1227684 ]
 [ 0.4034478  -0.5895414 ]]

Lampiran

Melakukan encoding ulang set data besar

Tutorial ini Anda mengkodekan ulang dataset dalam memori, untuk kejelasan.

Ini hanya mungkin karena glue/mrpc adalah kumpulan data yang sangat kecil. Untuk menangani kumpulan data yang lebih besar pustaka tf_models menyertakan beberapa alat untuk memproses dan mengenkode ulang kumpulan data untuk pelatihan yang efisien.

Langkah pertama adalah menjelaskan fitur mana dari set data yang harus diubah:

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)

Kemudian terapkan transformasi untuk menghasilkan file TFRecord baru.

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

Terakhir buat tf.data input tf.data dari file TFRecord tersebut:

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

Hasil tf.data.Datasets mengembalikan pasangan (features, labels) , seperti yang diharapkan oleh 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))

Buat tf.data.Dataset untuk pelatihan dan evaluasi

Jika Anda perlu mengubah pemuatan data, berikut beberapa kode untuk Anda mulai:

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 BERT di TFHub

Anda bisa mendapatkan model BERT dari rak dari TFHub . Tidak akan sulit untuk menambahkan kepala klasifikasi di atas hub.KerasLayer ini. hub.KerasLayer

# Note: 350MB download.
import tensorflow_hub as hub
hub_model_name = "bert_en_uncased_L-12_H-768_A-12" 
hub_encoder = hub.KerasLayer(f"https://tfhub.dev/tensorflow/{hub_model_name}/2",
                             trainable=True)

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

Uji coba pada sekumpulan data:

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)

Pada tahap ini, akan mudah menambahkan kepala klasifikasi sendiri.

Fungsi bert_models.classifier_model juga dapat membuat pengklasifikasi ke encoder dari TensorFlow 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)

Satu kelemahan untuk memuat model ini dari TFHub adalah struktur lapisan keras internal tidak dipulihkan. Jadi lebih sulit untuk memeriksa atau memodifikasi model. Model TransformerEncoder sekarang menjadi satu lapisan:

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'

Bangunan model tingkat rendah

Jika Anda memerlukan kontrol lebih besar atas konstruksi model, perlu diperhatikan bahwa fungsi classifier_model digunakan sebelumnya sebenarnya hanyalah pembungkus tipis di atas kelas nlp.modeling.networks.TransformerEncoder dan nlp.modeling.models.BertClassifier . Ingatlah bahwa jika Anda mulai memodifikasi arsitektur, mungkin tidak benar atau mungkin memuat ulang pos pemeriksaan terlatih sehingga Anda harus berlatih kembali dari awal.

Buat pembuat enkode:

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 0x7fac08046e10>,
 'max_sequence_length': 512,
 'num_layers': 12}
manual_encoder = nlp.modeling.networks.TransformerEncoder(**transformer_config)

Kembalikan bobot:

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 0x7fabefa596d8>

Uji coba:

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)

Bungkus dalam pengklasifikasi:

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.07863025, -0.02940944],
       [ 0.30274656,  0.27299827]], dtype=float32)

Pengoptimal dan jadwal

Pengoptimal yang digunakan untuk melatih model dibuat menggunakan fungsi nlp.optimization.create_optimizer :

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

Wrapper tingkat tinggi itu menyiapkan jadwal kecepatan pembelajaran dan pengoptimal.

Jadwal kecepatan pemelajaran dasar yang digunakan di sini adalah peluruhan linier ke nol selama pelatihan berlangsung:

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 0x7fabef5e69e8>]

png

Ini, pada gilirannya, WarmUp jadwal WarmUp yang secara linier meningkatkan kecepatan pembelajaran ke nilai target selama 10% pertama pelatihan:

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 0x7fabef559630>]

png

Kemudian buat nlp.optimization.AdamWeightDecay menggunakan jadwal itu, dikonfigurasi untuk model 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'])