แก้ไขงาน GLUE โดยใช้ BERT บน TPU

ดูบน TensorFlow.org ทำงานใน Google Colab ดูบน GitHub ดาวน์โหลดโน๊ตบุ๊ค ดูรุ่น TF Hub

BERT สามารถใช้แก้ปัญหาต่างๆ ในการประมวลผลภาษาธรรมชาติได้ คุณจะได้เรียนรู้วิธีการ BERT ปรับแต่งสำหรับงานจำนวนมากจาก มาตรฐานกาว :

  1. โคล่า (คอร์ปัสของภาษาศาสตร์ยอมรับ): เป็นประโยคที่ถูกต้องตามหลักไวยากรณ์?

  2. SST-2 (Stanford ความเชื่อมั่น Treebank): งานคือการคาดการณ์ความเชื่อมั่นของประโยคที่กำหนด

  3. MRPC (Microsoft Research แปลความหมาย Corpus): ตรวจสอบว่าคู่ของประโยคที่มีความหมายเทียบเท่า

  4. QQP (Quora คำถาม Pairs2): ตรวจสอบว่าคู่ของคำถามจะเทียบเท่าความหมาย

  5. MNLI (Multi-แนวธรรมชาติภาษาอนุมาน): ให้เป็นประโยคที่สถานที่ตั้งและประโยคสมมติฐานของงานคือการคาดการณ์ว่าจะเป็นสถานที่สร้างความสมมติฐาน (entailment) ขัดแย้งกับสมมติฐาน (ขัดแย้ง) หรือไม่ (กลาง)

  6. QNLI (คำถาม-ตอบภาษาธรรมชาติอนุมาน): งานคือการตรวจสอบว่าประโยคบริบทมีคำตอบสำหรับคำถามที่

  7. RTE (ตระหนักถึงข้อความ entailment): ตรวจสอบว่าประโยค entails สมมติฐานที่กำหนดหรือไม่

  8. WNLI (Winograd ภาษาธรรมชาติอนุมาน): งานคือการคาดการณ์ถ้าประโยคที่มีคำสรรพนามแทนจะถูกยกให้โดยประโยคเดิม

บทแนะนำนี้ประกอบด้วยโค้ดแบบ end-to-end ที่สมบูรณ์เพื่อฝึกโมเดลเหล่านี้บน TPU คุณยังสามารถเรียกใช้โน้ตบุ๊กเครื่องนี้บน GPU โดยเปลี่ยนหนึ่งบรรทัด (อธิบายด้านล่าง)

ในสมุดบันทึกนี้ คุณจะ:

  • โหลดโมเดล BERT จาก TensorFlow Hub
  • เลือกงาน GLUE และดาวน์โหลดชุดข้อมูล
  • ประมวลผลข้อความล่วงหน้า
  • ปรับแต่ง BERT (ตัวอย่างมีให้สำหรับชุดข้อมูลแบบประโยคเดียวและหลายประโยค)
  • บันทึกรูปแบบการฝึกอบรมและใช้งาน

ติดตั้ง

คุณจะใช้แบบจำลองแยกต่างหากเพื่อประมวลผลข้อความล่วงหน้าก่อนที่จะใช้เพื่อปรับแต่ง BERT รุ่นนี้ขึ้นอยู่กับ tensorflow / ข้อความ ซึ่งคุณจะติดตั้งอยู่ด้านล่าง

pip install -q -U tensorflow-text

คุณจะใช้เพิ่มประสิทธิภาพ AdamW จาก tensorflow / รุ่น เพื่อ BERT ปรับแต่งซึ่งคุณจะติดตั้งได้เป็นอย่างดี

pip install -q -U tf-models-official
pip install -U tfds-nightly
import os
import tensorflow as tf
import tensorflow_hub as hub
import tensorflow_datasets as tfds
import tensorflow_text as text  # A dependency of the preprocessing model
import tensorflow_addons as tfa
from official.nlp import optimization
import numpy as np

tf.get_logger().setLevel('ERROR')
/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/requests/__init__.py:104: RequestsDependencyWarning: urllib3 (1.26.7) or chardet (2.3.0)/charset_normalizer (2.0.7) doesn't match a supported version!
  RequestsDependencyWarning)

