رموز الكلمات الفرعية

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

يوضح هذا البرنامج التعليمي كيفية إنشاء المفردات subword من مجموعة البيانات، واستخدامها لبناء text.BertTokenizer من المفردات.

الميزة الرئيسية لمميزات الكلمة الفرعية هي أنه يقحم بين الترميز المستند إلى الكلمات والمستند إلى الأحرف. تحصل الكلمات الشائعة على فتحة في المفردات ، ولكن يمكن أن يتراجع الرمز المميز إلى قطع الكلمات والشخصيات الفردية لكلمات غير معروفة.

ملخص

و tensorflow_text تتضمن حزمة تطبيقات TensorFlow العديد من tokenizers المشترك. يتضمن هذا ثلاثة رموز مميزة بنمط الكلمات الفرعية:

  • text.BertTokenizer - و BertTokenizer الفئة هي واجهة مستوى أعلى. ويشمل خوارزمية تقسيم رمزية بيرت وعلى WordPieceTokenizer . فإنه يأخذ الجمل كمدخل وإرجاع معرفات رمزية.
  • text.WordpieceTokenizer - و WordPieceTokenizer الفئة هي واجهة مستوى أقل. وتنفذ فقط خوارزمية WordPiece . يجب توحيد النص وتقسيمه إلى كلمات قبل تسميته. فإنه يأخذ الكلمات كمدخل وإرجاع معرفات رمزية.
  • text.SentencepieceTokenizer - و SentencepieceTokenizer يتطلب الإعداد أكثر تعقيدا. يتطلب مُهيئته نموذج جملة مُدرَّب مسبقًا. رؤية مستودع جوجل / sentencepiece للحصول على تعليمات حول كيفية بناء واحد من هذه النماذج. يمكن أن تقبل الأحكام كمدخل عندما tokenizing.

يقوم هذا البرنامج التعليمي ببناء مفردات Wordpiece بطريقة من أعلى إلى أسفل ، بدءًا من الكلمات الموجودة. لا تعمل هذه العملية مع اليابانية أو الصينية أو الكورية لأن هذه اللغات لا تحتوي على وحدات واضحة متعددة الأحرف. لtokenize اللغات التالية conside باستخدام text.SentencepieceTokenizer ، text.UnicodeCharTokenizer أو هذا النهج .

يثبت

pip install -q -U tensorflow-text
pip install -q tensorflow_datasets
import collections
import os
import pathlib
import re
import string
import sys
import tempfile
import time

import numpy as np
import matplotlib.pyplot as plt

import tensorflow_datasets as tfds
import tensorflow_text as text
import tensorflow as tf
tf.get_logger().setLevel('ERROR')
pwd = pathlib.Path.cwd()

قم بتنزيل مجموعة البيانات

جلب ترجمة بيانات البرتغالية / الانجليزية من tfds :

examples, metadata = tfds.load('ted_hrlr_translate/pt_to_en', with_info=True,
                               as_supervised=True)
train_examples, val_examples = examples['train'], examples['validation']

تنتج مجموعة البيانات هذه أزواج جمل برتغالية / إنجليزية:

for pt, en in train_examples.take(1):
  print("Portuguese: ", pt.numpy().decode('utf-8'))
  print("English:   ", en.numpy().decode('utf-8'))
Portuguese:  e quando melhoramos a procura , tiramos a única vantagem da impressão , que é a serendipidade .
English:    and when you improve searchability , you actually take away the one advantage of print , which is serendipity .

لاحظ بعض الأشياء حول أمثلة الجمل أعلاه:

  • إنها صغيرة.
  • توجد مسافات حول علامات الترقيم.
  • ليس من الواضح ما إذا كان يتم استخدام تطبيع Unicode أم لا.
train_en = train_examples.map(lambda pt, en: en)
train_pt = train_examples.map(lambda pt, en: pt)

قم بتوليد المفردات

