การประมวลผลล่วงหน้าของ BERT ด้วยข้อความ TF

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

ภาพรวม

การประมวลผลข้อความล่วงหน้าเป็นการแปลงข้อความดิบแบบ end-to-end เป็นอินพุตจำนวนเต็มของโมเดล โมเดล NLP มักจะมาพร้อมกับโค้ด Python หลายร้อย (ถ้าไม่ใช่หลายพัน) บรรทัดสำหรับการประมวลผลข้อความล่วงหน้า การประมวลผลข้อความล่วงหน้ามักเป็นสิ่งที่ท้าทายสำหรับโมเดลเนื่องจาก:

  • ความเบ้ในการฝึกอบรม เป็นเรื่องยากขึ้นเรื่อยๆ ที่จะตรวจสอบให้แน่ใจว่าตรรกะในการประมวลผลล่วงหน้าของข้อมูลเข้าของแบบจำลองนั้นสอดคล้องกันในทุกขั้นตอนของการพัฒนาแบบจำลอง (เช่น การฝึกเตรียมล่วงหน้า การปรับละเอียด การประเมิน การอนุมาน) การใช้ไฮเปอร์พารามิเตอร์ที่แตกต่างกัน โทเค็นไลเซชัน อัลกอริธึมการประมวลผลสตริงล่วงหน้า หรือเพียงแค่การบรรจุอินพุตโมเดลที่ไม่สอดคล้องกันที่ขั้นตอนต่างๆ อาจให้ผลที่ยากต่อการดีบักและส่งผลร้ายต่อโมเดล

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

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

นอกจากนี้ อินเทอร์เฟซของโมเดลที่ง่ายกว่ายังทำให้สะดวกยิ่งขึ้นในการลองใช้โมเดล (เช่น การอนุมานหรือการฝึก) ในชุดข้อมูลต่างๆ ที่ยังไม่ได้สำรวจ

การประมวลผลข้อความล่วงหน้าด้วย TF.Text

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

กวดวิชานี้จะแสดงวิธีการใช้ TF.Text Ops preprocessing การแปลงข้อมูลข้อความลงในปัจจัยการผลิตสำหรับรูปแบบ BERT และปัจจัยการผลิตสำหรับภาษากำบัง pretraining งานที่อธิบายไว้ใน "หน้ากาก LM และกาวขั้นตอน" ของ เบิร์ต: Pre-ฝึกอบรมลึกแบบสองทิศทางหม้อแปลงภาษา ความเข้าใจ กระบวนการนี้เกี่ยวข้องกับการแปลงข้อความให้เป็นหน่วยคำย่อย รวมประโยค ตัดแต่งเนื้อหาให้มีขนาดคงที่ และแยกป้ายกำกับสำหรับงานสร้างแบบจำลองภาษาที่ปิดบัง

ติดตั้ง

มานำเข้าแพ็คเกจและไลบรารีที่เราต้องการก่อน

pip install -q -U tensorflow-text
import tensorflow as tf
import tensorflow_text as text
import functools

ข้อมูลของเรามีสองคุณสมบัติข้อความและเราสามารถสร้างตัวอย่างที่ tf.data.Dataset เป้าหมายของเราคือการสร้างฟังก์ชั่นที่เราสามารถจัดหา Dataset.map() ด้วยที่จะใช้ในการฝึกอบรม

examples = {
    "text_a": [
      b"Sponge bob Squarepants is an Avenger",
      b"Marvel Avengers"
    ],
    "text_b": [
     b"Barack Obama is the President.",
     b"President is the highest office"
  ],
}

dataset = tf.data.Dataset.from_tensor_slices(examples)
next(iter(dataset))
{'text_a': <tf.Tensor: shape=(), dtype=string, numpy=b'Sponge bob Squarepants is an Avenger'>,
 'text_b': <tf.Tensor: shape=(), dtype=string, numpy=b'Barack Obama is the President.'>}

Tokenizing

ขั้นตอนแรกของเราคือรันการประมวลผลล่วงหน้าของสตริงและแปลงชุดข้อมูลของเราให้เป็นโทเค็น ซึ่งสามารถทำได้โดยใช้ text.BertTokenizer ซึ่งเป็น text.Splitter ที่สามารถ tokenize ประโยคลงใน subwords หรือ wordpieces สำหรับ รุ่น BERT ให้คำศัพท์ที่สร้างขึ้นจาก ขั้นตอนวิธีการ Wordpiece คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับ tokenizers subword อื่น ๆ ที่มีอยู่ใน TF.Text จาก ที่นี่

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

