Tokenizacja z TF Text

Zobacz na TensorFlow.org Uruchom w Google Colab Zobacz na GitHub Pobierz notatnik Zobacz modele piasty TF

Przegląd

Tokenizacja to proces dzielenia łańcucha na tokeny. Zazwyczaj te tokeny to słowa, cyfry i/lub znaki interpunkcyjne. tensorflow_text pakiet zawiera szereg tokenizers dostępnych do przeróbki tekstu wymagane przez swoich modeli opartych na tekście. Wykonując tokenizację na wykresie TensorFlow, nie będziesz musiał martwić się o różnice między przepływami uczenia i wnioskowania oraz zarządzaniem skryptami przetwarzania wstępnego.

W tym przewodniku omówiono wiele opcji tokenizacji udostępnianych przez TensorFlow Text, kiedy możesz chcieć użyć jednej opcji zamiast innej oraz jak te tokenizatory są wywoływane z Twojego modelu.

Ustawiać

pip install -q tensorflow-text
import requests
import tensorflow as tf
import tensorflow_text as tf_text

Splitter API

Główne interfejsy są Splitter i SplitterWithOffsets które mają pojedyncze metody split i split_with_offsets . SplitterWithOffsets wariant (która rozciąga Splitter ) zawiera opcję coraz offsety bajtowe. Dzięki temu wywołujący może wiedzieć, z których bajtów w oryginalnym ciągu został utworzony utworzony token.

Tokenizer i TokenizerWithOffsets są wyspecjalizowane wersje Splitter , które zapewniają metody wygodę tokenize i tokenize_with_offsets odpowiednio.

Na ogół dla dowolnego wejścia n-wymiarowej zwrócone żetony są w n + 1-wymiarowego RaggedTensor z najbardziej wewnętrznych wymiarów żetonów Mapowanie pierwotnych poszczególnych łańcuchów.

class Splitter {
  @abstractmethod
  def split(self, input)
}

class SplitterWithOffsets(Splitter) {
  @abstractmethod
  def split_with_offsets(self, input)
}

Istnieje również Detokenizer interfejs. Każdy tokenizer implementujący ten interfejs może zaakceptować N-wymiarowy postrzępiony tensor tokenów i zwykle zwraca tensor N-1-wymiarowy lub tensor postrzępiony, który ma złożone razem dane tokeny.

class Detokenizer {
  @abstractmethod
  def detokenize(self, input)
}

Tokenizatory

Poniżej znajduje się zestaw tokenizerów dostarczonych przez TensorFlow Text. Zakłada się, że dane wejściowe ciągów to UTF-8. Proszę przejrzeć podręcznik Unicode do konwersji ciągów znaków na UTF-8.

Tokenizatory całych słów

Te tokenizatory próbują podzielić ciąg na słowa i są najbardziej intuicyjnym sposobem dzielenia tekstu.

WhitespaceTokenizer

text.WhitespaceTokenizer jest najbardziej podstawowym tokenizer który rozszczepia łańcuchy na OIOM zdefiniowane białych znaków (np. Miejsca, Tab, nowa linia). Jest to często dobre do szybkiego tworzenia modeli prototypowych.

tokenizer = tf_text.WhitespaceTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/util/dispatch.py:206: batch_gather (from tensorflow.python.ops.array_ops) is deprecated and will be removed after 2017-10-25.
Instructions for updating:
`tf.batch_gather` is deprecated, please use `tf.gather` with `batch_dims=-1` instead.
[[b'What', b'you', b'know', b'you', b"can't", b'explain,', b'but', b'you', b'feel', b'it.']]

Wadą tego tokenizera jest to, że w słowie tworzącym token dołączana jest interpunkcja. Aby podzielić słów i znaków interpunkcyjnych na oddzielne elementów, z których UnicodeScriptTokenizer powinny być stosowane.

Tokenizer UnicodeScript