يولد هذا القسم مفردات لفظية من مجموعة بيانات. إذا كان لديك بالفعل ملف المفردات ونريد فقط أن نرى كيف لبناء text.BertTokenizer أو text.Wordpiece tokenizer معها ثم يمكنك تخطي إلى الأمام إلى أن tokenizer بناء القسم.

يتم تضمين رمز الجيل المفردات في tensorflow_text حزمة نقطة. لا يتم استيراده افتراضيًا ، فأنت بحاجة إلى استيراده يدويًا:

from tensorflow_text.tools.wordpiece_vocab import bert_vocab_from_dataset as bert_vocab

و bert_vocab.bert_vocab_from_dataset وظيفة توليد المفردات.

هناك العديد من الحجج التي يمكنك تعيينها لضبط سلوكها. في هذا البرنامج التعليمي ، ستستخدم الإعدادات الافتراضية في الغالب. إذا كنت ترغب في معرفة المزيد حول خيارات، وقراءة لأول مرة عن الخوارزمية ، ومن ثم إلقاء نظرة على رمز .

يستغرق هذا حوالي دقيقتين.

bert_tokenizer_params=dict(lower_case=True)
reserved_tokens=["[PAD]", "[UNK]", "[START]", "[END]"]

bert_vocab_args = dict(
    # The target vocabulary size
    vocab_size = 8000,
    # Reserved tokens that must be included in the vocabulary
    reserved_tokens=reserved_tokens,
    # Arguments for `text.BertTokenizer`
    bert_tokenizer_params=bert_tokenizer_params,
    # Arguments for `wordpiece_vocab.wordpiece_tokenizer_learner_lib.learn`
    learn_params={},
)
%%time
pt_vocab = bert_vocab.bert_vocab_from_dataset(
    train_pt.batch(1000).prefetch(2),
    **bert_vocab_args
)
CPU times: user 1min 30s, sys: 2.21 s, total: 1min 32s
Wall time: 1min 28s

فيما يلي بعض الشرائح من المفردات الناتجة.

print(pt_vocab[:10])
print(pt_vocab[100:110])
print(pt_vocab[1000:1010])
print(pt_vocab[-10:])
['[PAD]', '[UNK]', '[START]', '[END]', '!', '#', '$', '%', '&', "'"]
['no', 'por', 'mais', 'na', 'eu', 'esta', 'muito', 'isso', 'isto', 'sao']
['90', 'desse', 'efeito', 'malaria', 'normalmente', 'palestra', 'recentemente', '##nca', 'bons', 'chave']
['##–', '##—', '##‘', '##’', '##“', '##”', '##⁄', '##€', '##♪', '##♫']

اكتب ملف مفردات:

def write_vocab_file(filepath, vocab):
  with open(filepath, 'w') as f:
    for token in vocab:
      print(token, file=f)
write_vocab_file('pt_vocab.txt', pt_vocab)

استخدم هذه الوظيفة لتوليد مفردات من البيانات الإنجليزية:

%%time
en_vocab = bert_vocab.bert_vocab_from_dataset(
    train_en.batch(1000).prefetch(2),
    **bert_vocab_args
)
CPU times: user 1min 3s, sys: 2.21 s, total: 1min 6s
Wall time: 1min 2s
print(en_vocab[:10])
print(en_vocab[100:110])
print(en_vocab[1000:1010])
print(en_vocab[-10:])
['[PAD]', '[UNK]', '[START]', '[END]', '!', '#', '$', '%', '&', "'"]
['as', 'all', 'at', 'one', 'people', 're', 'like', 'if', 'our', 'from']
['choose', 'consider', 'extraordinary', 'focus', 'generation', 'killed', 'patterns', 'putting', 'scientific', 'wait']
['##_', '##`', '##ย', '##ร', '##อ', '##–', '##—', '##’', '##♪', '##♫']

فيما يلي ملفا المفردات:

write_vocab_file('en_vocab.txt', en_vocab)
ls *.txt
en_vocab.txt  pt_vocab.txt