_VOCAB = [
    # Special tokens
    b"[UNK]", b"[MASK]", b"[RANDOM]", b"[CLS]", b"[SEP]",
    # Suffixes
    b"##ack", b"##ama", b"##ger", b"##gers", b"##onge", b"##pants",  b"##uare",
    b"##vel", b"##ven", b"an", b"A", b"Bar", b"Hates", b"Mar", b"Ob",
    b"Patrick", b"President", b"Sp", b"Sq", b"bob", b"box", b"has", b"highest",
    b"is", b"office", b"the",
]

_START_TOKEN = _VOCAB.index(b"[CLS]")
_END_TOKEN = _VOCAB.index(b"[SEP]")
_MASK_TOKEN = _VOCAB.index(b"[MASK]")
_RANDOM_TOKEN = _VOCAB.index(b"[RANDOM]")
_UNK_TOKEN = _VOCAB.index(b"[UNK]")
_MAX_SEQ_LEN = 8
_MAX_PREDICTIONS_PER_BATCH = 5

_VOCAB_SIZE = len(_VOCAB)

lookup_table = tf.lookup.StaticVocabularyTable(
    tf.lookup.KeyValueTensorInitializer(
      keys=_VOCAB,
      key_dtype=tf.string,
      values=tf.range(
          tf.size(_VOCAB, out_type=tf.int64), dtype=tf.int64),
      value_dtype=tf.int64),
      num_oov_buckets=1
)

Let 's สร้าง text.BertTokenizer ใช้คำศัพท์ดังกล่าวข้างต้นและ tokenize ปัจจัยการผลิตที่ข้อความเป็น RaggedTensor .`

bert_tokenizer = text.BertTokenizer(lookup_table, token_out_type=tf.string)
bert_tokenizer.tokenize(examples["text_a"])
<tf.RaggedTensor [[[b'Sp', b'##onge'], [b'bob'], [b'Sq', b'##uare', b'##pants'], [b'is'], [b'an'], [b'A', b'##ven', b'##ger']], [[b'Mar', b'##vel'], [b'A', b'##ven', b'##gers']]]>
bert_tokenizer.tokenize(examples["text_b"])
<tf.RaggedTensor [[[b'Bar', b'##ack'], [b'Ob', b'##ama'], [b'is'], [b'the'], [b'President'], [b'[UNK]']], [[b'President'], [b'is'], [b'the'], [b'highest'], [b'office']]]>

เอาท์พุทข้อความจาก text.BertTokenizer ช่วยให้เราเห็นว่าข้อความจะถูก tokenized แต่รูปแบบต้องใช้รหัสจำนวนเต็ม เราสามารถตั้งค่า token_out_type พระรามเพื่อ tf.int64 ที่จะได้รับจำนวนเต็มรหัส (ซึ่งเป็นดัชนีลงไปในคำศัพท์ที่)

bert_tokenizer = text.BertTokenizer(lookup_table, token_out_type=tf.int64)
segment_a = bert_tokenizer.tokenize(examples["text_a"])
segment_a
<tf.RaggedTensor [[[22, 9], [24], [23, 11, 10], [28], [14], [15, 13, 7]], [[18, 12], [15, 13, 8]]]>
segment_b = bert_tokenizer.tokenize(examples["text_b"])
segment_b
<tf.RaggedTensor [[[16, 5], [19, 6], [28], [30], [21], [0]], [[21], [28], [30], [27], [29]]]>

text.BertTokenizer ส่งกลับ RaggedTensor มีรูปร่าง [batch, num_tokens, num_wordpieces] เพราะเราไม่จำเป็นต้องเสริม num_tokens มิติสำหรับกรณีการใช้งานของเราในปัจจุบันเราสามารถผสานสองมิติสุดท้ายที่จะได้รับ RaggedTensor มีรูปร่าง [batch, num_wordpieces] :

segment_a = segment_a.merge_dims(-2, -1)
segment_a
<tf.RaggedTensor [[22, 9, 24, 23, 11, 10, 28, 14, 15, 13, 7], [18, 12, 15, 13, 8]]>
segment_b = segment_b.merge_dims(-2, -1)
segment_b
<tf.RaggedTensor [[16, 5, 19, 6, 28, 30, 21, 0], [21, 28, 30, 27, 29]]>