UnicodeScriptTokenizer rozszczepia łańcuchy oparte na Unicode granic skryptów. Użyte kody skryptów odpowiadają wartościom UScriptCode International Components for Unicode (ICU). Zobacz: http://icu-project.org/apiref/icu4c/uscript_8h.html

W praktyce jest to podobne do WhitespaceTokenizer z najbardziej widoczna różnica polega na tym, że będzie ona podzielona interpunkcyjnych (USCRIPT_COMMON) z wersjami językowymi (np. USCRIPT_LATIN, USCRIPT_CYRILLIC, etc), a także oddzielenie tekstów językowych od siebie. Zauważ, że spowoduje to również podział słów skróconych na oddzielne tokeny.

tokenizer = tf_text.UnicodeScriptTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[b'What', b'you', b'know', b'you', b'can', b"'", b't', b'explain', b',', b'but', b'you', b'feel', b'it', b'.']]

Tokenizery podsłów

Tokenizery podsłów mogą być używane z mniejszym słownictwem i pozwalają modelowi mieć pewne informacje o nowych słowach z podsłów, które go tworzą.

Pokrótce omówić opcje podsłowo tokenizacja poniżej, ale poradnik podsłowo tokenizacja idzie bardziej w głębi, a także wyjaśnia, jak generować pliki vocab.

WordpieceTokenizer

Tokenizacja WordPiece to schemat tokenizacji oparty na danych, który generuje zestaw subtokenów. Te subtokeny mogą odpowiadać morfemom językowym, ale często tak nie jest.

WordpieceTokenizer oczekuje, że dane wejściowe zostaną już podzielone na tokeny. Z powodu tego warunku, będzie często chcą podzielić pomocą WhitespaceTokenizer lub UnicodeScriptTokenizer wcześniej.

tokenizer = tf_text.WhitespaceTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[b'What', b'you', b'know', b'you', b"can't", b'explain,', b'but', b'you', b'feel', b'it.']]

Po ciąg jest podzielony na tokeny The WordpieceTokenizer mogą być wykorzystane do rozłamu w subtokens.

url = "https://github.com/tensorflow/text/blob/master/tensorflow_text/python/ops/test_data/test_wp_en_vocab.txt?raw=true"
r = requests.get(url)
filepath = "vocab.txt"
open(filepath, 'wb').write(r.content)
52382
subtokenizer = tf_text.UnicodeScriptTokenizer(filepath)
subtokens = tokenizer.tokenize(tokens)
print(subtokens.to_list())
[[[b'What'], [b'you'], [b'know'], [b'you'], [b"can't"], [b'explain,'], [b'but'], [b'you'], [b'feel'], [b'it.']]]

BertTokenizer

BertTokenizer odzwierciedla oryginalną implementację tokenizacji z papieru BERT. Jest to wspierane przez WordpieceTokenizer, ale wykonuje również dodatkowe zadania, takie jak normalizacja i tokenizacja najpierw na słowa.

tokenizer = tf_text.BertTokenizer(filepath, token_out_type=tf.string, lower_case=True)
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[[b'what'], [b'you'], [b'know'], [b'you'], [b'can'], [b"'"], [b't'], [b'explain'], [b','], [b'but'], [b'you'], [b'feel'], [b'it'], [b'.']]]

SentencepieceTokenizer

SentencepieceTokenizer to tokenizer podrzędny, który można w dużym stopniu konfigurować. Jest to wspierane przez bibliotekę Sentencepiece. Podobnie jak BertTokenizer, może obejmować normalizację i dzielenie tokenów przed podziałem na podtokeny.

url = "https://github.com/tensorflow/text/blob/master/tensorflow_text/python/ops/test_data/test_oss_model.model?raw=true"
sp_model = requests.get(url).content
tokenizer = tf_text.SentencepieceTokenizer(sp_model, out_type=tf.string)
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[b'\xe2\x96\x81What', b'\xe2\x96\x81you', b'\xe2\x96\x81know', b'\xe2\x96\x81you', b'\xe2\x96\x81can', b"'", b't', b'\xe2\x96\x81explain', b',', b'\xe2\x96\x81but', b'\xe2\x96\x81you', b'\xe2\x96\x81feel', b'\xe2\x96\x81it', b'.']]