بناء الرمز المميز

و text.BertTokenizer يمكن تهيئة عن طريق تمرير مسار الملف المفردات كما الوسيطة الأولى (انظر القسم الخاص tf.lookup عن خيارات أخرى):

pt_tokenizer = text.BertTokenizer('pt_vocab.txt', **bert_tokenizer_params)
en_tokenizer = text.BertTokenizer('en_vocab.txt', **bert_tokenizer_params)

الآن يمكنك استخدامه لتشفير بعض النصوص. خذ مجموعة من 3 أمثلة من البيانات الإنجليزية:

for pt_examples, en_examples in train_examples.batch(3).take(1):
  for ex in en_examples:
    print(ex.numpy())
b'and when you improve searchability , you actually take away the one advantage of print , which is serendipity .'
b'but what if it were active ?'
b"but they did n't test for curiosity ."

تشغيله من خلال BertTokenizer.tokenize الأسلوب. في البداية، وهذا يعود ل tf.RaggedTensor بالفؤوس (batch, word, word-piece) :

# Tokenize the examples -> (batch, word, word-piece)
token_batch = en_tokenizer.tokenize(en_examples)
# Merge the word and word-piece axes -> (batch, tokens)
token_batch = token_batch.merge_dims(-2,-1)

for ex in token_batch.to_list():
  print(ex)
[72, 117, 79, 1259, 1491, 2362, 13, 79, 150, 184, 311, 71, 103, 2308, 74, 2679, 13, 148, 80, 55, 4840, 1434, 2423, 540, 15]
[87, 90, 107, 76, 129, 1852, 30]
[87, 83, 149, 50, 9, 56, 664, 85, 2512, 15]

إذا قمت باستبدال معرفات رمزية مع التمثيل نصهم (باستخدام tf.gather ) يمكنك أن ترى أنه في المثال الأول عبارة "searchability" و "serendipity" تم تتحلل إلى "search ##ability" و "s ##ere ##nd ##ip ##ity" :

# Lookup each token id in the vocabulary.
txt_tokens = tf.gather(en_vocab, token_batch)
# Join with spaces.
tf.strings.reduce_join(txt_tokens, separator=' ', axis=-1)
<tf.Tensor: shape=(3,), dtype=string, numpy=
array([b'and when you improve search ##ability , you actually take away the one advantage of print , which is s ##ere ##nd ##ip ##ity .',
       b'but what if it were active ?',
       b"but they did n ' t test for curiosity ."], dtype=object)>

لإعادة تجميع الكلمات من الرموز المستخرجة، استخدم BertTokenizer.detokenize الأسلوب:

words = en_tokenizer.detokenize(token_batch)
tf.strings.reduce_join(words, separator=' ', axis=-1)
<tf.Tensor: shape=(3,), dtype=string, numpy=
array([b'and when you improve searchability , you actually take away the one advantage of print , which is serendipity .',
       b'but what if it were active ?',
       b"but they did n ' t test for curiosity ."], dtype=object)>

التخصيص والتصدير

هذا البرنامج التعليمي يبني tokenizer النص وdetokenizer المستخدمة من قبل محول البرنامج التعليمي. ويضيف هذا القسم طرق وخطوات المعالجة لتبسيط هذا البرنامج التعليمي، وصادرات tokenizers باستخدام tf.saved_model بحيث يمكن استيرادها من قبل البرامج التعليمية الأخرى.

الترميز المخصص

الدروس المصب على حد سواء تتوقع النص برموز لتشمل [START] و [END] الرموز.

و reserved_tokens حجز مساحة في بداية المفردات، لذلك [START] و [END] له نفس الأرقام القياسية لكل من اللغات:

START = tf.argmax(tf.constant(reserved_tokens) == "[START]")
END = tf.argmax(tf.constant(reserved_tokens) == "[END]")

