ดูบน TensorFlow.org | ทำงานใน Google Colab | ดูบน GitHub | ดาวน์โหลดโน๊ตบุ๊ค | ดูรุ่น TF Hub |
BERT สามารถใช้แก้ปัญหาต่างๆ ในการประมวลผลภาษาธรรมชาติได้ คุณจะได้เรียนรู้วิธีการ BERT ปรับแต่งสำหรับงานจำนวนมากจาก มาตรฐานกาว :
โคล่า (คอร์ปัสของภาษาศาสตร์ยอมรับ): เป็นประโยคที่ถูกต้องตามหลักไวยากรณ์?
SST-2 (Stanford ความเชื่อมั่น Treebank): งานคือการคาดการณ์ความเชื่อมั่นของประโยคที่กำหนด
MRPC (Microsoft Research แปลความหมาย Corpus): ตรวจสอบว่าคู่ของประโยคที่มีความหมายเทียบเท่า
QQP (Quora คำถาม Pairs2): ตรวจสอบว่าคู่ของคำถามจะเทียบเท่าความหมาย
MNLI (Multi-แนวธรรมชาติภาษาอนุมาน): ให้เป็นประโยคที่สถานที่ตั้งและประโยคสมมติฐานของงานคือการคาดการณ์ว่าจะเป็นสถานที่สร้างความสมมติฐาน (entailment) ขัดแย้งกับสมมติฐาน (ขัดแย้ง) หรือไม่ (กลาง)
QNLI (คำถาม-ตอบภาษาธรรมชาติอนุมาน): งานคือการตรวจสอบว่าประโยคบริบทมีคำตอบสำหรับคำถามที่
RTE (ตระหนักถึงข้อความ entailment): ตรวจสอบว่าประโยค entails สมมติฐานที่กำหนดหรือไม่
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_name = 'bert_en_uncased_L-12_H-768_A-12'
map_name_to_handle = {
'bert_en_uncased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/3',
'bert_en_uncased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_uncased_L-24_H-1024_A-16/3',
'bert_en_wwm_uncased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_wwm_uncased_L-24_H-1024_A-16/3',
'bert_en_cased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_cased_L-12_H-768_A-12/3',
'bert_en_cased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_cased_L-24_H-1024_A-16/3',
'bert_en_wwm_cased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_wwm_cased_L-24_H-1024_A-16/3',
'bert_multi_cased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_multi_cased_L-12_H-768_A-12/3',
'small_bert/bert_en_uncased_L-2_H-128_A-2':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-2_H-128_A-2/1',
'small_bert/bert_en_uncased_L-2_H-256_A-4':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-2_H-256_A-4/1',
'small_bert/bert_en_uncased_L-2_H-512_A-8':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-2_H-512_A-8/1',
'small_bert/bert_en_uncased_L-2_H-768_A-12':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-2_H-768_A-12/1',
'small_bert/bert_en_uncased_L-4_H-128_A-2':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-128_A-2/1',
'small_bert/bert_en_uncased_L-4_H-256_A-4':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-256_A-4/1',
'small_bert/bert_en_uncased_L-4_H-512_A-8':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-512_A-8/1',
'small_bert/bert_en_uncased_L-4_H-768_A-12':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-768_A-12/1',
'small_bert/bert_en_uncased_L-6_H-128_A-2':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-6_H-128_A-2/1',
'small_bert/bert_en_uncased_L-6_H-256_A-4':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-6_H-256_A-4/1',
'small_bert/bert_en_uncased_L-6_H-512_A-8':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-6_H-512_A-8/1',
'small_bert/bert_en_uncased_L-6_H-768_A-12':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-6_H-768_A-12/1',
'small_bert/bert_en_uncased_L-8_H-128_A-2':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-8_H-128_A-2/1',
'small_bert/bert_en_uncased_L-8_H-256_A-4':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-8_H-256_A-4/1',
'small_bert/bert_en_uncased_L-8_H-512_A-8':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-8_H-512_A-8/1',
'small_bert/bert_en_uncased_L-8_H-768_A-12':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-8_H-768_A-12/1',
'small_bert/bert_en_uncased_L-10_H-128_A-2':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-10_H-128_A-2/1',
'small_bert/bert_en_uncased_L-10_H-256_A-4':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-10_H-256_A-4/1',
'small_bert/bert_en_uncased_L-10_H-512_A-8':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-10_H-512_A-8/1',
'small_bert/bert_en_uncased_L-10_H-768_A-12':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-10_H-768_A-12/1',
'small_bert/bert_en_uncased_L-12_H-128_A-2':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-12_H-128_A-2/1',
'small_bert/bert_en_uncased_L-12_H-256_A-4':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-12_H-256_A-4/1',
'small_bert/bert_en_uncased_L-12_H-512_A-8':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-12_H-512_A-8/1',
'small_bert/bert_en_uncased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-12_H-768_A-12/1',
'albert_en_base':
'https://tfhub.dev/tensorflow/albert_en_base/2',
'albert_en_large':
'https://tfhub.dev/tensorflow/albert_en_large/2',
'albert_en_xlarge':
'https://tfhub.dev/tensorflow/albert_en_xlarge/2',
'albert_en_xxlarge':
'https://tfhub.dev/tensorflow/albert_en_xxlarge/2',
'electra_small':
'https://tfhub.dev/google/electra_small/2',
'electra_base':
'https://tfhub.dev/google/electra_base/2',
'experts_pubmed':
'https://tfhub.dev/google/experts/bert/pubmed/2',
'experts_wiki_books':
'https://tfhub.dev/google/experts/bert/wiki_books/2',
'talking-heads_base':
'https://tfhub.dev/tensorflow/talkheads_ggelu_bert_en_base/1',
'talking-heads_large':
'https://tfhub.dev/tensorflow/talkheads_ggelu_bert_en_large/1',
}
map_model_to_preprocess = {
'bert_en_uncased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'bert_en_uncased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'bert_en_wwm_cased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_cased_preprocess/3',
'bert_en_cased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_cased_preprocess/3',
'bert_en_cased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_cased_preprocess/3',
'bert_en_wwm_uncased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-2_H-128_A-2':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-2_H-256_A-4':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-2_H-512_A-8':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-2_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-4_H-128_A-2':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-4_H-256_A-4':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-4_H-512_A-8':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-4_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-6_H-128_A-2':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-6_H-256_A-4':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-6_H-512_A-8':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-6_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-8_H-128_A-2':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-8_H-256_A-4':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-8_H-512_A-8':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-8_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-10_H-128_A-2':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-10_H-256_A-4':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-10_H-512_A-8':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-10_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-12_H-128_A-2':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-12_H-256_A-4':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-12_H-512_A-8':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'bert_multi_cased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_multi_cased_preprocess/3',
'albert_en_base':
'https://tfhub.dev/tensorflow/albert_en_preprocess/3',
'albert_en_large':
'https://tfhub.dev/tensorflow/albert_en_preprocess/3',
'albert_en_xlarge':
'https://tfhub.dev/tensorflow/albert_en_preprocess/3',
'albert_en_xxlarge':
'https://tfhub.dev/tensorflow/albert_en_preprocess/3',
'electra_small':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'electra_base':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'experts_pubmed':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'experts_wiki_books':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'talking-heads_base':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'talking-heads_large':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
}
tfhub_handle_encoder = map_name_to_handle[bert_model_name]
tfhub_handle_preprocess = map_model_to_preprocess[bert_model_name]
print('BERT model selected :', tfhub_handle_encoder)
print('Preprocessing model auto-selected:', tfhub_handle_preprocess)
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 (สำหรับหลายประโยค) เนื่องจากชุดข้อมูลเหล่านี้มีขนาดเล็กและไม่ใช้เวลาในการปรับแต่งนาน
tfds_name = 'glue/cola'
tfds_info = tfds.builder(tfds_name).info
sentence_features = list(tfds_info.features.keys())
sentence_features.remove('idx')
sentence_features.remove('label')
available_splits = list(tfds_info.splits.keys())
train_split = 'train'
validation_split = 'validation'
test_split = 'test'
if tfds_name == 'glue/mnli':
validation_split = 'validation_matched'
test_split = 'test_matched'
num_classes = tfds_info.features['label'].num_classes
num_examples = tfds_info.splits.total_num_examples
print(f'Using {tfds_name} from TFDS')
print(f'This dataset has {num_examples} examples')
print(f'Number of classes: {num_classes}')
print(f'Features {sentence_features}')
print(f'Splits {available_splits}')
with tf.device('/job:localhost'):
# batch_size=-1 is a way to load the dataset into memory
in_memory_ds = tfds.load(tfds_name, batch_size=-1, shuffle_files=True)
# The code below is just to show some samples from the selected dataset
print(f'Here are some sample rows from {tfds_name} dataset')
sample_dataset = tf.data.Dataset.from_tensor_slices(in_memory_ds[train_split])
labels_names = tfds_info.features['label'].names
print(labels_names)
print()
sample_i = 1
for sample_row in sample_dataset.take(5):
samples = [sample_row[feature] for feature in sentence_features]
print(f'sample row {sample_i}')
for sample in samples:
print(sample.numpy())
sample_label = sample_row['label']
print(f'label: {sample_label} ({labels_names[sample_label]})')
print()
sample_i += 1
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)
วิธียูทิลิตี้
def prepare(record):
model_inputs = [[record[ft]] for ft in sentence_features]
return model_inputs
def prepare_serving(record):
model_inputs = {ft: record[ft] for ft in sentence_features}
return model_inputs
def print_bert_results(test, bert_result, dataset_name):
bert_result_class = tf.argmax(bert_result, axis=1)[0]
if dataset_name == 'glue/cola':
print('sentence:', test[0].numpy())
if bert_result_class == 1:
print('This sentence is acceptable')
else:
print('This sentence is unacceptable')
elif dataset_name == 'glue/sst2':
print('sentence:', test[0])
if bert_result_class == 1:
print('This sentence has POSITIVE sentiment')
else:
print('This sentence has NEGATIVE sentiment')
elif dataset_name == 'glue/mrpc':
print('sentence1:', test[0])
print('sentence2:', test[1])
if bert_result_class == 1:
print('Are a paraphrase')
else:
print('Are NOT a paraphrase')
elif dataset_name == 'glue/qqp':
print('question1:', test[0])
print('question2:', test[1])
if bert_result_class == 1:
print('Questions are similar')
else:
print('Questions are NOT similar')
elif dataset_name == 'glue/mnli':
print('premise :', test[0])
print('hypothesis:', test[1])
if bert_result_class == 1:
print('This premise is NEUTRAL to the hypothesis')
elif bert_result_class == 2:
print('This premise CONTRADICTS the hypothesis')
else:
print('This premise ENTAILS the hypothesis')
elif dataset_name == 'glue/qnli':
print('question:', test[0])
print('sentence:', test[1])
if bert_result_class == 1:
print('The question is NOT answerable by the sentence')
else:
print('The question is answerable by the sentence')
elif dataset_name == 'glue/rte':
print('sentence1:', test[0])
print('sentence2:', test[1])
if bert_result_class == 1:
print('Sentence1 DOES NOT entails sentence2')
else:
print('Sentence1 entails sentence2')
elif dataset_name == 'glue/wnli':
print('sentence1:', test[0])
print('sentence2:', test[1])
if bert_result_class == 1:
print('Sentence1 DOES NOT entails sentence2')
else:
print('Sentence1 entails sentence2')
print('BERT raw results:', bert_result[0])
print()
ทดสอบ
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 พื้นฐานแล้ว คุณสามารถลองใช้รุ่นอื่นเพื่อให้ได้ความแม่นยำมากขึ้นหรืออาจใช้กับรุ่นขนาดเล็กกว่าก็ได้
คุณยังสามารถลองใช้ชุดข้อมูลอื่นๆ ได้อีกด้วย