การตัดแต่งเนื้อหา

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

เราสามารถแก้ไขปัญหานี้โดยใช้ text.Trimmer เพื่อตัดเนื้อหาของเราลงไปขนาดที่กำหนดไว้ (ครั้งเดียวตัดแบ่งตามแกนที่ผ่านมา) มีที่แตกต่างกัน text.Trimmer ประเภทที่เลือกเนื้อหาที่จะรักษาโดยใช้ขั้นตอนวิธีการที่แตกต่างกัน text.RoundRobinTrimmer ตัวอย่างเช่นจะจัดสรรโควต้าอย่างเท่าเทียมกันสำหรับแต่ละเซ็กเมนต์ แต่อาจตัดปลายของประโยค text.WaterfallTrimmer จะตัดเริ่มต้นจากจุดสิ้นสุดของประโยคที่ผ่านมา

สำหรับตัวอย่างของเราเราจะใช้ RoundRobinTrimmer ซึ่งเลือกรายการจากแต่ละกลุ่มในลักษณะจากซ้ายไปขวา

trimmer = text.RoundRobinTrimmer(max_seq_length=[_MAX_SEQ_LEN])
trimmed = trimmer.trim([segment_a, segment_b])
trimmed
[<tf.RaggedTensor [[22, 9, 24, 23], [18, 12, 15, 13]]>,
 <tf.RaggedTensor [[16, 5, 19, 6], [21, 28, 30, 27]]>]

trimmed ในขณะนี้มีกลุ่มที่จำนวนขององค์ประกอบทั่วชุดคือ 8 องค์ประกอบ (เมื่อตัดแบ่งตามแกน = -1)

การรวมกลุ่ม

ตอนนี้เรามีกลุ่มตัดเราสามารถรวมเข้าด้วยกันเพื่อให้ได้คนเดียว RaggedTensor BERT ใช้ราชสกุลพิเศษเพื่อระบุจุดเริ่มต้น ( [CLS] ) และจุดสิ้นสุดของส่วน ( [SEP] ) นอกจากนี้เรายังต้อง RaggedTensor ระบุว่ารายการในรวม Tensor เป็นของซึ่งส่วน เราสามารถใช้ text.combine_segments() ที่จะได้รับทั้งสองคนนี้ Tensor พร้อมด้วยสัญญาณพิเศษแทรก

segments_combined, segments_ids = text.combine_segments(
  [segment_a, segment_b],
  start_of_sequence_id=_START_TOKEN, end_of_segment_id=_END_TOKEN)
segments_combined, segments_ids
(<tf.RaggedTensor [[3, 22, 9, 24, 23, 11, 10, 28, 14, 15, 13, 7, 4, 16, 5, 19, 6, 28, 30, 21, 0, 4], [3, 18, 12, 15, 13, 8, 4, 21, 28, 30, 27, 29, 4]]>,
 <tf.RaggedTensor [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1]]>)

งานแบบจำลองภาษาที่สวมหน้ากาก

ตอนนี้เรามีปัจจัยการผลิตขั้นพื้นฐานของเราเราสามารถเริ่มต้นที่จะดึงปัจจัยการผลิตที่จำเป็นสำหรับ "หน้ากาก LM และกาวขั้นตอน" งานที่อธิบายไว้ใน BERT: Pre-ฝึกอบรมลึกแบบสองทิศทางหม้อแปลงภาษาเข้าใจ

งานแบบจำลองภาษาที่ปิดบังมีปัญหาย่อยสองปัญหาให้เรานึกถึง: (1) รายการใดบ้างที่จะเลือกสำหรับการกำบังและ (2) ค่าเหล่านี้กำหนดไว้อย่างไร

การเลือกรายการ

เพราะเราจะเลือกที่จะเลือกรายการสุ่มสำหรับกำบังเราจะใช้ text.RandomItemSelector RandomItemSelector สุ่มเลือกรายการในเรื่องชุดข้อ จำกัด ที่กำหนด ( max_selections_per_batch , selection_rate และ unselectable_ids ) และผลตอบแทนหน้ากากบูลแสดงให้เห็นว่ารายการที่ได้รับการคัดเลือก