def add_start_end(ragged):
  count = ragged.bounding_shape()[0]
  starts = tf.fill([count,1], START)
  ends = tf.fill([count,1], END)
  return tf.concat([starts, ragged, ends], axis=1)
words = en_tokenizer.detokenize(add_start_end(token_batch))
tf.strings.reduce_join(words, separator=' ', axis=-1)
<tf.Tensor: shape=(3,), dtype=string, numpy=
array([b'[START] and when you improve searchability , you actually take away the one advantage of print , which is serendipity . [END]',
       b'[START] but what if it were active ? [END]',
       b"[START] but they did n ' t test for curiosity . [END]"],
      dtype=object)>

تفريغ مخصص

قبل تصدير الرموز المميزة ، هناك بعض الأشياء التي يمكنك تنظيفها في البرامج التعليمية النهائية:

  1. انهم يريدون لتوليد إخراج النص نظيفة، لذلك إسقاط الرموز محفوظة مثل [START] ، [END] و [PAD] .
  2. انهم المهتمة في سلاسل كاملة، لذلك تطبيق سلسلة الانضمام على طول words محور النتيجة.
def cleanup_text(reserved_tokens, token_txt):
  # Drop the reserved tokens, except for "[UNK]".
  bad_tokens = [re.escape(tok) for tok in reserved_tokens if tok != "[UNK]"]
  bad_token_re = "|".join(bad_tokens)

  bad_cells = tf.strings.regex_full_match(token_txt, bad_token_re)
  result = tf.ragged.boolean_mask(token_txt, ~bad_cells)

  # Join them into strings.
  result = tf.strings.reduce_join(result, separator=' ', axis=-1)

  return result
en_examples.numpy()
array([b'and when you improve searchability , you actually take away the one advantage of print , which is serendipity .',
       b'but what if it were active ?',
       b"but they did n't test for curiosity ."], dtype=object)
token_batch = en_tokenizer.tokenize(en_examples).merge_dims(-2,-1)
words = en_tokenizer.detokenize(token_batch)
words
<tf.RaggedTensor [[b'and', b'when', b'you', b'improve', b'searchability', b',', b'you', b'actually', b'take', b'away', b'the', b'one', b'advantage', b'of', b'print', b',', b'which', b'is', b'serendipity', b'.'], [b'but', b'what', b'if', b'it', b'were', b'active', b'?'], [b'but', b'they', b'did', b'n', b"'", b't', b'test', b'for', b'curiosity', b'.']]>
cleanup_text(reserved_tokens, words).numpy()
array([b'and when you improve searchability , you actually take away the one advantage of print , which is serendipity .',
       b'but what if it were active ?',
       b"but they did n ' t test for curiosity ."], dtype=object)

يصدر

كتلة التعليمات البرمجية التالية يبني CustomTokenizer فئة لاحتواء text.BertTokenizer الحالات، منطق العرف، و @tf.function مغلفة المطلوبة للتصدير.

