Tokenizzazione con testo TF

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza su GitHub Scarica taccuino Vedi i modelli di mozzo TF

Panoramica

La tokenizzazione è il processo di scomposizione di una stringa in token. Comunemente, questi token sono parole, numeri e/o punteggiatura. Il tensorflow_text pacchetto fornisce un certo numero di tokenizers disponibili per la pre-elaborazione testo richiesto dai vostri modelli basati su testo. Eseguendo la tokenizzazione nel grafico TensorFlow, non dovrai preoccuparti delle differenze tra i flussi di lavoro di formazione e inferenza e la gestione degli script di pre-elaborazione.

Questa guida illustra le numerose opzioni di tokenizzazione fornite da TensorFlow Text, quando potresti voler utilizzare un'opzione rispetto a un'altra e come questi tokenizer vengono chiamati dall'interno del tuo modello.

Impostare

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

API di divisione

Le interfacce principali sono Splitter e SplitterWithOffsets aventi metodi singole split e split_with_offsets . Lo SplitterWithOffsets variante (che si estende Splitter ) include un'opzione per ottenere scostamenti di byte. Ciò consente al chiamante di sapere da quali byte nella stringa originale è stato creato il token creato.

Il Tokenizer e TokenizerWithOffsets sono versioni specializzate del Splitter che forniscono i metodi di convenienza tokenize e tokenize_with_offsets rispettivamente.

Generalmente, per qualsiasi ingresso N-dimensionale, i token restituiti sono in una N + 1-dimensionale RaggedTensor con la dimensione più interna di token mappatura per le singole stringhe originali.

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

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

V'è anche un Detokenizer interfaccia. Qualsiasi tokenizer che implementa questa interfaccia può accettare un tensore irregolare di token N-dimensionale e normalmente restituisce un tensore a N-1 dimensioni o un tensore irregolare che ha i token dati assemblati insieme.

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

Tokenizzatori

Di seguito è riportata la suite di tokenizer fornita da TensorFlow Text. Si presume che gli input di stringa siano UTF-8. Si prega di rivedere la guida Unicode per la conversione di stringhe in UTF-8.

Tokenizzatori di parole intere

Questi tokenizer tentano di dividere una stringa per parole ed è il modo più intuitivo per dividere il testo.

Tokenizzatore di spazi bianchi

Il text.WhitespaceTokenizer è il tokenizzatore più fondamentale che divide le stringhe di caratteri in ICU definito spaziatura (ad es. Spazio, tab, nuova linea). Questo è spesso utile per costruire rapidamente modelli prototipo.

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

Potresti notare un difetto di questo tokenizer è che la punteggiatura è inclusa nella parola per creare un token. Per dividere le parole e la punteggiatura in token separati, UnicodeScriptTokenizer dovrebbe essere usato.

UnicodeScriptTokenizer

UnicodeScriptTokenizer divide le stringhe Unicode basate su confini di script. I codici script utilizzati corrispondono ai valori UScriptCode di International Components for Unicode (ICU). Vedi: http://icu-project.org/apiref/icu4c/uscript_8h.html

In pratica, questo è simile al WhitespaceTokenizer con il più evidente essere differenza che si dividerà punteggiatura (USCRIPT_COMMON) da testi di lingua (es. USCRIPT_LATIN, USCRIPT_CYRILLIC, ecc) mentre anche separando testi in lingua uno dall'altro. Nota che questo dividerà anche le parole di contrazione in token separati.

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

Tokenizzatori di sottoparole

I tokenizzatori di sottoparole possono essere utilizzati con un vocabolario più piccolo e consentono al modello di avere alcune informazioni sulle nuove parole dalle sottoparole che lo creano.

Discutiamo brevemente le opzioni Subword tokenizzazione sotto, ma il tutorial di Subword Tokenizzazione va più in profondità e spiega anche come generare i file vocab.

WordpieceTokenizer

