Google I / O คืนวันที่ 18-20 พ.ค. จองพื้นที่และสร้างตารางเวลาของคุณ ลงทะเบียนตอนนี้

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

ดูใน TensorFlow.org เรียกใช้ใน Google Colab ดูบน GitHub ดาวน์โหลดสมุดบันทึก ดูโมเดล TF Hub

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

  1. CoLA (Corpus of Linguistic Acceptability): ประโยคถูกต้องตามหลักไวยากรณ์หรือไม่?

  2. SST-2 (Stanford Sentiment Treebank): ภารกิจคือการทำนายความรู้สึกของประโยคที่กำหนด

  3. MRPC (Microsoft Research Paraphrase Corpus): ตรวจสอบว่าคู่ของประโยคมีความหมายเทียบเท่ากันหรือไม่

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

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

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

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

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

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

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

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

ติดตั้ง

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

pip install -q -U tensorflow-text

คุณจะใช้เครื่องมือเพิ่มประสิทธิภาพ AdamW จาก tensorflow / models เพื่อปรับแต่ง 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')

จากนั้นกำหนดค่า 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 เครื่องเดียว ดู คู่มือ TPU ของ TensorFlow สำหรับข้อมูลเพิ่มเติม

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.test.is_gpu_available():
  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 ดั้งเดิม
  • BERT ขนาดเล็ก มีสถาปัตยกรรมทั่วไปเหมือนกัน แต่บล็อก Transformer น้อยกว่าและ / หรือเล็กกว่าซึ่งช่วยให้คุณสำรวจการแลกเปลี่ยนระหว่างความเร็วขนาดและคุณภาพ
  • ALBERT : "A Lite BERT" สี่ขนาดที่แตกต่างกันซึ่งจะลดขนาดโมเดล (แต่ไม่ใช่เวลาในการคำนวณ) โดยการแชร์พารามิเตอร์ระหว่างเลเยอร์
  • BERT Experts : แปดรุ่นที่ทั้งหมดมีสถาปัตยกรรมพื้นฐานของ BERT แต่มีตัวเลือกระหว่างโดเมนก่อนการฝึกอบรมที่แตกต่างกันเพื่อให้สอดคล้องกับงานเป้าหมายมากขึ้น
  • Electra มีสถาปัตยกรรมแบบเดียวกับ BERT (มีสามขนาดที่แตกต่างกัน) แต่ได้รับการฝึกอบรมล่วงหน้าในฐานะผู้เลือกปฏิบัติในการตั้งค่าที่คล้ายกับ Generative Adversarial Network (GAN)
  • BERT with Talking-Heads Attention และ Gated GELU [ base , large ] มีการปรับปรุงสองประการสำหรับแกนหลักของสถาปัตยกรรม Transformer

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

ในบทช่วยสอนนี้คุณจะเริ่มต้นด้วย 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

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

ใน ข้อความ Classify ด้วย BERT colab โมเดลก่อนการประมวลผลจะถูกใช้โดยตรงกับตัวเข้ารหัส BERT

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

นอกเหนือจากข้อกำหนดของ TPU แล้วยังสามารถช่วยให้การประมวลผลล่วงหน้าทำได้แบบอะซิงโครนัสในท่ออินพุต (คุณสามารถเรียนรู้เพิ่มเติมได้ใน คู่มือประสิทธิภาพ 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_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_mask', 'input_type_ids', 'input_word_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)
('Failed to import pydot. You must `pip install pydot` and install graphviz (https://graphviz.gitlab.io/download/), ', 'for `pydotprint` 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):
  inputs = dict(
      input_word_ids=tf.keras.layers.Input(shape=(None,), dtype=tf.int32),
      input_mask=tf.keras.layers.Input(shape=(None,), dtype=tf.int32),
      input_type_ids=tf.keras.layers.Input(shape=(None,), dtype=tf.int32),
  )

  encoder = hub.KerasLayer(tfhub_handle_encoder, trainable=True, name='encoder')
  net = encoder(inputs)['pooled_output']
  net = tf.keras.layers.Dropout(rate=0.1)(net)
  net = tf.keras.layers.Dense(num_classes, activation=None, name='classifier')(net)
  return tf.keras.Model(inputs, net, name='prediction')

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

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

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

tf.keras.utils.plot_model(test_classifier_model)
('Failed to import pydot. You must `pip install pydot` and install graphviz (https://graphviz.gitlab.io/download/), ', 'for `pydotprint` to work.')

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

คุณจะใช้ TensorFlow DataSet จากชุดมาตรฐาน GLUE

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 ['test', 'train', 'validation']
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/tensorflow/python/keras/engine/functional.py:595: 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:437: 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 [==============================] - 79s 77ms/step - loss: 0.5812 - MatthewsCorrelationCoefficient: 0.5968 - val_loss: 0.4688 - val_MatthewsCorrelationCoefficient: 0.5871
Epoch 2/3
267/267 [==============================] - 15s 58ms/step - loss: 0.3561 - MatthewsCorrelationCoefficient: 0.5906 - val_loss: 0.5723 - val_MatthewsCorrelationCoefficient: 0.5871
Epoch 3/3
267/267 [==============================] - 15s 58ms/step - loss: 0.2352 - MatthewsCorrelationCoefficient: 0.5909 - val_loss: 0.6748 - val_MatthewsCorrelationCoefficient: 0.5871

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

คุณจะสร้างแบบจำลองขั้นสุดท้ายที่มีส่วนก่อนการประมวลผลและ 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.
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'Onto the table jumped a cat.']
This sentence is acceptable
BERT raw results: tf.Tensor([-1.5364362  3.0245366], shape=(2,), dtype=float32)

sentence: [b'it is important to John to leave.']
This sentence is acceptable
BERT raw results: tf.Tensor([-2.1081586  4.0080795], shape=(2,), dtype=float32)

sentence: [b'Gina filled the pitcher with lemonade.']
This sentence is acceptable
BERT raw results: tf.Tensor([-2.5824902  3.740626 ], shape=(2,), dtype=float32)

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

sentence: [b'The student hated his morphology professor.']
This sentence is acceptable
BERT raw results: tf.Tensor([-2.4559186  3.5234451], shape=(2,), dtype=float32)

หากคุณต้องการใช้โมเดลของคุณบน TF Serving โปรดจำไว้ว่าโมเดลจะเรียก 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'His loves him'
This sentence is unacceptable
BERT raw results: tf.Tensor([ 2.160802  -2.4170692], shape=(2,), dtype=float32)

sentence: b'John says Mary likes himself.'
This sentence is unacceptable
BERT raw results: tf.Tensor([ 1.759533  -2.0088294], shape=(2,), dtype=float32)

sentence: b'He treats John very under.'
This sentence is acceptable
BERT raw results: tf.Tensor([-0.19971004  1.1566539 ], shape=(2,), dtype=float32)

sentence: b'Karen asked where him to vote for.'
This sentence is unacceptable
BERT raw results: tf.Tensor([ 2.1606677 -2.1753395], shape=(2,), dtype=float32)

sentence: b"I didn't give Jack Ed's picture of anybody."
This sentence is unacceptable
BERT raw results: tf.Tensor([ 1.755337 -1.904901], shape=(2,), dtype=float32)

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

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

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

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