random_selector = text.RandomItemSelector(
    max_selections_per_batch=_MAX_PREDICTIONS_PER_BATCH,
    selection_rate=0.2,
    unselectable_ids=[_START_TOKEN, _END_TOKEN, _UNK_TOKEN]
)
selected = random_selector.get_selection_mask(
    segments_combined, axis=1)
selected
<tf.RaggedTensor [[False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, True, True, True, False, False], [False, False, False, False, False, True, False, False, False, False, False, True, False]]>

การเลือกมูลค่าหน้ากาก

วิธีการอธิบายกระดาษ BERT ต้นฉบับสำหรับการเลือกค่ามาส์กมีดังนี้:

สำหรับ mask_token_rate ของเวลาที่เปลี่ยนรายการที่มี [MASK] โทเค็น:

"my dog is hairy" -> "my dog is [MASK]"

สำหรับ random_token_rate ของเวลาที่เปลี่ยนรายการด้วยคำสุ่ม:

"my dog is hairy" -> "my dog is apple"

สำหรับ 1 - mask_token_rate - random_token_rate ของเวลาที่ให้รายการที่ไม่เปลี่ยนแปลง:

"my dog is hairy" -> "my dog is hairy."

text.MaskedValuesChooser สุนทรีย์ตรรกะนี้สามารถนำมาใช้สำหรับการทำงานประมวลผลเบื้องต้นของเรา นี่คือตัวอย่างของสิ่งที่ MaskValuesChooser ผลตอบแทนที่ได้รับ mask_token_rate 80% และเริ่มต้น random_token_rate :

input_ids = tf.ragged.constant([[19, 7, 21, 20, 9, 8], [13, 4, 16, 5], [15, 10, 12, 11, 6]])
mask_values_chooser = text.MaskValuesChooser(_VOCAB_SIZE, _MASK_TOKEN, 0.8)
mask_values_chooser.get_mask_values(input_ids)
<tf.RaggedTensor [[1, 1, 1, 1, 1, 1], [1, 1, 1, 1], [1, 10, 1, 1, 6]]>

เมื่อมาพร้อมกับ RaggedTensor ป้อนข้อมูล text.MaskValuesChooser ส่งกลับ RaggedTensor ของรูปร่างเดียวกันกับทั้ง _MASK_VALUE (0), รหัสสุ่มหรือรหัสไม่เปลี่ยนแปลงเดียวกัน

การสร้างอินพุตสำหรับงานโมเดลภาษาที่ปกปิด

ตอนนี้เรามี RandomItemSelector เพื่อช่วยให้เราเลือกรายการสำหรับกำบังและ text.MaskValuesChooser ในการกำหนดค่าที่เราสามารถใช้ text.mask_language_model() จะรวบรวมปัจจัยการผลิตทั้งหมดของงานนี้สำหรับรูปแบบเบิร์ตของเรา

masked_token_ids, masked_pos, masked_lm_ids = text.mask_language_model(
  segments_combined,
  item_selector=random_selector, mask_values_chooser=mask_values_chooser)
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/util/dispatch.py:206: batch_gather (from tensorflow.python.ops.array_ops) is deprecated and will be removed after 2017-10-25.
Instructions for updating:
`tf.batch_gather` is deprecated, please use `tf.gather` with `batch_dims=-1` instead.

ดำน้ำ Let 's ลึกและตรวจสอบผลของ mask_language_model() การส่งออกของ masked_token_ids คือ:

masked_token_ids
<tf.RaggedTensor [[3, 22, 1, 24, 23, 1, 10, 28, 1, 15, 1, 7, 4, 16, 5, 19, 6, 28, 30, 21, 0, 4], [3, 18, 12, 15, 13, 1, 4, 21, 28, 30, 27, 1, 4]]>

โปรดจำไว้ว่าข้อมูลที่ป้อนของเราถูกเข้ารหัสโดยใช้คำศัพท์ ถ้าเราถอดรหัส masked_token_ids ใช้คำศัพท์ของเราเราจะได้รับ:

tf.gather(_VOCAB, masked_token_ids)
<tf.RaggedTensor [[b'[CLS]', b'Sp', b'[MASK]', b'bob', b'Sq', b'[MASK]', b'##pants', b'is', b'[MASK]', b'A', b'[MASK]', b'##ger', b'[SEP]', b'Bar', b'##ack', b'Ob', b'##ama', b'is', b'the', b'President', b'[UNK]', b'[SEP]'], [b'[CLS]', b'Mar', b'##vel', b'A', b'##ven', b'[MASK]', b'[SEP]', b'President', b'is', b'the', b'highest', b'[MASK]', b'[SEP]']]>