ถัดไป กำหนดค่า TFHub ให้อ่านจุดตรวจสอบโดยตรงจากที่เก็บข้อมูล Cloud Storage ของ TFHub แนะนำให้ใช้เฉพาะเมื่อใช้งานรุ่น TFHub บน TPU

หากไม่มีการตั้งค่านี้ TFHub จะดาวน์โหลดไฟล์บีบอัดและแยกจุดตรวจในเครื่อง ความพยายามที่จะโหลดจากไฟล์ในเครื่องเหล่านี้จะล้มเหลวโดยมีข้อผิดพลาดดังต่อไปนี้:

InvalidArgumentError: Unimplemented: File system scheme '[local]' not implemented

เพราะนี่คือ TPU สามารถอ่านได้อย่างเดียวโดยตรงจากบุ้งกี๋ Cloud Storage

os.environ["TFHUB_MODEL_LOAD_FORMAT"]="UNCOMPRESSED"

เชื่อมต่อกับคนงาน TPU

รหัสต่อไปนี้เชื่อมต่อกับผู้ปฏิบัติงาน TPU และเปลี่ยนอุปกรณ์เริ่มต้นของ TensorFlow เป็นอุปกรณ์ CPU บนตัวปฏิบัติงาน TPU นอกจากนี้ยังกำหนดกลยุทธ์การกระจาย TPU ที่คุณจะใช้เพื่อแจกจ่ายการฝึกโมเดลไปยังแกน TPU 8 ตัวที่แยกจากกันซึ่งมีอยู่ในพนักงาน TPU รายนี้ ดู TensorFlow ของ TPU คู่มือ สำหรับข้อมูลเพิ่มเติม

import os

if os.environ['COLAB_TPU_ADDR']:
  cluster_resolver = tf.distribute.cluster_resolver.TPUClusterResolver(tpu='')
  tf.config.experimental_connect_to_cluster(cluster_resolver)
  tf.tpu.experimental.initialize_tpu_system(cluster_resolver)
  strategy = tf.distribute.TPUStrategy(cluster_resolver)
  print('Using TPU')
elif tf.config.list_physical_devices('GPU'):
  strategy = tf.distribute.MirroredStrategy()
  print('Using GPU')
else:
  raise ValueError('Running on CPU is not recommended.')
Using TPU

กำลังโหลดโมเดลจาก TensorFlow Hub

ที่นี่คุณสามารถเลือกรุ่น BERT ที่คุณจะโหลดจาก TensorFlow Hub และปรับแต่งได้ มี BERT ให้เลือกหลายรุ่น

  • BERT-Base , uncased และ อีกเจ็ดรุ่น ที่มีน้ำหนักการฝึกอบรมที่ออกโดยผู้เขียน BERT เดิม
  • BERTs ขนาดเล็ก มีสถาปัตยกรรมทั่วไปเหมือนกัน แต่น้อยลงและ / หรือเล็กบล็อกหม้อแปลงไฟฟ้าซึ่งจะช่วยให้คุณสำรวจความสมดุลระหว่างความเร็ว, ขนาดและคุณภาพ
  • ALBERT : สี่ขนาดที่แตกต่างกัน "A Lite BERT" ที่ช่วยลดขนาดของรูปแบบ ( แต่ไม่ใช่เวลาในการคำนวณ) โดยการแบ่งปันพารามิเตอร์ระหว่างชั้น
  • ผู้เชี่ยวชาญ BERT : แปดรูปแบบที่ทุกคนมีสถาปัตยกรรม BERT ฐาน แต่เสนอทางเลือกระหว่างโดเมนก่อนการฝึกอบรมที่แตกต่างกันในการจัดขึ้นอย่างใกล้ชิดกับงานเป้าหมาย
  • Electra มีสถาปัตยกรรมเดียวกับเบิร์ต (ในสามขนาดที่แตกต่างกัน) แต่ได้รับก่อนการฝึกอบรมเป็น discriminator ในการตั้งค่าที่คล้ายกำเนิดขัดแย้งเครือข่าย (GAN)
  • BERT กับ Talking Heads-เรียนและรั้วรอบขอบชิด Gelu [ ฐาน , ขนาดใหญ่ ] มีสองการปรับปรุงหลักของสถาปัตยกรรมหม้อแปลง

ดูเอกสารแบบจำลองที่ลิงก์ด้านบนสำหรับรายละเอียดเพิ่มเติม