La tokenizzazione di WordPiece è uno schema di tokenizzazione basato sui dati che genera una serie di token secondari. Questi sub-token possono corrispondere a morfemi linguistici, ma spesso non è così.

Il WordpieceTokenizer si aspetta che l'input sia già suddiviso in token. A causa di questo prerequisito, spesso si vuole dividere con il WhitespaceTokenizer o UnicodeScriptTokenizer anticipo.

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

Dopo la stringa viene divisa in token, il WordpieceTokenizer può essere usato per dividere in 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

Il BertTokenizer rispecchia l'implementazione originale della tokenizzazione dal documento BERT. Questo è supportato da WordpieceTokenizer, ma esegue anche attività aggiuntive come la normalizzazione e la tokenizzazione delle parole prima.

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

FraseTokenizer

Il SentencepieceTokenizer è un tokenizzatore sub-token altamente configurabile. Questo è supportato dalla libreria di Frasi. Come BertTokenizer, può includere la normalizzazione e la suddivisione dei token prima della suddivisione in token secondari.

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

Altri splitter

UnicodeCharTokenizer

Questo divide una stringa in caratteri UTF-8. È utile per le lingue CJK che non hanno spazi tra le parole.

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

L'output è codepoint Unicode. Questo può essere utile anche per creare ngrammi di caratteri, come i bigrammi. Per riconvertire in caratteri 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

Questo è un wrapper per i modelli distribuiti su TF Hub per rendere le chiamate più semplici poiché TF Hub attualmente non supporta tensori irregolari. Avere un modello che esegue la tokenizzazione è particolarmente utile per i linguaggi CJK quando si desidera dividere in parole, ma non si dispone di spazi per fornire una guida euristica. Al momento, abbiamo un unico modello di segmentazione per il cinese.

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

Potrebbe essere difficile visualizzare i risultati delle stringhe di byte con codifica UTF-8. Decodifica i valori dell'elenco per semplificare la visualizzazione.

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))
[['新华社', '北京']]

DividiUnisciTokenizer

Lo SplitMergeTokenizer & SplitMergeFromLogitsTokenizer hanno uno scopo mirato di suddivisione di un testo in base ai valori forniti che indicano dove la stringa dovrebbe essere diviso. Ciò è utile quando si creano i propri modelli di segmentazione come il precedente esempio di segmentazione.

Per lo SplitMergeTokenizer , un valore 0 è usato per indicare l'inizio di una nuova stringa, e il valore 1 indica il carattere è parte della stringa corrente.

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

Lo SplitMergeFromLogitsTokenizer è simile, ma accetta invece coppie di valori logit da una rete neurale che predire se ogni carattere deve essere suddiviso in una nuova stringa o fusi in quello corrente.

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

Il RegexSplitter è in grado di stringhe segmenti a punti di interruzione arbitrari definiti da un'espressione regolare fornita.

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

offset

Quando si tokenizza le stringhe, spesso si desidera sapere da dove ha avuto origine il token nella stringa originale. Per questo motivo, ogni tokenizzatore che implementa TokenizerWithOffsets ha un metodo tokenize_with_offsets che restituirà gli offset di byte insieme con i gettoni. Start_offsets elenca i byte nella stringa originale da cui inizia ogni token e end_offsets elenca i byte immediatamente dopo il punto in cui termina ogni token. Per riformulare, gli offset di inizio sono inclusivi e gli offset di fine sono esclusivi.

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

detokenizzazione

Tokenizers che implementano il Detokenizer offrono un detokenize metodo che tenta di unire le stringhe. Questo ha la possibilità di essere in perdita, quindi la stringa detokenizzata potrebbe non corrispondere sempre esattamente alla stringa originale, pre-tokenizzata.

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

Dati TF

TF Data è una potente API per la creazione di una pipeline di input per i modelli di addestramento. I tokenizzatori funzionano come previsto con l'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!']]