Токенизация с помощью TF Text

Посмотреть на TensorFlow.org Запускаем в Google Colab Посмотреть на GitHub Скачать блокнот Посмотреть модели TF Hub

Обзор

Токенизация - это процесс разбиения строки на токены. Обычно эти токены представляют собой слова, числа и / или знаки препинания. tensorflow_text пакет предоставляет ряд tokenizers доступных для предварительной обработки текста требует вашего текста на основе моделей. Выполнив токенизацию в графе TensorFlow, вам не нужно будет беспокоиться о различиях между рабочими процессами обучения и логического вывода и управлением сценариями предварительной обработки.

В этом руководстве обсуждаются многие варианты токенизации, предоставляемые TensorFlow Text, когда вы можете использовать один вариант вместо другого, и то, как эти токенизаторы вызываются из вашей модели.

Настраивать

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

Splitter API

Основные интерфейсы Splitter и SplitterWithOffsets , которые имеют единичные методы split и split_with_offsets . SplitterWithOffsets вариант (который простирается Splitter ) включает в себя опцию для получения смещения байт. Это позволяет вызывающей стороне узнать, из каких байтов исходной строки был создан токен.

Tokenizer и TokenizerWithOffsets специализированные версии Splitter , которые обеспечивают удобные методы tokenize и tokenize_with_offsets соответственно.

Как правило, для любого N-мерного ввода, возвращенные жетоны в N +--мерном RaggedTensor с внутренним-самым измерением маркеров , отображающих к исходным отдельным строкам.

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

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

Существует также Detokenizer интерфейс. Любой токенизатор, реализующий этот интерфейс, может принимать N-мерный рваный тензор токенов и обычно возвращает N-1-мерный тензор или рваный тензор, который собирает данные токены вместе.

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

Токенизаторы

Ниже представлен набор токенизаторов, предоставляемых TensorFlow Text. Предполагается, что строковые входы имеют кодировку UTF-8. Пожалуйста , ознакомьтесь с руководством Unicode для преобразования строк в кодировку UTF-8.

Токенизаторы целого слова

Эти токенизаторы пытаются разбить строку по словам и являются наиболее интуитивно понятным способом разделения текста.

WhitespaceTokenizer

text.WhitespaceTokenizer является самым основным токенизатором который разделяет строки на ОЯТ определенные символы пробелов (напр. Пробел, табуляция, новая строка). Это часто полезно для быстрого создания моделей-прототипов.

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.']]

Вы можете заметить недостаток этого токенизатора в том, что в слово добавлена ​​пунктуация, составляющая токен. Для разделения слов и знаков препинания в отдельные лексемы, то UnicodeScriptTokenizer следует использовать.

UnicodeScriptTokenizer

UnicodeScriptTokenizer разбивает строки , основанные на границах сценария Unicode. Используемые коды скриптов соответствуют значениям UScriptCode международных компонентов Unicode (ICU). См: http://icu-project.org/apiref/icu4c/uscript_8h.html

На практике это похоже на WhitespaceTokenizer с самой очевидной разницей, что она будет разделена пунктуация (USCRIPT_COMMON) от языковых текстов (например, USCRIPT_LATIN, USCRIPT_CYRILLIC и т.д.) , а также разделение текстов языка друг от друга. Обратите внимание, что это также разделит слова сокращения на отдельные токены.

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'.']]

Токенизаторы подслов

Токенизаторы подслов могут использоваться с меньшим словарным запасом и позволяют модели получать некоторую информацию о новых словах из подслов, которые создают их.

Мы кратко обсудим возможные варианты подсловной лексемизации ниже, но учебник подсловной лексемизацию идет больше в глубине , а также объясняет , как генерировать файлы Vocab.

WordpieceTokenizer

Токенизация WordPiece - это схема токенизации, управляемая данными, которая генерирует набор суб-токенов. Эти суб-токены могут соответствовать лингвистическим морфемам, но часто это не так.

WordpieceTokenizer ожидает, что ввод уже будет разделен на токены. Из - за этой предпосылки, вы часто хотите разделить с помощью WhitespaceTokenizer или UnicodeScriptTokenizer заранее.

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.']]

После того , как строка разбивается на лексемы, то WordpieceTokenizer может быть использовано для разделения в 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 отражает оригинальную реализацию токенизации из статьи BERT. Это поддерживается WordpieceTokenizer, но также выполняет дополнительные задачи, такие как нормализация и преобразование сначала в слова.

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 - это токенизатор суб-токена, который легко настраивается. Это поддерживается библиотекой Sentencepiece. Как и BertTokenizer, он может включать нормализацию и разделение токенов перед разделением на суб-токены.

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'.']]

Прочие разветвители

UnicodeCharTokenizer

Это разбивает строку на символы UTF-8. Это полезно для языков CJK, в которых нет пробелов между словами.

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

На выходе будут кодовые точки Unicode. Это также может быть полезно для создания символьных нграмм, таких как биграммы. Чтобы преобразовать обратно в символы 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.']]

HubModuleTokenizer

Это оболочка для моделей, развернутых в TF Hub, чтобы упростить вызовы, поскольку TF Hub в настоящее время не поддерживает рваные тензоры. Наличие модели, выполняющей токенизацию, особенно полезно для языков CJK, когда вы хотите разбить на слова, но у вас нет пробелов для эвристического руководства. В настоящее время у нас есть единая модель сегментации для китайцев.

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']]

Может быть трудно просмотреть результаты байтовых строк в кодировке UTF-8. Расшифруйте значения списка, чтобы упростить просмотр.

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 имеют целенаправленную целью разделения строки на основе предоставленных значений , которые указывают , где строка должна быть разделена. Это полезно при построении ваших собственных моделей сегментации, подобных предыдущему примеру сегментации.

Для SplitMergeTokenizer , значение 0 используется для указания начала новой строки, а значение 1 указывает символ является частью текущей строки.

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

SplitMergeFromLogitsTokenizer аналогичен, но вместо этого он принимает логит пару значений из нейронной сети, предсказать , если каждый символ должен быть разделен на новую строку или слит в текущий.

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 способен строки сегмента при произвольных контрольных точках , определяемых при условии регулярного выражения.

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.']]

Смещения

При разметке строк часто требуется знать, откуда в исходной строке произошел токен. По этой причине, каждый Tokenizer , который реализует TokenizerWithOffsets имеет метод tokenize_with_offsets , который будет возвращать смещение байта вместе с маркерами. Start_offsets перечисляет байты в исходной строке, с которой начинается каждый токен, а end_offsets перечисляет байты сразу после точки, где заканчивается каждый токен. Чтобы выполнить повторное стирание, начальные смещения включаются, а конечные смещения являются исключительными.

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

Детокенизация

Tokenizers которые реализуют Detokenizer обеспечивают detokenize метод , который пытается объединить строки. Это может привести к потерям, поэтому детокенизированная строка не всегда может точно соответствовать исходной, предварительно токенизированной строке.

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

Данные TF

TF Data - это мощный API для создания входного конвейера для обучающих моделей. Токенизаторы работают с 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!']]