ในบทช่วยสอนนี้ คุณจะเริ่มด้วย BERT-base คุณสามารถใช้รุ่นที่ใหญ่กว่าและใหม่กว่าเพื่อความแม่นยำที่สูงขึ้น หรือใช้รุ่นที่เล็กกว่าเพื่อการฝึกฝนที่เร็วขึ้น หากต้องการเปลี่ยนโมเดล คุณต้องเปลี่ยนโค้ดเพียงบรรทัดเดียว (แสดงด้านล่าง) ความแตกต่างทั้งหมดถูกห่อหุ้มไว้ใน SavedModel ที่คุณจะดาวน์โหลดจาก TensorFlow Hub

เลือกรุ่น BERT เพื่อปรับแต่ง

BERT model selected           : https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/3
Preprocessing model auto-selected: https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3

ประมวลผลข้อความล่วงหน้า

ใน ข้อความประเภทกับ BERT Colab รุ่น preprocessing จะใช้ฝังโดยตรงด้วยการเข้ารหัส BERT

บทช่วยสอนนี้สาธิตวิธีทำการประมวลผลล่วงหน้าซึ่งเป็นส่วนหนึ่งของไปป์ไลน์อินพุตสำหรับการฝึกอบรม โดยใช้ Dataset.map จากนั้นผสานเข้ากับโมเดลที่ส่งออกเพื่อการอนุมาน ด้วยวิธีนี้ ทั้งการฝึกและการอนุมานสามารถทำงานได้จากอินพุตข้อความดิบ แม้ว่า TPU เองจะต้องการอินพุตที่เป็นตัวเลข

ต้องการ TPU กันก็สามารถช่วยให้ประสิทธิภาพการทำงานที่ได้ทำ preprocessing ถ่ายทอดสดในท่อป้อนข้อมูล (คุณสามารถเรียนรู้เพิ่มเติมใน คู่มือการปฏิบัติงาน tf.data )

บทช่วยสอนนี้ยังสาธิตวิธีสร้างแบบจำลองหลายอินพุต และวิธีปรับความยาวลำดับของอินพุตเป็น BERT

มาสาธิตโมเดลก่อนการประมวลผลกัน

bert_preprocess = hub.load(tfhub_handle_preprocess)
tok = bert_preprocess.tokenize(tf.constant(['Hello TensorFlow!']))
print(tok)
<tf.RaggedTensor [[[7592], [23435, 12314], [999]]]>

แต่ละรุ่น preprocessing นอกจากนี้ยังมีวิธีการ .bert_pack_inputs(tensors, seq_length) ซึ่งจะนำรายชื่อของสัญญาณ (เช่น tok ด้านบน) และความยาวลำดับอาร์กิวเมนต์ ซึ่งบรรจุอินพุตเพื่อสร้างพจนานุกรมของเทนเซอร์ในรูปแบบที่โมเดล BERT คาดไว้

text_preprocessed = bert_preprocess.bert_pack_inputs([tok, tok], tf.constant(20))

print('Shape Word Ids : ', text_preprocessed['input_word_ids'].shape)
print('Word Ids       : ', text_preprocessed['input_word_ids'][0, :16])
print('Shape Mask     : ', text_preprocessed['input_mask'].shape)
print('Input Mask     : ', text_preprocessed['input_mask'][0, :16])
print('Shape Type Ids : ', text_preprocessed['input_type_ids'].shape)
print('Type Ids       : ', text_preprocessed['input_type_ids'][0, :16])
Shape Word Ids :  (1, 20)
Word Ids       :  tf.Tensor(
[  101  7592 23435 12314   999   102  7592 23435 12314   999   102     0
     0     0     0     0], shape=(16,), dtype=int32)
Shape Mask     :  (1, 20)
Input Mask     :  tf.Tensor([1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0], shape=(16,), dtype=int32)
Shape Type Ids :  (1, 20)
Type Ids       :  tf.Tensor([0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0], shape=(16,), dtype=int32)

