सबवर्ड टोकनाइज़र

TensorFlow.org पर देखें Google Colab में चलाएं GitHub पर स्रोत देखें नोटबुक डाउनलोड करें

इस ट्यूटोरियल दर्शाता है कि कैसे एक डाटासेट से एक subword शब्दावली उत्पन्न करते हैं, और इसका इस्तेमाल एक निर्माण करने के लिए करने के लिए text.BertTokenizer शब्दावली से।

सबवर्ड टोकननाइज़र का मुख्य लाभ यह है कि यह शब्द-आधारित और वर्ण-आधारित टोकन के बीच अंतर करता है। सामान्य शब्दों को शब्दावली में एक स्थान मिलता है, लेकिन टोकननाइज़र अज्ञात शब्दों के लिए शब्द के टुकड़ों और अलग-अलग वर्णों पर वापस आ सकता है।

अवलोकन

tensorflow_text पैकेज कई आम tokenizers की TensorFlow कार्यान्वयन भी शामिल है। इसमें तीन उपशब्द-शैली के टोकन शामिल हैं:

  • text.BertTokenizer - BertTokenizer वर्ग एक उच्च स्तर इंटरफ़ेस है। यह बर्ट के टोकन बंटवारे एल्गोरिथ्म और एक शामिल WordPieceTokenizer । यह इनपुट के रूप में लेता है और वाक्य टोकन पहचान-चिह्न देता है।
  • text.WordpeiceTokenizer - WordPieceTokenizer वर्ग एक निचले स्तर इंटरफ़ेस है। यह केवल लागू करता WordPiece एल्गोरिथ्म । आपको टेक्स्ट को कॉल करने से पहले उसे मानकीकृत और शब्दों में विभाजित करना होगा। यह इनपुट के रूप में शब्द लेता है और टोकन पहचान-चिह्न देता है।
  • text.SentencepieceTokenizer - SentencepieceTokenizer एक अधिक जटिल सेटअप की आवश्यकता है। इसके इनिशियलाइज़र को पूर्व-प्रशिक्षित वाक्यपीस मॉडल की आवश्यकता होती है। देखें गूगल / sentencepiece भंडार कैसे इन मॉडलों में से एक का निर्माण करने के बारे में निर्देश के लिए। यह जब tokenizing इनपुट के रूप में वाक्य स्वीकार कर सकते हैं।

यह ट्यूटोरियल मौजूदा शब्दों से शुरू करते हुए टॉप डाउन तरीके से वर्डपीस शब्दावली बनाता है। यह प्रक्रिया जापानी, चीनी या कोरियाई के लिए काम नहीं करती क्योंकि इन भाषाओं में स्पष्ट बहु-वर्ण इकाइयाँ नहीं होती हैं। इन भाषाओं विचार के का उपयोग कर tokenize करने के लिए 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
2021-08-11 18:46:18.414452: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
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']
2021-08-11 18:46:23.603290: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1
2021-08-11 18:46:24.267575: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:46:24.268580: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1733] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2021-08-11 18:46:24.268617: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
2021-08-11 18:46:24.271953: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublas.so.11
2021-08-11 18:46:24.272053: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublasLt.so.11
2021-08-11 18:46:24.273192: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcufft.so.10
2021-08-11 18:46:24.273527: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcurand.so.10
2021-08-11 18:46:24.274580: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusolver.so.11
2021-08-11 18:46:24.275559: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusparse.so.11
2021-08-11 18:46:24.275779: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudnn.so.8
2021-08-11 18:46:24.275884: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:46:24.276973: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:46:24.277878: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1871] Adding visible gpu devices: 0
2021-08-11 18:46:24.278525: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2021-08-11 18:46:24.279136: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:46:24.280033: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1733] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2021-08-11 18:46:24.280116: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:46:24.281009: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:46:24.281856: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1871] Adding visible gpu devices: 0
2021-08-11 18:46:24.281894: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
2021-08-11 18:46:24.912068: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1258] Device interconnect StreamExecutor with strength 1 edge matrix:
2021-08-11 18:46:24.912106: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1264]      0 
2021-08-11 18:46:24.912115: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1277] 0:   N 
2021-08-11 18:46:24.912363: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:46:24.913392: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:46:24.914368: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:46:24.915336: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1418] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 14646 MB memory) -> physical GPU (device: 0, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:05.0, compute capability: 7.0)

यह डेटासेट पुर्तगाली/अंग्रेज़ी वाक्य जोड़े तैयार करता है:

for pt, en in train_examples.take(1):
  print("Portuguese: ", pt.numpy().decode('utf-8'))
  print("English:   ", en.numpy().decode('utf-8'))
2021-08-11 18:46:25.028577: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:176] None of the MLIR Optimization Passes are enabled (registered 2)
2021-08-11 18:46:25.029197: I tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2000165000 Hz
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 36s, sys: 2.48 s, total: 1min 39s
Wall time: 1min 33s

यहाँ परिणामी शब्दावली के कुछ अंश दिए गए हैं।

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 8s, sys: 1.98 s, total: 1min 10s
Wall time: 1min 5s
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 ताकि वे अन्य ट्यूटोरियल से आयात किया जा सकता।

कस्टम टोकनाइजेशन

