Xem trên TensorFlow.org | Chạy trong Google Colab | Xem nguồn trên GitHub | Tải xuống sổ ghi chép |
Hướng dẫn này cho thấy làm thế nào để tạo ra một từ vựng subword từ một tập dữ liệu, và sử dụng nó để xây dựng một text.BertTokenizer
từ vựng.
Ưu điểm chính của trình mã hóa từ khóa phụ là nó nội suy giữa mã hóa dựa trên từ và mã hóa dựa trên ký tự. Các từ thông dụng có một vị trí trong từ vựng, nhưng trình mã hóa có thể rơi trở lại các mảnh từ và các ký tự riêng lẻ đối với các từ không xác định.
Tổng quat
Các tensorflow_text
gói bao gồm TensorFlow triển khai của nhiều tokenizers chung. Điều này bao gồm ba loại tokenizers kiểu từ khóa phụ:
-
text.BertTokenizer
- CácBertTokenizer
lớp là một giao diện mức độ cao hơn. Nó bao gồm các thuật toán tách thẻ Bert và mộtWordPieceTokenizer
. Phải mất câu như là đầu vào và trả về token-ID. -
text.WordpieceTokenizer
- CácWordPieceTokenizer
lớp là một giao diện cấp thấp hơn. Nó chỉ thực hiện các thuật toán WordPiece . Bạn phải chuẩn hóa và tách văn bản thành các từ trước khi gọi nó. Phải mất từ như đầu vào và trả về token-ID. -
text.SentencepieceTokenizer
- CácSentencepieceTokenizer
đòi hỏi một thiết lập phức tạp hơn. Bộ khởi tạo của nó yêu cầu một mô hình câu chữ được đào tạo trước. Xem kho google / sentencepiece để được hướng dẫn làm thế nào để xây dựng một trong những mô hình này. Nó có thể chấp nhận câu như là đầu vào khi tokenizing.
Hướng dẫn này xây dựng vốn từ vựng Wordpiece theo cách từ trên xuống, bắt đầu từ các từ hiện có. Quá trình này không hoạt động đối với tiếng Nhật, tiếng Trung hoặc tiếng Hàn vì những ngôn ngữ này không có các đơn vị nhiều ký tự rõ ràng. Tokenize các thứ tiếng conside sử dụng text.SentencepieceTokenizer
, text.UnicodeCharTokenizer
hoặc cách tiếp cận này .
Thành lập
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()
Tải xuống tập dữ liệu
Fetch bản dịch bộ dữ liệu Bồ Đào Nha / Tiếng Anh từ 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']
Tập dữ liệu này tạo ra các cặp câu tiếng Bồ Đào Nha / tiếng Anh:
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 .
Lưu ý một số điều về các câu ví dụ ở trên:
- Chúng là chữ thường.
- Có khoảng trắng xung quanh dấu câu.
- Không rõ liệu chuẩn hóa unicode có đang được sử dụng hay không.
train_en = train_examples.map(lambda pt, en: en)
train_pt = train_examples.map(lambda pt, en: pt)
Tạo từ vựng
Phần này tạo ra một từ vựng ghép từ một tập dữ liệu. Nếu bạn đã có một file từ vựng và chỉ muốn xem làm thế nào để xây dựng một text.BertTokenizer
hoặc text.Wordpiece
tokenizer với nó thì bạn có thể bỏ qua phần đầu đến xây dựng các tokenizer phần.
Mã thế hệ từ vựng được bao gồm trong tensorflow_text
gói pip. Nó không được nhập theo mặc định, bạn cần phải nhập thủ công:
from tensorflow_text.tools.wordpiece_vocab import bert_vocab_from_dataset as bert_vocab
Các bert_vocab.bert_vocab_from_dataset
chức năng sẽ tạo ra các từ vựng.
Có nhiều đối số bạn có thể đặt để điều chỉnh hành vi của nó. Đối với hướng dẫn này, bạn sẽ chủ yếu sử dụng các giá trị mặc định. Nếu bạn muốn tìm hiểu thêm về các tùy chọn, đầu tiên đọc về các thuật toán , và sau đó có một cái nhìn tại các mã .
Quá trình này mất khoảng 2 phút.
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
Dưới đây là một số phần của từ vựng kết quả.
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'] ['##–', '##—', '##‘', '##’', '##“', '##”', '##⁄', '##€', '##♪', '##♫']
Viết tệp từ vựng:
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)
Sử dụng hàm đó để tạo từ vựng từ dữ liệu tiếng Anh:
%%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'] ['##_', '##`', '##ย', '##ร', '##อ', '##–', '##—', '##’', '##♪', '##♫']
Đây là hai tệp từ vựng:
write_vocab_file('en_vocab.txt', en_vocab)
ls *.txt
en_vocab.txt pt_vocab.txt
Xây dựng tokenizer
Các text.BertTokenizer
có thể được khởi tạo bằng cách đi qua con đường tập tin từ vựng của như là đối số đầu tiên (xem phần trên tf.lookup cho các tùy chọn khác):
pt_tokenizer = text.BertTokenizer('pt_vocab.txt', **bert_tokenizer_params)
en_tokenizer = text.BertTokenizer('en_vocab.txt', **bert_tokenizer_params)
Bây giờ bạn có thể sử dụng nó để mã hóa một số văn bản. Lấy một loạt 3 ví dụ từ dữ liệu tiếng Anh:
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 ."
Chạy nó thông qua BertTokenizer.tokenize
phương pháp. Ban đầu, đây trả về một tf.RaggedTensor
với trục (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]
Nếu bạn thay thế các ID mã thông báo với cơ quan đại diện văn bản của họ (sử dụng tf.gather
), bạn có thể thấy rằng trong ví dụ đầu tiên dòng chữ "searchability"
và "serendipity"
đã được phân tách ra thành "search ##ability"
và "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)>
Để tái lập lại những lời từ các thẻ chiết xuất, sử dụng BertTokenizer.detokenize
phương pháp:
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)>
Tùy chỉnh và xuất khẩu
Hướng dẫn này được xây dựng các văn bản và tokenizer detokenizer sử dụng bởi các Transformer hướng dẫn. Phần này cho biết thêm các phương pháp và các bước xử lý để đơn giản hóa hướng dẫn đó, và xuất khẩu tokenizers sử dụng tf.saved_model
để họ có thể được nhập khẩu bởi các hướng dẫn khác.
Mã hóa tùy chỉnh
Các hướng dẫn hạ lưu cả mong đợi văn bản tokenized bao gồm [START]
và [END]
mã thông báo.
Các reserved_tokens
không gian dự trữ ở phần đầu của từ vựng, vì vậy [START]
và [END]
có các chỉ số tương tự cho cả hai ngôn ngữ:
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)>
Tách rời tùy chỉnh
Trước khi xuất tokenizers, có một số thứ bạn có thể dọn dẹp cho các hướng dẫn hạ lưu:
- Họ muốn tạo ra văn bản sạch sẽ, vì vậy thả tokens reserved như
[START]
,[END]
và[PAD]
. - Họ đang quan tâm trong chuỗi hoàn chỉnh, vì vậy áp dụng một chuỗi tham gia dọc theo
words
trục của kết quả.
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)
Xuất khẩu
Khối mã sau xây dựng một CustomTokenizer
lớp để chứa các text.BertTokenizer
trường hợp, logic tùy chỉnh, và @tf.function
giấy gói cần thiết cho xuất khẩu.
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)
Xây dựng một CustomTokenizer
cho mỗi ngôn ngữ:
tokenizers = tf.Module()
tokenizers.pt = CustomTokenizer(reserved_tokens, 'pt_vocab.txt')
tokenizers.en = CustomTokenizer(reserved_tokens, 'en_vocab.txt')
Xuất tokenizers như một 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.
Nạp lại các saved_model
và thử nghiệm các phương pháp:
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 !
Lưu trữ nó cho hướng dẫn dịch :
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
Tùy chọn: Thuật toán
Điều đáng chú ý ở đây là có hai phiên bản của thuật toán WordPiece: Bottom-up và top-down. Trong cả hai trường hợp, mục tiêu đều giống nhau: "Với một kho ngữ liệu đào tạo và một số mã thông báo D mong muốn, bài toán tối ưu hóa là chọn các phôi chữ D sao cho số lượng văn bản thu được là tối thiểu về số lượng mẫu chữ khi được phân đoạn theo mô hình phôi chữ đã chọn. "
Bản gốc thuật toán WordPiece từ dưới lên , dựa trên mã hóa byte cặp . Giống như BPE, Nó bắt đầu với bảng chữ cái và kết hợp lặp đi lặp lại các bigrams thông thường để tạo thành các mảnh từ và từ.
Máy phát điện từ vựng TensorFlow Tiêu đề của sau việc thực hiện từ trên xuống từ Bert . Bắt đầu với các từ và chia nhỏ chúng thành các thành phần nhỏ hơn cho đến khi chúng đạt đến ngưỡng tần suất hoặc không thể chia nhỏ hơn nữa. Phần tiếp theo mô tả chi tiết điều này. Đối với tiếng Nhật, tiếng Trung và tiếng Hàn, cách tiếp cận từ trên xuống này không hoạt động vì không có đơn vị từ rõ ràng nào để bắt đầu. Đối với những bạn cần một cách tiếp cận khác nhau .
Chọn từ vựng
Các từ trên xuống WordPiece thuật toán thế hệ mất trong một bộ (word, count) theo cặp và một ngưỡng T
, và trả về một vốn từ vựng V
.
Thuật toán là lặp đi lặp lại. Nó được điều hành cho k
lặp, nơi thường k = 4
, nhưng chỉ có hai đầu tiên là thực sự quan trọng. Cái thứ ba và thứ tư (và xa hơn nữa) giống hệt cái thứ hai. Lưu ý rằng mỗi bước của việc tìm kiếm nhị phân chạy các thuật toán từ đầu cho k
lặp.
Các bước lặp được mô tả bên dưới:
Lần lặp đầu tiên
- Lặp qua từng lời nói và cặp đếm trong đầu vào, ký hiệu là
(w, c)
. - Đối với mỗi từ
w
, tạo ra mỗi chuỗi, ký hiệu làs
. Ví dụ, cho từhuman
, chúng ta tạo ra{h, hu, hum, huma, human, ##u, ##um, ##uma, ##uman, ##m, ##ma, ##man, #a, ##an, ##n}
. - Duy trì một bản đồ chuỗi-to-count băm, và làm tăng số lần của mỗi
s
bởic
. Ví dụ, nếu chúng ta có(human, 113)
và(humas, 3)
ở đầu vào của chúng tôi, số lượng củas = huma
sẽ113+3=116
. - Một khi chúng ta đã thu thập các tội danh mỗi chuỗi con, lặp qua
(s, c)
cặp bắt đầu với dài nhấts
đầu tiên. - Giữ bất kỳ
s
mà có mộtc > T
. Ví dụ, nếuT = 100
và chúng tôi có(pers, 231); (dogs, 259); (##rint; 76)
, sau đó chúng tôi sẽ tiếp tụcpers
vàdogs
. - Khi một
s
được giữ, trừ tắt tính của nó từ tất cả các tiền tố của nó. Đây là lý do để phân loại tất cả cács
theo chiều dài trong bước 4. Đây là một phần quan trọng của thuật toán, bởi vì nếu không lời sẽ được tính gấp đôi. Ví dụ, chúng ta hãy nói rằng chúng tôi đã giữhuman
và chúng tôi có được(huma, 116)
. Chúng ta biết rằng113
trong những116
đến từhuman
, và3
đến từhumas
. Tuy nhiên, bây giờ màhuman
là trong vốn từ vựng của chúng tôi, chúng tôi biết chúng tôi sẽ không bao giờ phân khúchuman
vàohuma ##n
. Vì vậy, một khihuman
đã được lưu giữ, sau đóhuma
chỉ có một số hiệu quả của3
.
Thuật toán này sẽ tạo ra một tập hợp các chữ mảnh s
(nhiều trong số đó sẽ là toàn bộ từ w
), mà chúng tôi có thể sử dụng như từ vựng WordPiece của chúng tôi.
Tuy nhiên, có một vấn đề: Thuật toán này sẽ tạo ra quá nhiều các mẩu từ. Lý do là chúng tôi chỉ trừ đi số lượng mã thông báo tiền tố. Do đó, nếu chúng tôi tiếp tục từ human
, chúng tôi sẽ trừ ra khỏi đếm cho h, hu, hu, huma
, nhưng không phải cho ##u, ##um, ##uma, ##uman
và vân vân. Vì vậy, chúng ta có thể tạo ra cả human
và ##uman
như mảnh từ, mặc dù ##uman
sẽ không bao giờ được áp dụng.
Vậy tại sao không trừ ra khỏi tính cho mỗi chuỗi con, không chỉ mỗi tiền tố? Bởi vì sau đó chúng ta có thể trừ đi số lượng nhiều lần. Chúng ta hãy nói rằng chúng tôi chế biến đang s
chiều dài 5 và chúng tôi giữ cả hai (##denia, 129)
và (##eniab, 137)
, nơi 65
của những tội đến từ từ undeniable
. Nếu chúng ta trừ khỏi tất cả các chuỗi con, chúng tôi sẽ trừ đi 65
từ chuỗi ##enia
hai lần, mặc dù chúng ta chỉ nên trừ một lần. Tuy nhiên, nếu chúng ta chỉ trừ các tiền tố, thì nó sẽ chỉ bị trừ một lần.
Lần lặp thứ hai (và thứ ba ...)
Để giải quyết vấn đề phát sinh quá mức được đề cập ở trên, chúng tôi thực hiện nhiều lần lặp lại thuật toán.
Lặp tiếp theo là giống hệt nhau để là người đầu tiên, với một khác biệt quan trọng: Trong bước 2, thay vì xem xét tất cả các chuỗi con, chúng tôi áp dụng các thuật toán WordPiece tokenization bằng cách sử dụng từ vựng từ phiên trước đó, và chỉ xem xét chuỗi con mà bắt đầu vào một điểm chia.
Ví dụ, chúng ta hãy nói rằng chúng tôi đang thực hiện bước 2 của thuật toán và bắt gặp từ undeniable
. Trong phiên đầu tiên, chúng tôi sẽ xem xét tất cả các chuỗi con, ví dụ như, {u, un, und, ..., undeniable, ##n, ##nd, ..., ##ndeniable, ...}
.
Bây giờ, đối với lần lặp thứ hai, chúng ta sẽ chỉ xem xét một tập hợp con trong số này. Giả sử rằng sau lần lặp đầu tiên, các từ liên quan là:
un, ##deni, ##able, ##ndeni, ##iable
Thuật toán WordPiece chí phân khúc này vào un ##deni ##able
(xem phần Áp dụng WordPiece để biết thêm thông tin). Trong trường hợp này, chúng ta sẽ chỉ xem xét chuỗi con mà bắt đầu tại một điểm phân khúc. Chúng tôi vẫn sẽ xem xét tất cả các vị trí cuối có thể. Vì vậy, trong lần lặp thứ hai, bộ s
cho undeniable
là:
{u, un, und, unden, undeni, undenia, undeniab, undeniabl, undeniable, ##d, ##de, ##den, ##deni, ##denia, ##deniab, ##deniabl , ##deniable, ##a, ##ab, ##abl, ##able}
Thuật toán giống hệt nhau. Trong ví dụ này, trong phiên đầu tiên, thuật toán tạo ra suprious tokens ##ndeni
và ##iable
. Bây giờ, những mã thông báo này không bao giờ được xem xét, vì vậy chúng sẽ không được tạo ra bởi lần lặp thứ hai. Chúng tôi thực hiện một số lần lặp chỉ để đảm bảo kết quả hội tụ (mặc dù không có đảm bảo hội tụ theo nghĩa đen).
Áp dụng WordPeces
Sau khi từ vựng WordPeces đã được tạo, chúng ta cần có thể áp dụng nó vào dữ liệu mới. Thuật toán là một ứng dụng đầu tiên phù hợp dài nhất tham lam đơn giản.
Ví dụ, hãy xem xét phân đoạn từ undeniable
.
Đầu tiên chúng ta tra cứu undeniable
trong từ điển WordPiece của chúng tôi, và nếu nó hiện tại, chúng tôi đã hoàn tất. Nếu không, chúng ta giảm các điểm cuối của một nhân vật, và lặp lại, ví dụ như, undeniabl
.
Cuối cùng, chúng tôi sẽ tìm thấy một ký tự phụ trong từ vựng của mình hoặc nhận được một ký tự phụ. (Nói chung, chúng tôi giả định rằng tất cả các nhân vật trong vốn từ vựng của chúng tôi, mặc dù sức mạnh đây không phải là trường hợp cho các ký tự Unicode hiếm. Nếu chúng ta gặp phải một ký tự Unicode hiếm hoi mà không có trong từ vựng, chúng tôi chỉ đơn giản là bản đồ toàn bộ từ để <unk>
).
Trong trường hợp này, chúng ta thấy un
trong vốn từ vựng của chúng tôi. Vì vậy, đó là phần từ đầu tiên của chúng tôi. Sau đó, chúng tôi nhảy đến cuối un
và lặp lại quá trình xử lý, ví dụ như, cố gắng tìm ##deniable
, sau đó ##deniabl
, vv Điều này được lặp lại cho đến khi chúng tôi đã phân đoạn toàn bộ từ.
Trực giác
Về mặt trực quan, mã hóa WordP mảnh đang cố gắng đáp ứng hai mục tiêu khác nhau:
Tokenize dữ liệu vào số nhỏ nhất của mảnh càng tốt. Điều quan trọng cần ghi nhớ là thuật toán WordPiece không "muốn" tách các từ. Nếu không, nó sẽ chỉ chia từng chữ vào nó ký tự, ví dụ như,
human -> {h, ##u, ##m, ##a, #n}
. Đây là một điều quan trọng là làm cho WordPiece khác nhau từ splitter hình thái, mà sẽ chia hình vị ngôn ngữ ngay cả đối với những từ thông thường (ví dụ,unwanted -> {un, want, ed}
).Khi một từ thực sự phải chia thành nhiều phần, hãy chia từ đó thành các phần có số lượng tối đa trong dữ liệu đào tạo. Ví dụ, lý do tại sao từ
undeniable
sẽ được chia thành{un, ##deni, ##able}
chứ không phải là lựa chọn thay thế như{unde, ##niab, ##le}
là tính choun
và##able
ở cụ thể sẽ rất cao, vì đây là những tiền tố và hậu tố phổ biến. Mặc dù số lượng cho##le
phải cao hơn##able
, đếm thấpunde
và##niab
sẽ làm cho một ít "mong muốn" tokenization cho thuật toán.
Tùy chọn: tf.lookup
Nếu bạn cần truy cập vào, hoặc kiểm soát nhiều hơn các từ vựng của nó đáng chú ý là bạn có thể xây dựng các bảng tra cứu bản thân và vượt qua đó để BertTokenizer
.
Khi bạn vượt qua một chuỗi, BertTokenizer
nào sau đây:
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)
Bây giờ bạn có quyền truy cập trực tiếp vào bảng tra cứu được sử dụng trong tokenizer.
pt_lookup.lookup(tf.constant(['é', 'um', 'uma', 'para', 'não']))
<tf.Tensor: shape=(5,), dtype=int64, numpy=array([7765, 85, 86, 87, 7765])>
Bạn không cần phải sử dụng một tập tin từ vựng, tf.lookup
có các tùy chọn khởi tạo khác. Nếu bạn có các từ vựng trong bộ nhớ, bạn có thể sử dụng 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)