นี่คือรายละเอียดบางส่วนที่ควรคำนึงถึง:

  • input_mask หน้ากากช่วยให้รูปแบบที่แตกต่างหมดจดระหว่างเนื้อหาและช่องว่างที่ หน้ากากมีรูปร่างเช่นเดียวกับ input_word_ids และมี 1 ทุกที่ input_word_ids ไม่ได้รอง
  • input_type_ids มีรูปร่างเช่นเดียวกับ input_mask แต่ภายในภูมิภาคที่ไม่ใช่เบาะมี 0 หรือ 1 ระบุว่าประโยคโทเค็นเป็นส่วนหนึ่งของ

ถัดไป คุณจะต้องสร้างโมเดลการประมวลผลล่วงหน้าที่สรุปตรรกะทั้งหมดนี้ โมเดลของคุณจะรับสตริงเป็นอินพุต และส่งคืนอ็อบเจ็กต์ที่จัดรูปแบบอย่างเหมาะสมซึ่งสามารถส่งผ่านไปยัง BERT ได้

โมเดล BERT แต่ละรุ่นมีรูปแบบการประมวลผลล่วงหน้าเฉพาะ ตรวจสอบให้แน่ใจว่าได้ใช้แบบจำลองที่เหมาะสมที่อธิบายไว้ในเอกสารประกอบแบบจำลองของ BERT

def make_bert_preprocess_model(sentence_features, seq_length=128):
  """Returns Model mapping string features to BERT inputs.

  Args:
    sentence_features: a list with the names of string-valued features.
    seq_length: an integer that defines the sequence length of BERT inputs.

  Returns:
    A Keras Model that can be called on a list or dict of string Tensors
    (with the order or names, resp., given by sentence_features) and
    returns a dict of tensors for input to BERT.
  """

  input_segments = [
      tf.keras.layers.Input(shape=(), dtype=tf.string, name=ft)
      for ft in sentence_features]

  # Tokenize the text to word pieces.
  bert_preprocess = hub.load(tfhub_handle_preprocess)
  tokenizer = hub.KerasLayer(bert_preprocess.tokenize, name='tokenizer')
  segments = [tokenizer(s) for s in input_segments]

  # Optional: Trim segments in a smart way to fit seq_length.
  # Simple cases (like this example) can skip this step and let
  # the next step apply a default truncation to approximately equal lengths.
  truncated_segments = segments

  # Pack inputs. The details (start/end token ids, dict of output tensors)
  # are model-dependent, so this gets loaded from the SavedModel.
  packer = hub.KerasLayer(bert_preprocess.bert_pack_inputs,
                          arguments=dict(seq_length=seq_length),
                          name='packer')
  model_inputs = packer(truncated_segments)
  return tf.keras.Model(input_segments, model_inputs)

มาสาธิตโมเดลก่อนการประมวลผลกัน คุณจะสร้างการทดสอบด้วยการป้อนสองประโยค (input1 และ input2) เอาท์พุทคือสิ่งที่รุ่น BERT จะคาดหวังเป็น input: input_word_ids , input_masks และ input_type_ids

test_preprocess_model = make_bert_preprocess_model(['my_input1', 'my_input2'])
test_text = [np.array(['some random test sentence']),
             np.array(['another sentence'])]
text_preprocessed = test_preprocess_model(test_text)

print('Keys           : ', list(text_preprocessed.keys()))
print('Shape Word Ids : ', text_preprocessed['input_word_ids'].shape)
print('Word Ids       : ', text_preprocessed['input_word_ids'][0, :16])
print('Shape Mask     : ', text_preprocessed['input_mask'].shape)
print('Input Mask     : ', text_preprocessed['input_mask'][0, :16])
print('Shape Type Ids : ', text_preprocessed['input_type_ids'].shape)
print('Type Ids       : ', text_preprocessed['input_type_ids'][0, :16])
Keys           :  ['input_word_ids', 'input_mask', 'input_type_ids']
Shape Word Ids :  (1, 128)
Word Ids       :  tf.Tensor(
[ 101 2070 6721 3231 6251  102 2178 6251  102    0    0    0    0    0
    0    0], shape=(16,), dtype=int32)
Shape Mask     :  (1, 128)
Input Mask     :  tf.Tensor([1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0], shape=(16,), dtype=int32)
Shape Type Ids :  (1, 128)
Type Ids       :  tf.Tensor([0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0], shape=(16,), dtype=int32)

มาดูโครงสร้างของโมเดลกัน โดยให้ความสนใจกับอินพุตทั้งสองที่คุณเพิ่งกำหนด