नीचे की ओर ट्यूटोरियल दोनों tokenized पाठ शामिल करने की उम्मीद [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-08-11 18:49:08.917974: 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/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%)
  adding: ted_hrlr_translate_pt_en_converter/saved_model.pb (deflated 91%)
du -h *.zip
184K    ted_hrlr_translate_pt_en_converter.zip

वैकल्पिक: एल्गोरिथ्म

यहां यह ध्यान देने योग्य है कि वर्डपीस एल्गोरिथम के दो संस्करण हैं: बॉटम-अप और टॉप-डाउन। दोनों ही मामलों में लक्ष्य समान है: "एक प्रशिक्षण कॉर्पस और कई वांछित टोकन डी को देखते हुए, अनुकूलन समस्या डी वर्डपीस का चयन करना है, ताकि परिणामी कॉर्पस चुने गए वर्डपीस मॉडल के अनुसार खंडित होने पर वर्डपीस की संख्या में न्यूनतम हो। "

मूल बॉटम-अप WordPiece एल्गोरिथ्म पर आधारित है, बाइट-जोड़ी एन्कोडिंग । बीपीई की तरह, यह वर्णमाला से शुरू होता है, और शब्द-टुकड़े और शब्दों को बनाने के लिए पुनरावृत्त रूप से सामान्य बिग्राम को जोड़ता है।

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 । अब, इन टोकनों पर कभी विचार नहीं किया जाता है, इसलिए वे दूसरी पुनरावृत्ति से उत्पन्न नहीं होंगे। हम यह सुनिश्चित करने के लिए कई पुनरावृत्तियों का प्रदर्शन करते हैं कि परिणाम अभिसरण करें (हालांकि कोई शाब्दिक अभिसरण गारंटी नहीं है)।

वर्डपीस लागू करना

एक बार वर्डपीस शब्दावली तैयार हो जाने के बाद, हमें इसे नए डेटा पर लागू करने में सक्षम होना चाहिए। एल्गोरिथ्म एक साधारण लालची सबसे लंबा-मैच-प्रथम अनुप्रयोग है।

उदाहरण के लिए, शब्द के आधार पर विभाजित करने पर विचार undeniable

हम पहले देखने undeniable हमारे WordPiece शब्दकोश में, और अगर यह वर्तमान में, हम काम हो गया। यदि नहीं, तो हम एक चरित्र, और बार-बार, जैसे, द्वारा अंत बिंदु घटती undeniabl

आखिरकार, हम या तो अपनी शब्दावली में एक सबटोकन पाएंगे, या एक सिंगल कैरेक्टर सबटोकन तक पहुंच जाएंगे। (सामान्य तौर पर, हम मानते हैं कि हर चरित्र, हमारे शब्दावली में है, हालांकि इस पराक्रम दुर्लभ यूनिकोड वर्ण के लिए मामला नहीं होना। हम एक दुर्लभ यूनिकोड वर्ण कि शब्दावली में नहीं है का सामना करते हैं हम केवल पूरे शब्द को मैप <unk> )।

इस मामले में, हम पाते हैं un हमारे शब्दावली में। तो यह हमारा पहला शब्द टुकड़ा है। फिर हम के अंत के लिए कूद un और प्रसंस्करण दोहराए जाते हैं, जैसे, खोजने की कोशिश ##deniable है, तो ##deniabl , आदि जब तक हम पूरे शब्द विभाजित करने के बाद यह दोहराया जाता है।

सहज बोध

सहज रूप से, WordPiece टोकेनाइजेशन दो अलग-अलग उद्देश्यों को पूरा करने का प्रयास कर रहा है:

  1. संभव के रूप में टुकड़ों में से कम से कम संख्या में डेटा Tokenize। यह ध्यान रखना महत्वपूर्ण है कि वर्डपीस एल्गोरिथम शब्दों को विभाजित करने के लिए "चाहता" नहीं है। अन्यथा, यह सिर्फ अपनी वर्ण, जैसे, में हर शब्द को विभाजित होगा human -> {h, ##u, ##m, ##a, #n} । यह एक महत्वपूर्ण बात यह है कि रूपात्मक splitters, जो भी आम शब्दों के लिए भाषाई रूपिम बंट जाएगा से WordPiece अलग बनाता है (जैसे, unwanted -> {un, want, ed} )।

  2. जब किसी शब्द को टुकड़ों में विभाजित करना होता है, तो उसे उन टुकड़ों में विभाजित करें जिनकी प्रशिक्षण डेटा में अधिकतम गणना होती है। उदाहरण के लिए, कारण है कि शब्द undeniable भागों में विभाजित किया {un, ##deni, ##able} बल्कि जैसे विकल्पों से {unde, ##niab, ##le} है कि के लिए मायने रखता है un और ##able में विशेष रूप से बहुत अधिक होगा, क्योंकि ये सामान्य उपसर्ग और प्रत्यय हैं। हालांकि के लिए गिनती ##le से अधिक होना चाहिए ##able , की कम मायने रखता है unde और ##niab यह एक कम "वांछनीय" एल्गोरिथ्म के लिए tokenization कर देगा।

वैकल्पिक: tf.लुकअप

आप शब्दावली ध्यान देने योग्य बात यह की कीमत है कि आप लुकअप तालिका अपने आप का निर्माण और के लिए है कि पारित कर सकते हैं से अधिक करने के लिए उपयोग, या अधिक नियंत्रण की जरूरत है 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)