Inne rozgałęźniki

UnicodeCharTokenizer

Dzieli ciąg na znaki UTF-8. Jest to przydatne w przypadku języków CJK, w których nie ma spacji między wyrazami.

tokenizer = tf_text.UnicodeCharTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[87, 104, 97, 116, 32, 121, 111, 117, 32, 107, 110, 111, 119, 32, 121, 111, 117, 32, 99, 97, 110, 39, 116, 32, 101, 120, 112, 108, 97, 105, 110, 44, 32, 98, 117, 116, 32, 121, 111, 117, 32, 102, 101, 101, 108, 32, 105, 116, 46]]

Dane wyjściowe to punkty kodowe Unicode. Może to być również przydatne do tworzenia postaci ngramów, takich jak bigramy. Aby przekonwertować z powrotem na znaki UTF-8.

characters = tf.strings.unicode_encode(tf.expand_dims(tokens, -1), "UTF-8")
bigrams = tf_text.ngrams(characters, 2, reduction_type=tf_text.Reduction.STRING_JOIN, string_separator='')
print(bigrams.to_list())
[[b'Wh', b'ha', b'at', b't ', b' y', b'yo', b'ou', b'u ', b' k', b'kn', b'no', b'ow', b'w ', b' y', b'yo', b'ou', b'u ', b' c', b'ca', b'an', b"n'", b"'t", b't ', b' e', b'ex', b'xp', b'pl', b'la', b'ai', b'in', b'n,', b', ', b' b', b'bu', b'ut', b't ', b' y', b'yo', b'ou', b'u ', b' f', b'fe', b'ee', b'el', b'l ', b' i', b'it', b't.']]

HubModułTokenizer

Jest to wrapper wokół modeli wdrożonych w TF Hub, aby ułatwić połączenia, ponieważ obecnie TF Hub nie obsługuje nierównych tensorów. Posiadanie modelu wykonującego tokenizację jest szczególnie przydatne w przypadku języków CJK, gdy chcesz podzielić na słowa, ale nie ma spacji, aby zapewnić przewodnik heurystyczny. W tej chwili mamy jeden model segmentacji dla języka chińskiego.

MODEL_HANDLE = "https://tfhub.dev/google/zh_segmentation/1"
segmenter = tf_text.HubModuleTokenizer(MODEL_HANDLE)
tokens = segmenter.tokenize(["新华社北京"])
print(tokens.to_list())
[[b'\xe6\x96\xb0\xe5\x8d\x8e\xe7\xa4\xbe', b'\xe5\x8c\x97\xe4\xba\xac']]

Wyświetlenie wyników zakodowanych w UTF-8 ciągów bajtów może być trudne. Dekoduj wartości listy, aby ułatwić przeglądanie.

def decode_list(x):
  if type(x) is list:
    return list(map(decode_list, x))
  return x.decode("UTF-8")

def decode_utf8_tensor(x):
  return list(map(decode_list, x.to_list()))

print(decode_utf8_tensor(tokens))
[['新华社', '北京']]

SplitMergeTokenizer

SplitMergeTokenizer & SplitMergeFromLogitsTokenizer mają ukierunkowane Celem podziału ciąg na podstawie określonych wartości, które wskazują, gdzie łańcuch powinny być podzielone. Jest to przydatne podczas tworzenia własnych modeli segmentacji, takich jak poprzedni przykład segmentacji.

Dla SplitMergeTokenizer , wartość 0 jest używany do wskazania rozpoczęcia nowego łańcucha, a wartość 1 oznacza, że postać jest częścią bieżącego łańcucha.

