Tokenizer subkata

Tetap teratur dengan koleksi Simpan dan kategorikan konten berdasarkan preferensi Anda.

Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHub Unduh buku catatan

Tutorial ini menunjukkan bagaimana untuk menghasilkan kosakata subword dari dataset, dan menggunakannya untuk membangun text.BertTokenizer dari kosakata.

Keuntungan utama dari tokenizer subword adalah interpolasi antara tokenisasi berbasis kata dan berbasis karakter. Kata-kata umum mendapatkan slot dalam kosa kata, tetapi tokenizer dapat kembali ke potongan kata dan karakter individu untuk kata-kata yang tidak diketahui.

Ringkasan

The tensorflow_text paket termasuk TensorFlow implementasi dari banyak tokenizers umum. Ini termasuk tiga tokenizer gaya sub-kata:

  • text.BertTokenizer - The BertTokenizer kelas adalah antarmuka tingkat yang lebih tinggi. Ini mencakup algoritma membelah tanda Bert dan sebuah WordPieceTokenizer . Dibutuhkan kalimat sebagai input dan mengembalikan token-ID.
  • text.WordpieceTokenizer - The WordPieceTokenizer kelas adalah antarmuka tingkat yang lebih rendah. Hanya mengimplementasikan algoritma WordPiece . Anda harus membakukan dan membagi teks menjadi kata-kata sebelum memanggilnya. Dibutuhkan kata-kata sebagai masukan dan mengembalikan token-ID.
  • text.SentencepieceTokenizer - The SentencepieceTokenizer membutuhkan setup yang lebih kompleks. Penginisialisasinya memerlukan model kalimat yang telah dilatih sebelumnya. Lihat repositori google / sentencepiece untuk instruksi bagaimana untuk membangun satu dari model ini. Hal ini dapat menerima kalimat sebagai input ketika tokenizing.

Tutorial ini membangun kosakata Wordpiece secara top down, dimulai dari kata-kata yang ada. Proses ini tidak bekerja untuk bahasa Jepang, Cina, atau Korea karena bahasa ini tidak memiliki unit multi-karakter yang jelas. Tokenize bahasa ini conside menggunakan text.SentencepieceTokenizer , text.UnicodeCharTokenizer atau pendekatan ini .

Mempersiapkan

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()

Unduh kumpulan data

Ambil Portugis / Inggris translation dataset dari 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']

Dataset ini menghasilkan pasangan kalimat Portugis/Inggris:

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 .

Perhatikan beberapa hal tentang contoh kalimat di atas:

  • Mereka huruf kecil.
  • Ada spasi di sekitar tanda baca.
  • Tidak jelas apakah normalisasi unicode atau apa yang digunakan.
train_en = train_examples.map(lambda pt, en: en)
train_pt = train_examples.map(lambda pt, en: pt)

Menghasilkan kosa kata

Bagian ini menghasilkan kosakata kata dari kumpulan data. Jika Anda sudah memiliki file kosa kata dan hanya ingin melihat bagaimana membangun sebuah text.BertTokenizer atau text.Wordpiece tokenizer dengan itu maka Anda dapat langsung melompat ke Build tokenizer bagian.

Kode generasi kosakata termasuk dalam tensorflow_text paket pip. Itu tidak diimpor secara default, Anda perlu mengimpornya secara manual:

from tensorflow_text.tools.wordpiece_vocab import bert_vocab_from_dataset as bert_vocab

The bert_vocab.bert_vocab_from_dataset fungsi akan menghasilkan kosakata.

Ada banyak argumen yang dapat Anda atur untuk menyesuaikan perilakunya. Untuk tutorial ini, sebagian besar Anda akan menggunakan default. Jika Anda ingin mempelajari lebih lanjut tentang pilihan, pertama kali membaca tentang algoritma , dan kemudian kita lihat kode .

Ini membutuhkan waktu sekitar 2 menit.

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

Berikut adalah beberapa potongan kosakata yang dihasilkan.

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']
['##–', '##—', '##‘', '##’', '##“', '##”', '##⁄', '##€', '##♪', '##♫']

Tulis file kosakata:

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)

Gunakan fungsi itu untuk menghasilkan kosakata dari data bahasa Inggris:

%%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']
['##_', '##`', '##ย', '##ร', '##อ', '##–', '##—', '##’', '##♪', '##♫']

Berikut adalah dua file kosakata:

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

Bangun tokenizer

The text.BertTokenizer dapat diinisialisasi dengan melewati jalan kosakata file sebagai argumen pertama (lihat bagian tf.lookup untuk pilihan lain):

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

Sekarang Anda dapat menggunakannya untuk menyandikan beberapa teks. Ambil kumpulan 3 contoh dari data bahasa Inggris:

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 ."

Menjalankannya melalui BertTokenizer.tokenize metode. Awalnya, ini mengembalikan tf.RaggedTensor dengan sumbu (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]

Jika Anda mengganti ID tanda dengan representasi teks mereka (menggunakan tf.gather ) Anda dapat melihat bahwa dalam contoh pertama kata-kata "searchability" dan "serendipity" telah didekomposisi menjadi "search ##ability" dan "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)>

Untuk merakit ulang kata-kata dari token diekstrak, menggunakan BertTokenizer.detokenize metode:

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)>

Kustomisasi dan ekspor

Tutorial ini membangun tokenizer teks dan detokenizer digunakan oleh Transformer tutorial. Bagian ini menambahkan metode dan langkah-langkah pengolahan untuk menyederhanakan tutorial itu, dan ekspor tokenizers menggunakan tf.saved_model sehingga mereka dapat diimpor oleh tutorial lainnya.

Tokenisasi khusus

Tutorial hilir kedua mengharapkan teks tokenized untuk menyertakan [START] dan [END] token.

The reserved_tokens ruang cadangan pada awal kosa kata, sehingga [START] dan [END] memiliki indeks yang sama untuk kedua bahasa:

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)>

Detokenisasi khusus

Sebelum mengekspor tokenizer, ada beberapa hal yang dapat Anda bersihkan untuk tutorial hilir:

  1. Mereka ingin untuk menghasilkan output teks bersih, jadi drop token dilindungi seperti [START] , [END] dan [PAD] .
  2. Mereka tertarik pada string lengkap, sehingga menerapkan string bergabung sepanjang words sumbu dari hasilnya.
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)

Ekspor

Blok kode berikut membangun CustomTokenizer kelas untuk mengandung text.BertTokenizer contoh, logika kustom, dan @tf.function pembungkus yang diperlukan untuk ekspor.

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)

Membangun CustomTokenizer untuk setiap bahasa:

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

Ekspor tokenizers sebagai 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.

Reload saved_model dan menguji metode:

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 !

Arsipkan untuk tutorial terjemahan :

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

Opsional: Algoritme

Perlu dicatat di sini bahwa ada dua versi algoritma WordPiece: Bottom-up dan top-down. Dalam kedua kasus, tujuannya sama: "Diberikan korpus pelatihan dan sejumlah token D yang diinginkan, masalah optimasi adalah memilih D kata-kata sedemikian rupa sehingga korpus yang dihasilkan minimal dalam jumlah kata-kata ketika disegmentasi sesuai dengan model kata-kata yang dipilih. "

Asli algoritma WordPiece bottom-up , didasarkan pada byte-pair encoding . Seperti BPE, Ini dimulai dengan alfabet, dan secara berulang menggabungkan bigram umum untuk membentuk potongan kata dan kata.

Generator kosakata TensorFlow Teks ini mengikuti pelaksanaan top-down dari Bert . Dimulai dengan kata-kata dan memecahnya menjadi komponen yang lebih kecil hingga mencapai ambang frekuensi, atau tidak dapat dipecah lebih lanjut. Bagian selanjutnya menjelaskan hal ini secara rinci. Untuk bahasa Jepang, Cina, dan Korea, pendekatan top-down ini tidak berfungsi karena tidak ada unit kata yang eksplisit untuk memulai. Bagi mereka Anda membutuhkan pendekatan yang berbeda .

Memilih kosakata

The top-down WordPiece algoritma generasi mengambil dalam satu set (kata, count) pasangan dan ambang T , dan kembali kosakata V .

