توکن سازهای زیر کلمه

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

این آموزش نشان می دهد که چگونه برای تولید یک فرهنگ لغت 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 .

در مورد جملات مثال بالا به چند نکته توجه کنید:

  • آنها حروف کوچک هستند.
  • در اطراف علائم نگارشی فضاهایی وجود دارد.
  • مشخص نیست که از نرمال سازی یونیکد استفاده می شود یا نه.
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 تابع واژگان تولید کند.

آرگومان های زیادی وجود دارد که می توانید برای تنظیم رفتار آن تنظیم کنید. برای این آموزش، بیشتر از پیش فرض ها استفاده می کنید. اگر شما می خواهید برای کسب اطلاعات بیشتر در مورد گزینه، برای اولین بار در مورد خواندن الگوریتم ، و سپس نگاهی به کد .

این حدود 2 دقیقه طول می کشد.

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 به طوری که آنها را می توان با آموزش های دیگر وارد شده است.

توکن سازی سفارشی

آموزش پایین دست هر دو انتظار متن token ها که شامل [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 از پایین به بالا است، بر اساس رمزگذاری بایت جفت . مانند 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 .

در نهایت، یا یک نشانه فرعی در دایره لغات خود پیدا می کنیم، یا به یک نشانه فرعی منفرد می رسیم. (به طور کلی، ما فرض کنیم که هر شخصیت در فرهنگ لغت ما است، اگر چه ممکن است این مورد برای شخصیت های نادر یونیکد نیست. اگر ما یک شخصیت نادر یونیکد که در واژگان روبرو می شوند ما به سادگی بر روی نقشه کل کلمه به <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

اگر شما نیاز به دسترسی به، یا کنترل بیشتری روی واژگان ارزش آن را اشاره کرد که شما می توانید در جدول 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)