class CustomTokenizer(tf.Module):
  def __init__(self, reserved_tokens, vocab_path):
    self.tokenizer = text.BertTokenizer(vocab_path, lower_case=True)
    self._reserved_tokens = reserved_tokens
    self._vocab_path = tf.saved_model.Asset(vocab_path)

    vocab = pathlib.Path(vocab_path).read_text().splitlines()
    self.vocab = tf.Variable(vocab)

    ## Create the signatures for export:   

    # Include a tokenize signature for a batch of strings. 
    self.tokenize.get_concrete_function(
        tf.TensorSpec(shape=[None], dtype=tf.string))

    # Include `detokenize` and `lookup` signatures for:
    #   * `Tensors` with shapes [tokens] and [batch, tokens]
    #   * `RaggedTensors` with shape [batch, tokens]
    self.detokenize.get_concrete_function(
        tf.TensorSpec(shape=[None, None], dtype=tf.int64))
    self.detokenize.get_concrete_function(
          tf.RaggedTensorSpec(shape=[None, None], dtype=tf.int64))

    self.lookup.get_concrete_function(
        tf.TensorSpec(shape=[None, None], dtype=tf.int64))
    self.lookup.get_concrete_function(
          tf.RaggedTensorSpec(shape=[None, None], dtype=tf.int64))

    # These `get_*` methods take no arguments
    self.get_vocab_size.get_concrete_function()
    self.get_vocab_path.get_concrete_function()
    self.get_reserved_tokens.get_concrete_function()

  @tf.function
  def tokenize(self, strings):
    enc = self.tokenizer.tokenize(strings)
    # Merge the `word` and `word-piece` axes.
    enc = enc.merge_dims(-2,-1)
    enc = add_start_end(enc)
    return enc

  @tf.function
  def detokenize(self, tokenized):
    words = self.tokenizer.detokenize(tokenized)
    return cleanup_text(self._reserved_tokens, words)

  @tf.function
  def lookup(self, token_ids):
    return tf.gather(self.vocab, token_ids)

  @tf.function
  def get_vocab_size(self):
    return tf.shape(self.vocab)[0]

  @tf.function
  def get_vocab_path(self):
    return self._vocab_path

  @tf.function
  def get_reserved_tokens(self):
    return tf.constant(self._reserved_tokens)

بناء CustomTokenizer لكل لغة:

tokenizers = tf.Module()
tokenizers.pt = CustomTokenizer(reserved_tokens, 'pt_vocab.txt')
tokenizers.en = CustomTokenizer(reserved_tokens, 'en_vocab.txt')

تصدير tokenizers باعتباره saved_model :

model_name = 'ted_hrlr_translate_pt_en_converter'
tf.saved_model.save(tokenizers, model_name)
2021-11-02 15:20:31.762976: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.

تحميل saved_model واختبار طرق:

reloaded_tokenizers = tf.saved_model.load(model_name)
reloaded_tokenizers.en.get_vocab_size().numpy()
7010
tokens = reloaded_tokenizers.en.tokenize(['Hello TensorFlow!'])
tokens.numpy()
array([[   2, 4006, 2358,  687, 1192, 2365,    4,    3]])
text_tokens = reloaded_tokenizers.en.lookup(tokens)
text_tokens
<tf.RaggedTensor [[b'[START]', b'hello', b'tens', b'##or', b'##f', b'##low', b'!', b'[END]']]>
round_trip = reloaded_tokenizers.en.detokenize(tokens)

print(round_trip.numpy()[0].decode('utf-8'))
hello tensorflow !

أرشفتها ل دروس الترجمة :

zip -r {model_name}.zip {model_name}
adding: ted_hrlr_translate_pt_en_converter/ (stored 0%)
  adding: ted_hrlr_translate_pt_en_converter/saved_model.pb (deflated 91%)
  adding: ted_hrlr_translate_pt_en_converter/variables/ (stored 0%)
  adding: ted_hrlr_translate_pt_en_converter/variables/variables.data-00000-of-00001 (deflated 51%)
  adding: ted_hrlr_translate_pt_en_converter/variables/variables.index (deflated 33%)
  adding: ted_hrlr_translate_pt_en_converter/assets/ (stored 0%)
  adding: ted_hrlr_translate_pt_en_converter/assets/pt_vocab.txt (deflated 57%)
  adding: ted_hrlr_translate_pt_en_converter/assets/en_vocab.txt (deflated 54%)
du -h *.zip
184K    ted_hrlr_translate_pt_en_converter.zip

اختياري: الخوارزمية

تجدر الإشارة هنا إلى وجود نسختين من خوارزمية WordPiece: من أسفل إلى أعلى ومن أعلى إلى أسفل. في كلتا الحالتين ، يكون الهدف هو نفسه: "بالنظر إلى مجموعة التدريب وعدد من الرموز المطلوبة D ، فإن مشكلة التحسين هي اختيار D wordpiece بحيث تكون المجموعة الناتجة في حدها الأدنى في عدد قطع الكلمات عند تقسيمها وفقًا لنموذج قطع الكلمات المختار. "