strings = ["新华社北京"]
labels = [[0, 1, 1, 0, 1]]
tokenizer = tf_text.SplitMergeTokenizer()
tokens = tokenizer.tokenize(strings, labels)
print(decode_utf8_tensor(tokens))
[['新华社', '北京']]

SplitMergeFromLogitsTokenizer jest podobna, ale zamiast akceptuje pary wartości logitowe z sieci neuronowych, że przewidzieć, czy każda postać powinna zostać podzielona na nowy ciąg lub połączone w aktualnej.

strings = [["新华社北京"]]
labels = [[[5.0, -3.2], [0.2, 12.0], [0.0, 11.0], [2.2, -1.0], [-3.0, 3.0]]]
tokenizer = tf_text.SplitMergeFromLogitsTokenizer()
tokenizer.tokenize(strings, labels)
print(decode_utf8_tensor(tokens))
[['新华社', '北京']]

RegexSplitter

RegexSplitter potrafi sznurków segmentu w dowolnych pułapki określonych przez przewidzianego wyrażenia regularnego.

splitter = tf_text.RegexSplitter("\s")
tokens = splitter.split(["What you know you can't explain, but you feel it."], )
print(tokens.to_list())
[[b'What', b'you', b'know', b'you', b"can't", b'explain,', b'but', b'you', b'feel', b'it.']]

Przesunięcia

Podczas tokenizacji ciągów często pożądane jest, aby wiedzieć, skąd w oryginalnym ciągu pochodzi token. Z tego powodu, każdy tokenizera które wprowadza TokenizerWithOffsets ma metodę tokenize_with_offsets które powrotu przesunięć bajtowych wraz ze znaczników. Start_offsets wyświetla listę bajtów w oryginalnym ciągu, od którego zaczyna się każdy token, a end_offsets wyświetla bajty bezpośrednio po punkcie, w którym kończy się każdy token. Aby odwrócić, odsunięcia początkowe są włączone, a odsunięcia końcowe są wyłączne.

tokenizer = tf_text.UnicodeScriptTokenizer()
(tokens, start_offsets, end_offsets) = tokenizer.tokenize_with_offsets(['Everything not saved will be lost.'])
print(tokens.to_list())
print(start_offsets.to_list())
print(end_offsets.to_list())
[[b'Everything', b'not', b'saved', b'will', b'be', b'lost', b'.']]
[[0, 11, 15, 21, 26, 29, 33]]
[[10, 14, 20, 25, 28, 33, 34]]

Detokenizacja

Tokenizers które implementują Detokenizer zapewnić detokenize metodę, która próbuje połączyć ciągi. Może to być stratne, więc zdetokenizowany ciąg może nie zawsze dokładnie odpowiadać oryginalnemu, wstępnie ztokenizowanemu ciągowi.

tokenizer = tf_text.UnicodeCharTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
strings = tokenizer.detokenize(tokens)
print(strings.numpy())
[[87, 104, 97, 116, 32, 121, 111, 117, 32, 107, 110, 111, 119, 32, 121, 111, 117, 32, 99, 97, 110, 39, 116, 32, 101, 120, 112, 108, 97, 105, 110, 44, 32, 98, 117, 116, 32, 121, 111, 117, 32, 102, 101, 101, 108, 32, 105, 116, 46]]
[b"What you know you can't explain, but you feel it."]

Dane TF

TF Data to zaawansowany interfejs API do tworzenia potoku wejściowego dla modeli szkoleniowych. Tokenizery działają zgodnie z oczekiwaniami z interfejsem API.

docs = tf.data.Dataset.from_tensor_slices([['Never tell me the odds.'], ["It's a trap!"]])
tokenizer = tf_text.WhitespaceTokenizer()
tokenized_docs = docs.map(lambda x: tokenizer.tokenize(x))
iterator = iter(tokenized_docs)
print(next(iterator).to_list())
print(next(iterator).to_list())
[[b'Never', b'tell', b'me', b'the', b'odds.']]
[[b"It's", b'a', b'trap!']]