Tokenização com texto TF

Ver no TensorFlow.org Executar no Google Colab Ver no GitHub Baixar caderno Veja os modelos TF Hub

Visão geral

A tokenização é o processo de quebrar uma string em tokens. Normalmente, esses tokens são palavras, números e / ou pontuação. O tensorflow_text pacote fornece um número de tokenizers disponíveis para pré-processamento de texto exigido por seus modelos baseados em texto. Ao realizar a tokenização no gráfico do TensorFlow, você não precisa se preocupar com as diferenças entre os fluxos de trabalho de treinamento e inferência e o gerenciamento de scripts de pré-processamento.

Este guia discute as várias opções de tokenização fornecidas pelo TensorFlow Text, quando você deseja usar uma opção em vez de outra e como esses tokenizadores são chamados de dentro do seu modelo.

Configurar

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

API divisor

Os principais interfaces são Splitter e SplitterWithOffsets que têm métodos únicos split e split_with_offsets . O SplitterWithOffsets variante (que se estende Splitter ) inclui uma opção para obter deslocamentos byte. Isso permite que o chamador saiba de quais bytes na string original o token criado foi criado.

O Tokenizer e TokenizerWithOffsets são versões especializadas do Splitter que fornecem os métodos de conveniência tokenize e tokenize_with_offsets respectivamente.

De um modo geral, para qualquer entrada de N-dimensional, as fichas são retornados em um N + 1-dimensional RaggedTensor com a dimensão mais interna de fichas de mapeamento para as cordas individuais originais.

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

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

Há também um Detokenizer interface. Qualquer tokenizador implementando esta interface pode aceitar um tensor irregular N-dimensional de tokens e normalmente retorna um tensor N-1-dimensional ou tensor irregular que tem os tokens fornecidos montados juntos.

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

Tokenizers

Abaixo está o pacote de tokenizadores fornecidos pelo TensorFlow Text. As entradas de string são consideradas UTF-8. Por favor, revise o guia de Unicode para a conversão de strings para UTF-8.

Tokenizadores de palavras inteiras

Esses tokenizers tentam dividir uma string por palavras e é a maneira mais intuitiva de dividir texto.

WhitespaceTokenizer

O text.WhitespaceTokenizer é o tokenizador mais básico que divide cordas em UTI definido caracteres em branco (por exemplo., O espaço de tabulação, nova linha). Isso geralmente é bom para construir modelos de protótipo rapidamente.

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

Você pode notar que um defeito deste tokenizer é que a pontuação é incluída com a palavra para compor um token. Para dividir as palavras e pontuação em tokens separados, o UnicodeScriptTokenizer deve ser usado.

UnicodeScriptTokenizer

O UnicodeScriptTokenizer divide seqüências com base em limites de script Unicode. Os códigos de script usados ​​correspondem aos valores UScriptCode do International Components for Unicode (ICU). Veja: http://icu-project.org/apiref/icu4c/uscript_8h.html

Na prática, isto é semelhante ao WhitespaceTokenizer com o ser diferença mais aparente que vai dividir pontuação (USCRIPT_COMMON) de textos de linguagem (por ex. USCRIPT_LATIN, USCRIPT_CYRILLIC, etc.) e ao mesmo tempo separar textos de linguagem de cada outro. Observe que isso também dividirá as palavras de contração em tokens separados.

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

Tokenizadores de subpalavra

Os tokenizadores de subpalavra podem ser usados ​​com um vocabulário menor e permitem que o modelo tenha algumas informações sobre as novas palavras das subpalavras que o criaram.

Nós discutir brevemente as opções subword tokenization abaixo, mas o tutorial subword Tokenization vai mais em profundidade e também explica como para gerar os arquivos de vocabulário.

WordpieceTokenizer

A tokenização do WordPiece é um esquema de tokenização controlado por dados que gera um conjunto de sub-tokens. Esses sub-tokens podem corresponder a morfemas linguísticos, mas nem sempre é o caso.

O WordpieceTokenizer espera que a entrada já esteja dividida em tokens. Devido a esta condição, muitas vezes você vai querer dividir usando o WhitespaceTokenizer ou UnicodeScriptTokenizer antemão.

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

Após a cadeia é dividida em fichas, o WordpieceTokenizer pode ser usado para dividir em 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

O BertTokenizer espelha a implementação original de tokenização do papel de BERT. Isso é apoiado pelo WordpieceTokenizer, mas também executa tarefas adicionais, como normalização e tokenização para palavras primeiro.

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

SentençapieceTokenizer

O SentençapieceTokenizer é um tokenizador de sub-token altamente configurável. Isso é apoiado pela biblioteca Sentençapiece. Como o BertTokenizer, pode incluir normalização e divisão de tokens antes de dividir em sub-tokens.

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

Outros divisores

UnicodeCharTokenizer

Isso divide uma string em caracteres UTF-8. É útil para idiomas CJK que não possuem espaços entre as palavras.

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

A saída são pontos de código Unicode. Isso também pode ser útil para criar ngrams de personagens, como bigramas. Para converter de volta em caracteres 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

Este é um invólucro em torno de modelos implantados no TF Hub para tornar as chamadas mais fáceis, já que o TF Hub atualmente não oferece suporte a tensores irregulares. Ter um modelo para executar a tokenização é particularmente útil para linguagens CJK quando você deseja dividir em palavras, mas não tem espaços para fornecer um guia heurístico. No momento, temos um único modelo de segmentação para chinês.

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

Pode ser difícil visualizar os resultados das strings de byte codificadas em UTF-8. Decodifique os valores da lista para facilitar a visualização.

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

O SplitMergeTokenizer & SplitMergeFromLogitsTokenizer têm uma finalidade específica de divisão uma corda com base em valores fornecidos que indicam onde o texto deverá estar dividida. Isso é útil ao construir seus próprios modelos de segmentação, como o exemplo anterior de segmentação.

Para o SplitMergeTokenizer , um valor de 0 é usado para indicar o início de uma nova cadeia, eo valor 1 indica que o personagem é parte da string atual.

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

O SplitMergeFromLogitsTokenizer é semelhante, mas em vez aceita pares de valores logit de uma rede neural que prever se cada personagem deve ser dividido em uma nova string ou incorporadas pela atual.

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

O RegexSplitter é capaz de cordas de segmento em pontos de interrupção arbitrária definida por uma expressão regular fornecida.

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

Offsets

Ao tokenizar strings, geralmente é desejável saber de onde o token se originou na string original. Por esta razão, cada tokenizador que implementa TokenizerWithOffsets tem um método tokenize_with_offsets que irá retornar os deslocamentos byte juntamente com os sinais. O start_offsets lista os bytes na string original em que cada token começa, e o end_offsets lista os bytes imediatamente após o ponto onde cada token termina. Para refrasear, os deslocamentos iniciais são inclusivos e os deslocamentos finais são exclusivos.

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

Detokenização

Tokenizers que implementar o Detokenizer fornecer uma detokenize método que tenta combinar as cordas. Isso tem a chance de causar perdas, portanto, a string detokenizada nem sempre pode corresponder exatamente à string original pré-tokenizada.

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

Dados TF

TF Data é uma API poderosa para criar um pipeline de entrada para modelos de treinamento. Os tokenizadores funcionam conforme o esperado com a 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!']]