tf.keras.utils.plot_model(test_preprocess_model, show_shapes=True, show_dtype=True)
('You must install pydot (`pip install pydot`) and install graphviz (see instructions at https://graphviz.gitlab.io/download/) ', 'for plot_model/model_to_dot to work.')

เพื่อนำไปใช้ประมวลผลเบื้องต้นในปัจจัยการผลิตทั้งหมดจากชุดข้อมูลที่คุณจะใช้ map ฟังก์ชั่นจากชุดข้อมูล ผลที่ได้คือที่เก็บไว้ชั่วคราวแล้วสำหรับ ผลการดำเนินงาน

AUTOTUNE = tf.data.AUTOTUNE


def load_dataset_from_tfds(in_memory_ds, info, split, batch_size,
                           bert_preprocess_model):
  is_training = split.startswith('train')
  dataset = tf.data.Dataset.from_tensor_slices(in_memory_ds[split])
  num_examples = info.splits[split].num_examples

  if is_training:
    dataset = dataset.shuffle(num_examples)
    dataset = dataset.repeat()
  dataset = dataset.batch(batch_size)
  dataset = dataset.map(lambda ex: (bert_preprocess_model(ex), ex['label']))
  dataset = dataset.cache().prefetch(buffer_size=AUTOTUNE)
  return dataset, num_examples

กำหนดรุ่นของคุณ

ตอนนี้คุณพร้อมที่จะกำหนดแบบจำลองของคุณสำหรับการจำแนกคู่ประโยคหรือประโยคโดยป้อนอินพุตที่ประมวลผลล่วงหน้าผ่านตัวเข้ารหัส BERT และวางตัวแยกประเภทเชิงเส้นไว้ด้านบน

def build_classifier_model(num_classes):

  class Classifier(tf.keras.Model):
    def __init__(self, num_classes):
      super(Classifier, self).__init__(name="prediction")
      self.encoder = hub.KerasLayer(tfhub_handle_encoder, trainable=True)
      self.dropout = tf.keras.layers.Dropout(0.1)
      self.dense = tf.keras.layers.Dense(num_classes)

    def call(self, preprocessed_text):
      encoder_outputs = self.encoder(preprocessed_text)
      pooled_output = encoder_outputs["pooled_output"]
      x = self.dropout(pooled_output)
      x = self.dense(x)
      return x

  model = Classifier(num_classes)
  return model

มาลองเรียกใช้โมเดลกับอินพุตที่ประมวลผลล่วงหน้า

test_classifier_model = build_classifier_model(2)
bert_raw_result = test_classifier_model(text_preprocessed)
print(tf.sigmoid(bert_raw_result))
tf.Tensor([[0.29329836 0.44367802]], shape=(1, 2), dtype=float32)

เลือกงานจาก GLUE

คุณจะใช้ TensorFlow ชุดข้อมูลจาก กาว ชุดมาตรฐาน

Colab ให้คุณดาวน์โหลดชุดข้อมูลขนาดเล็กเหล่านี้ไปยังระบบไฟล์ในเครื่อง และโค้ดด้านล่างอ่านทั้งหมดลงในหน่วยความจำ เนื่องจากโฮสต์ของผู้ปฏิบัติงาน TPU ที่แยกจากกันไม่สามารถเข้าถึงระบบไฟล์ในเครื่องของรันไทม์ colab

สำหรับชุดข้อมูลขนาดใหญ่ที่คุณจะต้องสร้างของคุณเอง ข้อมูล Google Cloud Storage ถังและมีคนงาน TPU อ่านข้อมูลจากที่นั่น คุณสามารถเรียนรู้เพิ่มเติมใน คู่มือ TPU

ขอแนะนำให้เริ่มต้นด้วยชุดข้อมูล CoLa (สำหรับประโยคเดียว) หรือ MRPC (สำหรับหลายประโยค) เนื่องจากชุดข้อมูลเหล่านี้มีขนาดเล็กและไม่ใช้เวลาในการปรับแต่งนาน

Using glue/cola from TFDS
This dataset has 10657 examples
Number of classes: 2
Features ['sentence']
Splits ['train', 'validation', 'test']
Here are some sample rows from glue/cola dataset
['unacceptable', 'acceptable']