ขอให้สังเกตว่าบางราชสกุล wordpiece ได้รับการแทนที่ด้วยทั้ง [MASK] , [RANDOM] หรือค่า ID ที่แตกต่างกัน masked_pos การส่งออกจะช่วยให้เราดัชนี (ในชุดนั้น) ของสัญญาณที่ได้รับการแทนที่

masked_pos
<tf.RaggedTensor [[2, 5, 8, 10], [5, 11]]>

masked_lm_ids ทำให้เรามีค่าเดิมของโทเค็น

masked_lm_ids
<tf.RaggedTensor [[9, 11, 14, 13], [8, 29]]>

เราสามารถถอดรหัส ID ที่นี่อีกครั้งเพื่อรับค่าที่มนุษย์อ่านได้

tf.gather(_VOCAB, masked_lm_ids)
<tf.RaggedTensor [[b'##onge', b'##uare', b'an', b'##ven'], [b'##gers', b'office']]>

อินพุตโมเดลแพดดิ้ง

ตอนนี้เรามีปัจจัยการผลิตทั้งหมดสำหรับรูปแบบของเราขั้นตอนสุดท้ายในการประมวลผลเบื้องต้นของเราคือการจัดแพคเกจพวกเขาเข้าสู่การแก้ไข 2 มิติ Tensor s กับ padding และยังสร้างหน้ากาก Tensor แสดงให้เห็นค่าที่มีค่าแผ่น เราสามารถใช้ text.pad_model_inputs() เพื่อช่วยให้เรากับงานนี้

# Prepare and pad combined segment inputs
input_word_ids, input_mask = text.pad_model_inputs(
  masked_token_ids, max_seq_length=_MAX_SEQ_LEN)
input_type_ids, _ = text.pad_model_inputs(
  masked_token_ids, max_seq_length=_MAX_SEQ_LEN)

# Prepare and pad masking task inputs
masked_lm_positions, masked_lm_weights = text.pad_model_inputs(
  masked_token_ids, max_seq_length=_MAX_PREDICTIONS_PER_BATCH)
masked_lm_ids, _ = text.pad_model_inputs(
  masked_lm_ids, max_seq_length=_MAX_PREDICTIONS_PER_BATCH)

model_inputs = {
    "input_word_ids": input_word_ids,
    "input_mask": input_mask,
    "input_type_ids": input_type_ids,
    "masked_lm_ids": masked_lm_ids,
    "masked_lm_positions": masked_lm_positions,
    "masked_lm_weights": masked_lm_weights,
}
model_inputs
{'input_word_ids': <tf.Tensor: shape=(2, 8), dtype=int64, numpy=
 array([[ 3, 22,  1, 24, 23,  1, 10, 28],
        [ 3, 18, 12, 15, 13,  1,  4, 21]])>,
 'input_mask': <tf.Tensor: shape=(2, 8), dtype=int64, numpy=
 array([[1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1]])>,
 'input_type_ids': <tf.Tensor: shape=(2, 8), dtype=int64, numpy=
 array([[ 3, 22,  1, 24, 23,  1, 10, 28],
        [ 3, 18, 12, 15, 13,  1,  4, 21]])>,
 'masked_lm_ids': <tf.Tensor: shape=(2, 5), dtype=int64, numpy=
 array([[ 9, 11, 14, 13,  0],
        [ 8, 29,  0,  0,  0]])>,
 'masked_lm_positions': <tf.Tensor: shape=(2, 5), dtype=int64, numpy=
 array([[ 3, 22,  1, 24, 23],
        [ 3, 18, 12, 15, 13]])>,
 'masked_lm_weights': <tf.Tensor: shape=(2, 5), dtype=int64, numpy=
 array([[1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1]])>}

ทบทวน

มาทบทวนสิ่งที่เรามีจนถึงตอนนี้และประกอบฟังก์ชันการประมวลผลล่วงหน้าของเรา นี่คือสิ่งที่เรามี:

def bert_pretrain_preprocess(vocab_table, features):
  # Input is a string Tensor of documents, shape [batch, 1].
  text_a = features["text_a"]
  text_b = features["text_b"]

  # Tokenize segments to shape [num_sentences, (num_words)] each.
  tokenizer = text.BertTokenizer(
      vocab_table,
      token_out_type=tf.int64)
  segments = [tokenizer.tokenize(text).merge_dims(
      1, -1) for text in (text_a, text_b)]

  # Truncate inputs to a maximum length.
  trimmer = text.RoundRobinTrimmer(max_seq_length=6)
  trimmed_segments = trimmer.trim(segments)

  # Combine segments, get segment ids and add special tokens.
  segments_combined, segment_ids = text.combine_segments(
      trimmed_segments,
      start_of_sequence_id=_START_TOKEN,
      end_of_segment_id=_END_TOKEN)

  # Apply dynamic masking task.
  masked_input_ids, masked_lm_positions, masked_lm_ids = (
      text.mask_language_model(
        segments_combined,
        random_selector,
        mask_values_chooser,
      )
  )

  # Prepare and pad combined segment inputs
  input_word_ids, input_mask = text.pad_model_inputs(
    masked_input_ids, max_seq_length=_MAX_SEQ_LEN)
  input_type_ids, _ = text.pad_model_inputs(
    masked_input_ids, max_seq_length=_MAX_SEQ_LEN)

  # Prepare and pad masking task inputs
  masked_lm_positions, masked_lm_weights = text.pad_model_inputs(
    masked_input_ids, max_seq_length=_MAX_PREDICTIONS_PER_BATCH)
  masked_lm_ids, _ = text.pad_model_inputs(
    masked_lm_ids, max_seq_length=_MAX_PREDICTIONS_PER_BATCH)

  model_inputs = {
      "input_word_ids": input_word_ids,
      "input_mask": input_mask,
      "input_type_ids": input_type_ids,
      "masked_lm_ids": masked_lm_ids,
      "masked_lm_positions": masked_lm_positions,
      "masked_lm_weights": masked_lm_weights,
  }
  return model_inputs

ก่อนหน้านี้เราสร้าง tf.data.Dataset และตอนนี้เราสามารถใช้ประกอบ preprocessing ฟังก์ชั่นของเรา bert_pretrain_preprocess() ใน Dataset.map() สิ่งนี้ช่วยให้เราสร้างไปป์ไลน์อินพุตเพื่อแปลงข้อมูลสตริงดิบของเราเป็นอินพุตจำนวนเต็มและป้อนลงในโมเดลของเราโดยตรง

dataset = tf.data.Dataset.from_tensors(examples)
dataset = dataset.map(functools.partial(
    bert_pretrain_preprocess, lookup_table))

next(iter(dataset))
{'input_word_ids': <tf.Tensor: shape=(2, 8), dtype=int64, numpy=
 array([[ 3, 22,  9,  1,  4, 16,  5, 19],
        [ 3, 18,  1, 15,  4,  1, 28, 30]])>,
 'input_mask': <tf.Tensor: shape=(2, 8), dtype=int64, numpy=
 array([[1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1]])>,
 'input_type_ids': <tf.Tensor: shape=(2, 8), dtype=int64, numpy=
 array([[ 3, 22,  9,  1,  4, 16,  5, 19],
        [ 3, 18,  1, 15,  4,  1, 28, 30]])>,
 'masked_lm_ids': <tf.Tensor: shape=(2, 5), dtype=int64, numpy=
 array([[24, 19,  0,  0,  0],
        [12, 21,  0,  0,  0]])>,
 'masked_lm_positions': <tf.Tensor: shape=(2, 5), dtype=int64, numpy=
 array([[ 3, 22,  9,  1,  4],
        [ 3, 18,  1, 15,  4]])>,
 'masked_lm_weights': <tf.Tensor: shape=(2, 5), dtype=int64, numpy=
 array([[1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1]])>}
  • ข้อความประเภทกับ BERT - กวดวิชาเกี่ยวกับวิธีการใช้รูปแบบการ BERT pretrained กับข้อความประเภท นี่เป็นการติดตามที่ดีเมื่อคุณคุ้นเคยกับวิธีประมวลผลอินพุตที่ใช้โดยโมเดล BERT ล่วงหน้าแล้ว

  • tokenizing ลุยกับข้อความ - การสอนรายละเอียดแตกต่างกันของ tokenizers ที่มีอยู่ใน TF.Text

  • การจัดการข้อความที่มี RaggedTensor - คู่มือรายละเอียดเกี่ยวกับวิธีการสร้างใช้และจัดการ RaggedTensor s