الأصلي خوارزمية WordPiece من أسفل إلى أعلى ، ويستند على ترميز بايت الزوج . مثل BPE ، يبدأ بالحروف الأبجدية ، ويجمع بشكل متكرر الأحرف الكبيرة الشائعة لتشكيل قطع الكلمات والكلمات.

مولد المفردات TensorFlow نص في أعقاب تنفيذ أعلى إلى أسفل من بيرت . البدء بالكلمات وتقسيمها إلى مكونات أصغر حتى تصل إلى حد التردد ، أو لا يمكن تقسيمها أكثر. يصف القسم التالي هذا بالتفصيل. بالنسبة لليابانيين والصينية والكورية ، لا يعمل هذا النهج من أعلى إلى أسفل نظرًا لعدم وجود وحدات كلمات صريحة لتبدأ بها. بالنسبة لأولئك كنت في حاجة الى نهج مختلف .

اختيار المفردات

يأخذ من أعلى إلى أسفل WordPiece الجيل الخوارزمية في مجموعة من (كلمة، العد) أزواج وعتبة T ، وعائدات المفردات V .

الخوارزمية تكرارية. يتم تشغيله ل k التكرارات، حيث عادة k = 4 ، ولكن فقط الأولين هي حقا مهمة. الثالث والرابع (وما بعده) متطابقان تمامًا مع الثاني. علما بأن كل خطوة من خطوات البحث الثنائي تشغيل الخوارزمية من الصفر ل k التكرارات.

التكرارات الموضحة أدناه:

التكرار الأول

  1. أعاد على كل كلمة وزوج والعد في المدخلات، ويرمز لها (w, c) .
  2. كل كلمة w ، تولد كل فرعية، كما تدل s . على سبيل المثال، لكلمة human ، فإننا توليد {h, hu, hum, huma, human, ##u, ##um, ##uma, ##uman, ##m, ##ma, ##man, #a, ##an, ##n} .
  3. الحفاظ على خريطة التجزئة فرعية إلى العد، وزيادة عدد كل s من قبل c . على سبيل المثال، إذا كان لدينا (human, 113) و (humas, 3) في مساهمتنا، وعدد من s = huma سوف يكون 113+3=116 .
  4. وعندما ننتهي من جمع تهم كل فرعية، أعاد على (s, c) أزواج بدءا من أطول s أولا.
  5. احتفظ بأي s التي لديها c > T . على سبيل المثال، إذا T = 100 ولدينا (pers, 231); (dogs, 259); (##rint; 76) ، ثم نحن من شأنه أن يبقي pers و dogs .
  6. عندما يكون s يتم الاحتفاظ، طرح قبالة به عدد من كل البادئات لها. وهذا هو السبب لفرز كل من s بواسطة طول في الخطوة 4. هذا هو جزء هام من الخوارزمية، لأن خلاف ذلك الكلمات التي تحسب مزدوجة. على سبيل المثال، دعونا تقول بأننا قد أبقى human ونصل الى (huma, 116) . ونحن نعلم أن 113 من هؤلاء 116 جاء من human ، و 3 جاء من humas . ومع ذلك، الآن بعد أن human هو في قاموسنا، ونحن نعلم نحن لن شريحة human إلى huma ##n . هكذا مرة واحدة human ظلت، ثم huma له سوى عد الفعال لل 3 .

وهذه الخوارزمية توليد مجموعة من كلمة قطع s (وكثير منها ستكون الكلمة بالكامل w )، والتي يمكن أن نستخدمها لدينا المفردات WordPiece.

ومع ذلك ، هناك مشكلة: هذه الخوارزمية سوف تفرط بشدة في إنشاء أجزاء من الكلمات. والسبب هو أننا نطرح فقط عدد الرموز المميزة للبادئة. لذلك، إذا علينا أن نحافظ على كلمة human ، فإننا سوف اطرح قبالة العد ل h, hu, hu, huma ، ولكن ليس ل ##u, ##um, ##uma, ##uman وهلم جرا. ولذا فإننا قد تولد كل من human و ##uman ككلمة قطعة، على الرغم من أن ##uman لن يتم تطبيقها.

فلماذا لا يطرح من التهم لكل فرعية، وليس فقط كل بادئة؟ لأنه قد ينتهي بنا الأمر بطرح الأعداد عدة مرات. دعونا يقول الله بأننا معالجة s بطول 5 وعلينا أن نحافظ على حد سواء (##denia, 129) و (##eniab, 137) ، حيث 65 من تلك التهم جاءت من الكلمة undeniable . إذا طرحنا الخروج من كل فرعية، فإننا طرح 65 من سلسلة فرعية ##enia مرتين، على الرغم من أننا يجب طرح مرة واحدة فقط. ومع ذلك ، إذا طرحنا فقط من البادئات ، فسيتم طرحها مرة واحدة بشكل صحيح.

التكرار الثاني (والثالث ...)

لحل مشكلة التوليد المذكورة أعلاه ، نقوم بإجراء تكرارات متعددة للخوارزمية.

التكرار اللاحقة متطابقة مع الأولى، مع تمييز واحد مهم: في الخطوة 2، بدلا من النظر في كل فرعية، ونحن نطبق خوارزمية WordPiece tokenization باستخدام مفردات من التكرار السابق، والنظر فقط فرعية التي تبدأ في نقطة الانقسام.

على سبيل المثال، لنفرض أننا تنفيذ الخطوة 2 من الخوارزمية واجهت كلمة undeniable . في التكرار الأول، فإننا نعتبر كل فرعية، على سبيل المثال، {u, un, und, ..., undeniable, ##n, ##nd, ..., ##ndeniable, ...} .

الآن ، بالنسبة للتكرار الثاني ، سننظر فقط في مجموعة فرعية منها. لنفترض أنه بعد التكرار الأول ، فإن أجزاء الكلمات ذات الصلة هي:

un, ##deni, ##able, ##ndeni, ##iable

وWordPiece خوارزمية إرادة شريحة ذلك في un ##deni ##able (راجع المقطع تطبيق WordPiece لمزيد من المعلومات). في هذه الحالة، وسوف ننظر فقط فرعية التي تبدأ عند نقطة تجزئة. ونحن لا تزال تنظر كل نهاية الموقف ممكن. حتى خلال التكرار الثاني، ومجموعة من s ل undeniable هو:

{u, un, und, unden, undeni, undenia, undeniab, undeniabl, undeniable, ##d, ##de, ##den, ##deni, ##denia, ##deniab, ##deniabl , ##deniable, ##a, ##ab, ##abl, ##able}

الخوارزمية متطابقة. في هذا المثال، في التكرار الأول، الخوارزمية تنتج suprious الرموز ##ndeni و ##iable . الآن ، لم يتم النظر في هذه الرموز المميزة أبدًا ، لذلك لن يتم إنشاؤها بواسطة التكرار الثاني. نقوم بإجراء العديد من التكرارات فقط للتأكد من تقارب النتائج (على الرغم من عدم وجود ضمان تقارب حرفي).

تطبيق WordPiece

بمجرد إنشاء مفردات WordPiece ، نحتاج إلى أن نكون قادرين على تطبيقها على البيانات الجديدة. الخوارزمية هي تطبيق جشع بسيط يطابق الأطول أولاً.

على سبيل المثال، والنظر في تقسيم كلمة undeniable .

علينا أولا البحث undeniable في القاموس WordPiece لدينا، وإذا كان في الوقت الحاضر، نحن القيام به. إن لم يكن، ونحن إنقاص نقطة النهاية التي كتبها حرف واحد، وتكرار، على سبيل المثال، undeniabl .

في النهاية ، سنجد إما ترجمة فرعية في مفرداتنا ، أو ننتقل إلى حرف واحد مترجم. (بشكل عام، فإننا نفترض أن كل حرف في قاموسنا، على الرغم من أن هذا قد لا يكون الحال بالنسبة للأحرف Unicode نادرة. وإذا واجهتنا حرف Unicode النادر أن ليس في المفردات نحن ببساطة الخريطة بأكملها كلمة ل <unk> ).

في هذه الحالة، نجد un في قاموسنا. هذه هي أول قطعة كلمة لدينا. ثم نقفز إلى نهاية un وتكرار المعالجة، على سبيل المثال، في محاولة للعثور على ##deniable ، ثم ##deniabl ، وما إلى ذلك ويتكرر هذا حتى قمنا بتقسيم الكلمة بأكملها.

البديهة

بشكل حدسي ، يحاول ترميز WordPiece تحقيق هدفين مختلفين:

  1. Tokenize البيانات في أقل عدد من القطع ممكن. من المهم أن تضع في اعتبارك أن خوارزمية WordPiece لا "تريد" تقسيم الكلمات. خلاف ذلك، فإنه سيكون مجرد تقسيم كل كلمة في شخصياته، على سبيل المثال، human -> {h, ##u, ##m, ##a, #n} . هذا هو الشيء الوحيد المهم أن يجعل مختلفة WordPiece من شق المورفولوجية، والتي سوف تقسيم الصرفية اللغوية حتى عن كلمات شائعة (على سبيل المثال، unwanted -> {un, want, ed} ).

  2. عندما يتعين تقسيم الكلمة إلى أجزاء ، قم بتقسيمها إلى أجزاء تحتوي على أقصى عدد في بيانات التدريب. على سبيل المثال، والسبب كلمة undeniable أن يكون الانقسام إلى {un, ##deni, ##able} بدلا من البدائل مثل {unde, ##niab, ##le} هو أن التهم عن un و ##able في خاصة ستكون عالية جدًا ، نظرًا لأن هذه هي البادئات واللواحق الشائعة. على الرغم من أن عدد ل ##le يجب أن يكون أعلى من ##able ، التهم انخفاض unde و ##niab سيجعل هذا أقل "مرغوب فيه" tokenization إلى الخوارزمية.

اختياري: tf.lookup

إذا كنت بحاجة إلى الوصول إلى، أو المزيد من السيطرة على المفردات ومن الجدير بالذكر أنه يمكنك بناء جدول البحث نفسك وتمرير ذلك إلى BertTokenizer .

عند تمرير سلسلة، BertTokenizer يفعل ما يلي:

pt_lookup = tf.lookup.StaticVocabularyTable(
    num_oov_buckets=1,
    initializer=tf.lookup.TextFileInitializer(
        filename='pt_vocab.txt',
        key_dtype=tf.string,
        key_index = tf.lookup.TextFileIndex.WHOLE_LINE,
        value_dtype = tf.int64,
        value_index=tf.lookup.TextFileIndex.LINE_NUMBER)) 
pt_tokenizer = text.BertTokenizer(pt_lookup)

الآن لديك وصول مباشر إلى جدول البحث المستخدم في الرمز المميز.

pt_lookup.lookup(tf.constant(['é', 'um', 'uma', 'para', 'não']))
<tf.Tensor: shape=(5,), dtype=int64, numpy=array([7765,   85,   86,   87, 7765])>

أنت لا تحتاج إلى استخدام ملف المفردات، tf.lookup لديها خيارات مهيئ أخرى. إذا كان لديك المفردات في الذاكرة التي يمكن استخدامها lookup.KeyValueTensorInitializer :

pt_lookup = tf.lookup.StaticVocabularyTable(
    num_oov_buckets=1,
    initializer=tf.lookup.KeyValueTensorInitializer(
        keys=pt_vocab,
        values=tf.range(len(pt_vocab), dtype=tf.int64))) 
pt_tokenizer = text.BertTokenizer(pt_lookup)