sample row 1
b'It is this hat that it is certain that he was wearing.'
label: 1 (acceptable)

sample row 2
b'Her efficient looking up of the answer pleased the boss.'
label: 1 (acceptable)

sample row 3
b'Both the workers will wear carnations.'
label: 1 (acceptable)

sample row 4
b'John enjoyed drawing trees for his syntax homework.'
label: 1 (acceptable)

sample row 5
b'We consider Leslie rather foolish, and Lou a complete idiot.'
label: 1 (acceptable)

ชุดข้อมูลยังกำหนดประเภทของปัญหา (การจำแนกหรือการถดถอย) และฟังก์ชันการสูญเสียที่เหมาะสมสำหรับการฝึกอบรม

def get_configuration(glue_task):

  loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

  if glue_task == 'glue/cola':
    metrics = tfa.metrics.MatthewsCorrelationCoefficient(num_classes=2)
  else:
    metrics = tf.keras.metrics.SparseCategoricalAccuracy(
        'accuracy', dtype=tf.float32)

  return metrics, loss

ฝึกโมเดลของคุณ

สุดท้าย คุณสามารถฝึกโมเดล end-to-end บนชุดข้อมูลที่คุณเลือกได้

การกระจาย

เรียกคืนรหัสการตั้งค่าที่ด้านบน ซึ่งเชื่อมต่อรันไทม์ของ colab กับผู้ปฏิบัติงาน TPU ที่มีอุปกรณ์ TPU หลายเครื่อง ในการเผยแพร่การฝึกอบรม คุณจะต้องสร้างและรวบรวมโมเดล Keras หลักของคุณภายในขอบเขตของกลยุทธ์การกระจาย TPU (โปรดดูรายละเอียด ที่กระจายการฝึกอบรมกับ Keras .)

ในทางกลับกัน การประมวลผลล่วงหน้าทำงานบน CPU ของโฮสต์ผู้ปฏิบัติงาน ไม่ใช่ TPU ดังนั้นโมเดล Keras สำหรับการประมวลผลล่วงหน้ารวมถึงชุดข้อมูลการฝึกอบรมและการตรวจสอบความถูกต้องที่แมปด้วยจะถูกสร้างขึ้นนอกขอบเขตกลยุทธ์การแจกจ่าย เรียกร้องให้ Model.fit() จะดูแลการจัดจำหน่ายผ่านในชุดข้อมูลที่จำลองรูปแบบ

เครื่องมือเพิ่มประสิทธิภาพ

ปรับจูนต่อไปเพิ่มประสิทธิภาพการตั้งค่าจาก BERT ก่อนการฝึกอบรม (ในขณะที่ ข้อความประเภทกับ BERT ): จะใช้เพิ่มประสิทธิภาพ AdamW กับการสลายตัวเชิงเส้นของอัตราการเรียนรู้ความคิดเริ่มต้นนำหน้าด้วยขั้นตอนการอุ่นเครื่องเชิงเส้นในช่วงแรก 10% ของขั้นตอนการฝึกอบรม ( num_warmup_steps ) ตามรายงานของ BERT อัตราการเรียนรู้เริ่มต้นจะน้อยกว่าสำหรับการปรับแต่งอย่างละเอียด (ดีที่สุดของ 5e-5, 3e-5, 2e-5)

epochs = 3
batch_size = 32
init_lr = 2e-5

print(f'Fine tuning {tfhub_handle_encoder} model')
bert_preprocess_model = make_bert_preprocess_model(sentence_features)

with strategy.scope():

  # metric have to be created inside the strategy scope
  metrics, loss = get_configuration(tfds_name)

  train_dataset, train_data_size = load_dataset_from_tfds(
      in_memory_ds, tfds_info, train_split, batch_size, bert_preprocess_model)
  steps_per_epoch = train_data_size // batch_size
  num_train_steps = steps_per_epoch * epochs
  num_warmup_steps = num_train_steps // 10

  validation_dataset, validation_data_size = load_dataset_from_tfds(
      in_memory_ds, tfds_info, validation_split, batch_size,
      bert_preprocess_model)
  validation_steps = validation_data_size // batch_size

  classifier_model = build_classifier_model(num_classes)

  optimizer = optimization.create_optimizer(
      init_lr=init_lr,
      num_train_steps=num_train_steps,
      num_warmup_steps=num_warmup_steps,
      optimizer_type='adamw')

  classifier_model.compile(optimizer=optimizer, loss=loss, metrics=[metrics])

  classifier_model.fit(
      x=train_dataset,
      validation_data=validation_dataset,
      steps_per_epoch=steps_per_epoch,
      epochs=epochs,
      validation_steps=validation_steps)