Algoritma ini berulang. Hal ini dijalankan untuk k iterasi, di mana biasanya k = 4 , tetapi hanya dua yang pertama benar-benar penting. Yang ketiga dan keempat (dan seterusnya) sama persis dengan yang kedua. Perhatikan bahwa setiap langkah dari pencarian biner menjalankan algoritma dari awal untuk k iterasi.

Iterasi yang dijelaskan di bawah ini:

Iterasi pertama

  1. Iterate atas setiap kata dan pasangan count pada input, dilambangkan sebagai (w, c) .
  2. Untuk setiap kata w , menghasilkan setiap substring, dilambangkan sebagai s . Misalnya, untuk kata human , kita menghasilkan {h, hu, hum, huma, human, ##u, ##um, ##uma, ##uman, ##m, ##ma, ##man, #a, ##an, ##n} .
  3. Menjaga substring-to-hitungan hash peta, dan kenaikan jumlah setiap s oleh c . Misalnya, jika kita memiliki (human, 113) dan (humas, 3) di masukan kami, hitungan s = huma akan 113+3=116 .
  4. Setelah kami mengumpulkan jumlah setiap substring, iterate atas (s, c) pasangan dimulai dengan terpanjang s pertama.
  5. Menjaga setiap s yang memiliki c > T . Misalnya, jika T = 100 dan kami memiliki (pers, 231); (dogs, 259); (##rint; 76) , maka kita akan tetap pers dan dogs .
  6. Ketika sebuah s disimpan, kurangi off count-nya dari semua prefiks nya. Ini adalah alasan untuk menyortir semua s dengan panjang pada langkah 4. Ini adalah bagian penting dari algoritma, karena jika tidak kata-kata akan ganda dihitung. Sebagai contoh, mari kita mengatakan bahwa kita telah terus human dan kami bisa (huma, 116) . Kita tahu bahwa 113 dari mereka 116 berasal dari human , dan 3 berasal dari humas . Namun, sekarang human adalah dalam kosa kata kita, kita tahu bahwa kita tidak akan pernah segmen human ke huma ##n . Jadi sekali human telah disimpan, maka huma hanya memiliki hitungan efektif 3 .

Algoritma ini akan menghasilkan satu set potongan kata s (banyak yang akan seluruh kata-kata w ), yang bisa kita gunakan sebagai kosakata WordPiece kami.

Namun, ada masalah: Algoritme ini akan menghasilkan terlalu banyak potongan kata. Alasannya adalah kami hanya mengurangi jumlah token awalan. Oleh karena itu, jika kita terus kata human , kita akan mengurangi off hitungan untuk h, hu, hu, huma , tetapi tidak untuk ##u, ##um, ##uma, ##uman dan sebagainya. Jadi kita mungkin menghasilkan baik human dan ##uman sebagai potongan kata, meskipun ##uman tidak akan pernah diterapkan.

Jadi mengapa tidak kurangi dari jumlah untuk setiap substring, bukan hanya setiap awalan? Karena dengan begitu kita bisa mengurangi hitungan beberapa kali. Mari kita mengatakan bahwa kita pengolahan sedang s panjang 5 dan kami menjaga kedua (##denia, 129) dan (##eniab, 137) , di mana 65 dari orang-orang penting datang dari kata undeniable . Jika kita kurangi off dari setiap substring, kita akan kurangi 65 dari substring ##enia dua kali, meskipun kami hanya harus mengurangi sekali. Namun, jika kita hanya mengurangi awalan, itu hanya akan dikurangi satu kali dengan benar.

Iterasi kedua (dan ketiga ...)

Untuk mengatasi masalah overgenerasi yang disebutkan di atas, kami melakukan beberapa iterasi dari algoritma.

Iterasi berikutnya adalah identik dengan yang pertama, dengan satu perbedaan penting: Pada langkah 2, bukan mempertimbangkan setiap substring, kami menerapkan algoritma WordPiece tokenization menggunakan kosakata dari iterasi sebelumnya, dan hanya mempertimbangkan substring yang dimulai pada titik perpecahan.

Sebagai contoh, mari kita mengatakan bahwa kita sedang melakukan langkah 2 dari algoritma dan menemukan kata undeniable . Pada iterasi pertama, kami akan mempertimbangkan setiap substring, misalnya, {u, un, und, ..., undeniable, ##n, ##nd, ..., ##ndeniable, ...} .

Sekarang, untuk iterasi kedua, kami hanya akan mempertimbangkan subset dari ini. Katakanlah setelah iterasi pertama, potongan kata yang relevan adalah:

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

Algoritma WordPiece akan segmen ini menjadi un ##deni ##able (lihat bagian Menerapkan WordPiece untuk informasi lebih lanjut). Dalam hal ini, kita hanya akan mempertimbangkan substring yang dimulai pada titik segmentasi. Kami masih akan mempertimbangkan setiap posisi akhir mungkin. Jadi selama iterasi kedua, set s untuk undeniable adalah:

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

Algoritme sebaliknya identik. Dalam contoh ini, pada iterasi pertama, algoritma menghasilkan suprious token ##ndeni dan ##iable . Sekarang, token ini tidak pernah dipertimbangkan, sehingga tidak akan dihasilkan oleh iterasi kedua. Kami melakukan beberapa iterasi hanya untuk memastikan hasil konvergen (walaupun tidak ada jaminan konvergensi literal).

Menerapkan WordPiece

Setelah kosakata WordPiece dihasilkan, kita harus dapat menerapkannya ke data baru. Algoritme adalah aplikasi sederhana yang paling lama cocok pertama.

Sebagai contoh, perhatikan segmentasi kata undeniable .

Kami pertama kali lookup undeniable dalam kamus WordPiece kami, dan jika ada itu, kita sudah selesai. Jika tidak, kita pengurangan titik akhir oleh satu karakter, dan ulangi, misalnya, undeniabl .

Akhirnya, kita akan menemukan subtoken dalam kosa kata kita, atau turun ke subtoken karakter tunggal. (Secara umum, kita asumsikan bahwa setiap karakter dalam kosa kata kita, meskipun kekuatan ini tidak menjadi kasus untuk karakter Unicode langka. Jika kita menemukan karakter Unicode langka yang tidak dalam kosa kata kita hanya memetakan seluruh kata untuk <unk> ).

Dalam hal ini, kita menemukan un dalam kosa kata kita. Jadi itu potongan kata pertama kami. Kemudian kita melompat ke akhir un dan ulangi pengolahan, misalnya, mencoba untuk menemukan ##deniable , kemudian ##deniabl , dll ini diulang sampai kita sudah tersegmentasi seluruh kata.

Intuisi

Secara intuitif, tokenisasi WordPiece mencoba memenuhi dua tujuan berbeda:

  1. Tokenize data ke sedikitnya jumlah potongan mungkin. Penting untuk diingat bahwa algoritma WordPiece tidak "ingin" membagi kata. Jika tidak, itu hanya akan membagi setiap kata ke dalam nya karakter, misalnya, human -> {h, ##u, ##m, ##a, #n} . Ini adalah salah satu hal penting yang membuat WordPiece berbeda dari splitter morfologi, yang akan membagi morfem linguistik bahkan untuk kata-kata umum (misalnya, unwanted -> {un, want, ed} ).

  2. Ketika sebuah kata memang harus dipecah menjadi beberapa bagian, pisahkan menjadi beberapa bagian yang memiliki jumlah maksimal dalam data pelatihan. Misalnya, alasan mengapa kata undeniable akan terpecah menjadi {un, ##deni, ##able} daripada alternatif seperti {unde, ##niab, ##le} adalah bahwa jumlah untuk un dan ##able di tertentu akan sangat tinggi, karena ini adalah awalan dan akhiran yang umum. Meskipun hitungan untuk ##le harus lebih tinggi dari ##able , hitungan rendah unde dan ##niab akan membuat ini kurang "diinginkan" tokenization untuk algoritma.

Opsional: tf.lookup

Jika Anda memerlukan akses ke, atau kontrol atas kosakata itu perlu dicatat bahwa Anda dapat membangun tabel pencarian diri sendiri dan mengirimkannya ke BertTokenizer .

Ketika Anda melewati string, BertTokenizer melakukan berikut ini:

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)

Sekarang Anda memiliki akses langsung ke tabel pencarian yang digunakan di tokenizer.

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

Anda tidak perlu menggunakan file kosakata, tf.lookup memiliki pilihan initializer lainnya. Jika Anda memiliki kosa kata dalam memori Anda dapat menggunakan 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)