Fine tuning https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/3 model
/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/keras/engine/functional.py:585: UserWarning: Input dict contained keys ['idx', 'label'] which did not match any model input. They will be ignored by the model.
  [n for n in tensors.keys() if n not in ref_input_names])
Epoch 1/3
/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/framework/indexed_slices.py:449: UserWarning: Converting sparse IndexedSlices(IndexedSlices(indices=Tensor("AdamWeightDecay/gradients/StatefulPartitionedCall:1", shape=(None,), dtype=int32), values=Tensor("clip_by_global_norm/clip_by_global_norm/_0:0", dtype=float32), dense_shape=Tensor("AdamWeightDecay/gradients/StatefulPartitionedCall:2", shape=(None,), dtype=int32))) to a dense Tensor of unknown shape. This may consume a large amount of memory.
  "shape. This may consume a large amount of memory." % value)
267/267 [==============================] - 86s 81ms/step - loss: 0.6092 - MatthewsCorrelationCoefficient: 0.0000e+00 - val_loss: 0.4846 - val_MatthewsCorrelationCoefficient: 0.0000e+00
Epoch 2/3
267/267 [==============================] - 14s 53ms/step - loss: 0.3774 - MatthewsCorrelationCoefficient: 0.0000e+00 - val_loss: 0.5322 - val_MatthewsCorrelationCoefficient: 0.0000e+00
Epoch 3/3
267/267 [==============================] - 14s 53ms/step - loss: 0.2623 - MatthewsCorrelationCoefficient: 0.0000e+00 - val_loss: 0.6469 - val_MatthewsCorrelationCoefficient: 0.0000e+00

ส่งออกเพื่อการอนุมาน

คุณจะสร้างแบบจำลองขั้นสุดท้ายที่มีส่วนประมวลผลล่วงหน้าและ BERT ที่ปรับแต่งแล้วที่เราเพิ่งสร้างขึ้น

ณ เวลาอนุมาน การประมวลผลล่วงหน้าจะต้องเป็นส่วนหนึ่งของโมเดล (เนื่องจากไม่มีคิวอินพุตแยกต่างหากอีกต่อไปสำหรับข้อมูลการฝึกที่ทำ) การประมวลผลล่วงหน้าไม่ได้เป็นเพียงการคำนวณเท่านั้น มีทรัพยากรของตัวเอง (ตารางคำศัพท์) ที่ต้องแนบกับ Keras Model ที่บันทึกไว้สำหรับการส่งออก การชุมนุมครั้งสุดท้ายนี้คือสิ่งที่จะรอด

คุณกำลังจะบันทึกรูปแบบบน Colab และต่อมาคุณสามารถดาวน์โหลดเพื่อเก็บไว้สำหรับอนาคต (ดู -> สารบัญ -> ไฟล์)

main_save_path = './my_models'
bert_type = tfhub_handle_encoder.split('/')[-2]
saved_model_name = f'{tfds_name.replace("/", "_")}_{bert_type}'

saved_model_path = os.path.join(main_save_path, saved_model_name)

preprocess_inputs = bert_preprocess_model.inputs
bert_encoder_inputs = bert_preprocess_model(preprocess_inputs)
bert_outputs = classifier_model(bert_encoder_inputs)
model_for_export = tf.keras.Model(preprocess_inputs, bert_outputs)

print('Saving', saved_model_path)

# Save everything on the Colab host (even the variables from TPU memory)
save_options = tf.saved_model.SaveOptions(experimental_io_device='/job:localhost')
model_for_export.save(saved_model_path, include_optimizer=False,
                      options=save_options)
Saving ./my_models/glue_cola_bert_en_uncased_L-12_H-768_A-12
WARNING:absl:Found untraced functions such as restored_function_body, restored_function_body, restored_function_body, restored_function_body, restored_function_body while saving (showing 5 of 910). These functions will not be directly callable after loading.

ทดสอบโมเดล

ขั้นตอนสุดท้ายคือการทดสอบผลลัพธ์ของแบบจำลองที่ส่งออกของคุณ

เพื่อทำการเปรียบเทียบ ให้โหลดแบบจำลองใหม่และทดสอบโดยใช้อินพุตบางส่วนจากการแยกการทดสอบจากชุดข้อมูล

with tf.device('/job:localhost'):
  reloaded_model = tf.saved_model.load(saved_model_path)

วิธียูทิลิตี้

ทดสอบ

with tf.device('/job:localhost'):
  test_dataset = tf.data.Dataset.from_tensor_slices(in_memory_ds[test_split])
  for test_row in test_dataset.shuffle(1000).map(prepare).take(5):
    if len(sentence_features) == 1:
      result = reloaded_model(test_row[0])
    else:
      result = reloaded_model(list(test_row))

    print_bert_results(test_row, result, tfds_name)
sentence: [b'An old woman languished in the forest.']
This sentence is acceptable
BERT raw results: tf.Tensor([-1.7032353  3.3714833], shape=(2,), dtype=float32)

sentence: [b"I went to the movies and didn't pick up the shirts."]
This sentence is acceptable
BERT raw results: tf.Tensor([-0.73970896  1.0806316 ], shape=(2,), dtype=float32)

sentence: [b"Every essay that she's written and which I've read is on that pile."]
This sentence is acceptable
BERT raw results: tf.Tensor([-0.7034159  0.6236454], shape=(2,), dtype=float32)

sentence: [b'Either Bill ate the peaches, or Harry.']
This sentence is unacceptable
BERT raw results: tf.Tensor([ 0.05972151 -0.08620442], shape=(2,), dtype=float32)

sentence: [b'I ran into the baker from whom I bought these bagels.']
This sentence is acceptable
BERT raw results: tf.Tensor([-1.6862067  3.285925 ], shape=(2,), dtype=float32)

หากคุณต้องการที่จะใช้รูปแบบของคุณบน TF การแสดง , จำไว้ว่ามันจะเรียก SavedModel ของคุณผ่านทางหนึ่งของลายเซ็นชื่อของมัน สังเกตว่าอินพุตมีความแตกต่างเล็กน้อย ใน Python คุณสามารถทดสอบได้ดังนี้:

with tf.device('/job:localhost'):
  serving_model = reloaded_model.signatures['serving_default']
  for test_row in test_dataset.shuffle(1000).map(prepare_serving).take(5):
    result = serving_model(**test_row)
    # The 'prediction' key is the classifier's defined model name.
    print_bert_results(list(test_row.values()), result['prediction'], tfds_name)
sentence: b'Everyone attended more than two seminars.'
This sentence is acceptable
BERT raw results: tf.Tensor([-1.5594155  2.862155 ], shape=(2,), dtype=float32)

sentence: b'Most columnists claim that a senior White House official has been briefing them.'
This sentence is acceptable
BERT raw results: tf.Tensor([-1.6298996  3.3155093], shape=(2,), dtype=float32)

sentence: b"That my father, he's lived here all his life is well known to those cops."
This sentence is acceptable
BERT raw results: tf.Tensor([-1.2048947  1.8589772], shape=(2,), dtype=float32)

sentence: b'Ourselves like us.'
This sentence is acceptable
BERT raw results: tf.Tensor([-1.2723312  2.0494034], shape=(2,), dtype=float32)

sentence: b'John is clever.'
This sentence is acceptable
BERT raw results: tf.Tensor([-1.6516167  3.3147635], shape=(2,), dtype=float32)

คุณทำได้! โมเดลที่บันทึกไว้ของคุณสามารถใช้สำหรับการแสดงผลหรือการอนุมานอย่างง่ายในกระบวนการ โดยมี api ที่ง่ายกว่าซึ่งมีโค้ดน้อยกว่าและดูแลรักษาง่ายกว่า

ขั้นตอนถัดไป

เมื่อคุณได้ลองใช้รุ่น BERT พื้นฐานแล้ว คุณสามารถลองใช้รุ่นอื่นเพื่อให้ได้ความแม่นยำมากขึ้นหรืออาจใช้กับรุ่นขนาดเล็กกว่าก็ได้

คุณยังสามารถลองใช้ชุดข้อมูลอื่นๆ ได้อีกด้วย