Tokenizadores de rostos abraçados
A biblioteca Hugging Face tokenizers
fornece uma implementação dos tokenizadores mais usados atualmente, com foco no desempenho e na versatilidade. Na postagem tokens, já vimos a importância dos tokens no processamento de texto, pois os computadores não entendem palavras, mas números. Portanto, é necessário converter palavras em números para que os modelos de linguagem possam processá-las.
Este caderno foi traduzido automaticamente para torná-lo acessível a mais pessoas, por favor me avise se você vir algum erro de digitação..
Instalação
Para instalar o tokenizers
com o pip:
pip install tokenizers
```
para instalar o `tokenizers` com o conda:
````bash
conda install conda-forge::tokenizers
```
O pipeline de tokenização
Para tokenizar uma sequência, é usado o Tokenizer.encode
, que executa as seguintes etapas:
- Padronização
- pré-tokenização
- Tokenização
- Pós-tokenização
Vamos dar uma olhada em cada um deles
Para esta postagem, usaremos o conjunto de dados [wikitext-103] (https://blog.einstein.ai/the-wikitext-long-term-dependency-language-modeling-dataset/)
!wget https://dax-cdn.cdn.appdomain.cloud/dax-wikitext-103/1.0.1/wikitext-103.tar.gz
!wget https://dax-cdn.cdn.appdomain.cloud/dax-wikitext-103/1.0.1/wikitext-103.tar.gz!tar -xvzf wikitext-103.tar.gz
--2024-02-26 08:14:11-- https://dax-cdn.cdn.appdomain.cloud/dax-wikitext-103/1.0.1/wikitext-103.tar.gzResolving dax-cdn.cdn.appdomain.cloud (dax-cdn.cdn.appdomain.cloud)... 23.200.169.125Connecting to dax-cdn.cdn.appdomain.cloud (dax-cdn.cdn.appdomain.cloud)|23.200.169.125|:443... connected.HTTP request sent, awaiting response...wikitext-103/wikitext-103/wiki.test.tokenswikitext-103/wiki.valid.tokenswikitext-103/README.txtwikitext-103/LICENSE.txtwikitext-103/wiki.train.tokens
!rm wikitext-103.tar.gz
Padronização
As normalizações são operações aplicadas ao texto antes da tokenização, como a remoção de espaços em branco, a conversão para letras minúsculas, a remoção de caracteres especiais etc. As seguintes normalizações são implementadas no Hugging Face:
Normalización | Descripción | Ejemplo |
---|---|---|
NFD (Normalization for D) | Los caracteres se descomponen por equivalencia canónica | â (U+00E2) se descompone en a (U+0061) + ^ (U+0302) |
NFKD (Normalization Form KD) | Los caracteres se descomponen por compatibilidad | fi (U+FB01) se descompone en f (U+0066) + i (U+0069) |
NFC (Normalization Form C) | Los caracteres se descomponen y luego se recomponen por equivalencia canónica | â (U+00E2) se descompone en a (U+0061) + ^ (U+0302) y luego se recompone en â (U+00E2) |
NFKC (Normalization Form KC) | Los caracteres se descomponen por compatibilidad y luego se recomponen por equivalencia canónica | fi (U+FB01) se descompone en f (U+0066) + i (U+0069) y luego se recompone en f (U+0066) + i (U+0069) |
Lowercase | Convierte el texto a minúsculas | Hello World se convierte en hello world |
Strip | Elimina todos los espacios en blanco de los lados especificados (izquierdo, derecho o ambos) del texto | Hello World se convierte en Hello World |
StripAccents | Elimina todos los símbolos de acento en unicode (se utilizará con NFD por coherencia) | á (U+00E1) se convierte en a (U+0061) |
Replace | Sustituye una cadena personalizada o regex y la cambia por el contenido dado | Hello World se convierte en Hello Universe |
BertNormalizer | Proporciona una implementación del Normalizador utilizado en el BERT original. Las opciones que se pueden configurar son clean_text , handle_chinese_chars , strip_accents y lowercase | Hello World se convierte en hello world |
Vamos criar um normalizador para ver como ele funciona.
!rm wikitext-103.tar.gzfrom tokenizers import normalizersbert_normalizer = normalizers.BertNormalizer()input_text = "Héllò hôw are ü?"normalized_text = bert_normalizer.normalize_str(input_text)normalized_text
'hello how are u?'
Para usar vários normalizadores, podemos usar o método Sequence
.
custom_normalizer = normalizers.Sequence([normalizers.NFKC(), normalizers.BertNormalizer()])normalized_text = custom_normalizer.normalize_str(input_text)normalized_text
'hello how are u?'
Para modificar o normalizador de um tokenizador
import tokenizerstokenizer = tokenizers.BertWordPieceTokenizer() # or any other tokenizer
import tokenizerstokenizer = tokenizers.BertWordPieceTokenizer() # or any other tokenizertokenizer.normalizer = custom_normalizer
Pré-tokenização
Pretokenização é o ato de dividir o texto em objetos menores. O pretokenizador dividirá o texto em "palavras" e os tokens finais serão partes dessas palavras.
O PreTokenizer se encarrega de dividir a entrada de acordo com um conjunto de regras. Esse pré-processamento permite que você garanta que o tokenizador não crie tokens em várias "divisões". Por exemplo, se você não quiser ter espaços em branco em um token, poderá ter um pré-tokenizador que divida as palavras em espaços em branco.
Os seguintes pré-tokenizadores são implementados no Hugging Face
PreTokenizer | Descripción | Ejemplo |
---|---|---|
ByteLevel | Divide en espacios en blanco mientras reasigna todos los bytes a un conjunto de caracteres visibles. Esta técnica fue introducida por OpenAI con GPT-2 y tiene algunas propiedades más o menos buenas: Como mapea sobre bytes, un tokenizador que utilice esto sólo requiere 256 caracteres como alfabeto inicial (el número de valores que puede tener un byte), frente a los más de 130.000 caracteres Unicode. Una consecuencia del punto anterior es que es absolutamente innecesario tener un token desconocido usando esto ya que podemos representar cualquier cosa con 256 tokens. Para caracteres no ascii, se vuelve completamente ilegible, ¡pero funciona! | Hello my friend, how are you? se divide en Hello , Ġmy , Ġfriend , , , Ġhow , Ġare , Ġyou , ? |
Whitespace | Divide en límites de palabra usando la siguiente expresión regular: \w+[^\w\s]+ . En mi post sobre expresiones regulares puedes entender qué hace | Hello there! se divide en Hello , there , ! |
WhitespaceSplit | Se divide en cualquier carácter de espacio en blanco | Hello there! se divide en Hello , there! |
Punctuation | Aislará todos los caracteres de puntuación | Hello? se divide en Hello , ? |
Metaspace | Separa los espacios en blanco y los sustituye por un carácter especial "▁" (U+2581) | Hello there se divide en Hello , ▁there |
CharDelimiterSplit | Divisiones en un carácter determinado | Ejemplo con el caracter x : Helloxthere se divide en Hello , there |
Digits | Divide los números de cualquier otro carácter | Hello123there se divide en Hello , 123 , there |
Split | Pretokenizador versátil que divide según el patrón y el comportamiento proporcionados. El patrón se puede invertir si es necesario. El patrón debe ser una cadena personalizada o una regex. El comportamiento debe ser removed , isolated , merged_with_previous , merged_with_next , contiguous . Para invertir se indica con un booleano | Ejemplo con pattern=" " , behavior=isolated , invert=False : Hello, how are you? se divide en Hello, , , how , , are , , you? |
Vamos criar um pré-tokenizador para ver como ele funciona.
import tokenizerstokenizer = tokenizers.BertWordPieceTokenizer() # or any other tokenizertokenizer.normalizer = custom_normalizerfrom tokenizers import pre_tokenizerspre_tokenizer = pre_tokenizers.Digits(individual_digits=True)input_text = "I paid $30 for the car"pre_tokenized_text = pre_tokenizer.pre_tokenize_str(input_text)pre_tokenized_text
[('I paid $', (0, 8)),('3', (8, 9)),('0', (9, 10)),(' for the car', (10, 22))]
Para usar vários pré-tokenizadores, podemos usar o método Sequence
.
custom_pre_tokenizer = pre_tokenizers.Sequence([pre_tokenizers.Whitespace(), pre_tokenizers.Digits(individual_digits=True)])pre_tokenized_text = custom_pre_tokenizer.pre_tokenize_str(input_text)pre_tokenized_text
[('I', (0, 1)),('paid', (2, 6)),('$', (7, 8)),('3', (8, 9)),('0', (9, 10)),('for', (11, 14)),('the', (15, 18)),('car', (19, 22))]
Para modificar o pré-tokenizador de um tokenizador
tokenizer.pre_tokenizer = custom_pre_tokenizer
Tokenização
Depois que os textos de entrada tiverem sido normalizados e pré-tokenizados, o tokenizador aplica o modelo aos pré-tokens. Essa é a parte do processo que precisa ser treinada no corpus (ou já foi treinada se for usado um tokenizador pré-treinado).
A função do modelo é dividir as "palavras" em tokens usando as regras que aprendeu. Ele também é responsável por atribuir esses tokens às suas IDs correspondentes no vocabulário do modelo.
O modelo tem um tamanho de vocabulário, ou seja, tem um número finito de tokens, portanto, precisa decompor as palavras e atribuí-las a um desses tokens.
Esse modelo é passado quando o Tokenizer é inicializado. Atualmente, a biblioteca 🤗 Tokenizers é compatível:
Modelo | Descripción |
---|---|
WordLevel | Este es el algoritmo "clásico" de tokenización. Te permite simplemente asignar palabras a IDs sin nada sofisticado. Tiene la ventaja de ser muy fácil de usar y entender, pero requiere vocabularios extremadamente grandes para una buena cobertura. El uso de este modelo requiere el uso de un PreTokenizer. Este modelo no realiza ninguna elección directamente, simplemente asigna tokens de entrada a IDs. |
BPE (Byte Pair Encoding) | Uno de los algoritmos de tokenización de subpalabras más populares. El Byte-Pair-Encoding funciona empezando con caracteres y fusionando los que se ven juntos con más frecuencia, creando así nuevos tokens. A continuación, trabaja de forma iterativa para construir nuevos tokens a partir de los pares más frecuentes que ve en un corpus. BPE es capaz de construir palabras que nunca ha visto utilizando múltiples subpalabras y, por tanto, requiere vocabularios más pequeños, con menos posibilidades de tener palabras unk (desconocidas). |
WordPiece | Se trata de un algoritmo de tokenización de subpalabras bastante similar a BPE, utilizado principalmente por Google en modelos como BERT. Utiliza un algoritmo codicioso que intenta construir primero palabras largas, dividiéndolas en varios tokens cuando no existen palabras completas en el vocabulario. A diferencia de BPE, que parte de los caracteres y construye tokens lo más grandes posible. Utiliza el famoso prefijo ## para identificar los tokens que forman parte de una palabra (es decir, que no empiezan una palabra). |
Unigram | Unigram es también un algoritmo de tokenización de subpalabras, y funciona tratando de identificar el mejor conjunto de tokens de subpalabras para maximizar la probabilidad de una frase dada. Se diferencia de BPE en que no es un algoritmo determinista basado en un conjunto de reglas aplicadas secuencialmente. En su lugar, Unigram podrá calcular múltiples formas de tokenizar, eligiendo la más probable. |
Quando você cria um tokenizador, precisa passar a ele o modelo
tokenizer.pre_tokenizer = custom_pre_tokenizerfrom tokenizers import Tokenizer, modelstokenizer = Tokenizer(models.Unigram())
Passaremos o normalizador e o pré-tokenizador que criamos para ele.
tokenizer.pre_tokenizer = custom_pre_tokenizerfrom tokenizers import Tokenizer, modelstokenizer = Tokenizer(models.Unigram())tokenizer.normalizer = custom_normalizertokenizer.pre_tokenizer = custom_pre_tokenizer
Agora temos que treinar o modelo ou carregar um modelo pré-treinado. Neste caso, vamos treinar um modelo com o corpus que baixamos.
Treinamento de modelos
Para treinar o modelo, temos vários tipos de "treinadores".
Trainer | Descripción |
---|---|
WordLevelTrainer | Entrena un tokenizador WordLevel |
BpeTrainer | Entrena un tokenizador BPE |
WordPieceTrainer | Entrena un tokenizador WordPiece |
UnigramTrainer | Entrena un tokenizador Unigram |
Quase todos os treinadores têm os mesmos parâmetros, que são:
- vocab_size: o tamanho do vocabulário final, incluindo todos os tokens e o alfabeto.
- show_progress: Mostrar ou não barras de progresso durante o treinamento
- special_tokens: Uma lista de tokens especiais dos quais o modelo deve estar ciente.
Além desses parâmetros, cada treinador tem seus próprios parâmetros; consulte a documentação Trainers para obter mais informações.
Para treinar, precisamos criar um Trainer
. Como o modelo que criamos é um Unigram
, criaremos um UnigramTrainer
.
tokenizer.pre_tokenizer = custom_pre_tokenizerfrom tokenizers import Tokenizer, modelstokenizer = Tokenizer(models.Unigram())tokenizer.normalizer = custom_normalizertokenizer.pre_tokenizer = custom_pre_tokenizerfrom tokenizers.trainers import trainerstrainer = trainers.UnigramTrainer(vocab_size=20000,initial_alphabet=pre_tokenizers.ByteLevel.alphabet(),special_tokens=["<PAD>", "<BOS>", "<EOS>"],)
Depois de criarmos o Trainer
, há duas maneiras de entrar, usando o método train
, que recebe uma lista de arquivos, ou usando o método train_from_iterator
, que recebe um iterador.
Treinamento do modelo com o método train
.
Primeiro, criamos uma lista de arquivos com o corpus
tokenizer.pre_tokenizer = custom_pre_tokenizerfrom tokenizers import Tokenizer, modelstokenizer = Tokenizer(models.Unigram())tokenizer.normalizer = custom_normalizertokenizer.pre_tokenizer = custom_pre_tokenizerfrom tokenizers.trainers import trainerstrainer = trainers.UnigramTrainer(vocab_size=20000,initial_alphabet=pre_tokenizers.ByteLevel.alphabet(),special_tokens=["<PAD>", "<BOS>", "<EOS>"],)files = [f"wikitext-103/wiki.{split}.tokens" for split in ["test", "train", "valid"]]files
['wikitext-103/wiki.test.tokens','wikitext-103/wiki.train.tokens','wikitext-103/wiki.valid.tokens']
E agora treinamos o modelo
tokenizer.train(files, trainer)
Treinamento do modelo com o método train_from_iterator
.
Primeiro, criamos uma função que retorna um iterador.
def iterator():for file in files:with open(file, "r") as f:for line in f:yield line
Agora, treinamos novamente o modelo
def iterator():for file in files:with open(file, "r") as f:for line in f:yield linetokenizer.train_from_iterator(iterator(), trainer)
Treinamento do modelo com o método train_from_iterator
a partir de um conjunto de dados Hugging Face
Se tivéssemos baixado o conjunto de dados Hugging Face, poderíamos ter treinado o modelo diretamente do conjunto de dados.
import datasetsdataset = datasets.load_dataset("wikitext", "wikitext-103-raw-v1", split="train+test+validation")
Agora podemos criar um iterador
import datasetsdataset = datasets.load_dataset("wikitext", "wikitext-103-raw-v1", split="train+test+validation")def batch_iterator(batch_size=1000):for i in range(0, len(dataset), batch_size):yield dataset[i : i + batch_size]["text"]
Treinamos novamente o modelo
import datasetsdataset = datasets.load_dataset("wikitext", "wikitext-103-raw-v1", split="train+test+validation")def batch_iterator(batch_size=1000):for i in range(0, len(dataset), batch_size):yield dataset[i : i + batch_size]["text"]tokenizer.train_from_iterator(batch_iterator(), trainer=trainer, length=len(dataset))
Salvando o modelo
Depois que o modelo tiver sido treinado, ele poderá ser salvo para uso futuro. Para salvar o modelo, é necessário salvá-lo em um arquivo json
.
tokenizer.save("wikitext-103-tokenizer.json")
Carregando o modelo pré-treinado
Podemos carregar um modelo pré-treinado a partir de um json
em vez de precisar treiná-lo.
tokenizer.save("wikitext-103-tokenizer.json")tokenizer.from_file("wikitext-103-tokenizer.json")
<tokenizers.Tokenizer at 0x7f1dd7784a30>
Também podemos carregar um modelo pré-treinado disponível no Hugging Face Hub.
tokenizer.from_pretrained('bert-base-uncased')
<tokenizers.Tokenizer at 0x7f1d64a75e30>
Pós-processamento
Talvez queiramos que nosso tokenizador adicione automaticamente tokens especiais, como [CLS]
ou [SEP]
.
Os seguintes pós-processadores são implementados no Hugging Face
PostProcesador | Descripción | Ejemplo |
---|---|---|
BertProcessing | Este post-procesador se encarga de añadir los tokens especiales que necesita un modelo Bert (SEP y CLS ) | Hello, how are you? se convierte en [CLS] , Hello , , , how , are , you , ? , [SEP] |
RobertaProcessing | Este post-procesador se encarga de añadir los tokens especiales que necesita un modelo Roberta (SEP y CLS ). También se encarga de recortar los offsets. Por defecto, el ByteLevel BPE puede incluir espacios en blanco en los tokens producidos. Si no desea que las compensaciones incluyan estos espacios en blanco, hay que inicializar este PostProcessor con trim_offsets=True . | Hello, how are you? se convierte en <s> , Hello , , , how , are , you , ? , </s> |
ElectraProcessing | Añade tokens especiales para ELECTRA | Hello, how are you? se convierte en [CLS] , Hello , , , how , are , you , ? , [SEP] |
TemplateProcessing | Permite crear fácilmente una plantilla para el postprocesamiento, añadiendo tokens especiales y especificando el type_id de cada secuencia/token especial. La plantilla recibe dos cadenas que representan la secuencia única y el par de secuencias, así como un conjunto de tokens especiales a utilizar | Example, when specifying a template with these values: single:[CLS] $A [SEP] , pair: [CLS] $A [SEP] $B [SEP] , special tokens: [CLS] , [SEP] . Input: (I like this , but not this ), Output: [CLS] I like this [SEP] but not this [SEP] |
Vamos criar um tokenizador de postagem para ver como ele funciona.
from tokenizers.processors import TemplateProcessingpost_processor = TemplateProcessing(single="[CLS] $A [SEP]",pair="[CLS] $A [SEP] $B:1 [SEP]:1",special_tokens=[("[CLS]", 1), ("[SEP]", 2)],)
Para modificar o tokenizador de postagem de um tokenizador
from tokenizers.processors import TemplateProcessingpost_processor = TemplateProcessing(single="[CLS] $A [SEP]",pair="[CLS] $A [SEP] $B:1 [SEP]:1",special_tokens=[("[CLS]", 1), ("[SEP]", 2)],)tokenizer.post_processor = post_processor
Vamos ver como funciona
from tokenizers.processors import TemplateProcessingpost_processor = TemplateProcessing(single="[CLS] $A [SEP]",pair="[CLS] $A [SEP] $B:1 [SEP]:1",special_tokens=[("[CLS]", 1), ("[SEP]", 2)],)tokenizer.post_processor = post_processorinput_text = "I paid $30 for the car"decoded_text = tokenizer.encode(input_text)decoded_text.tokens
['[CLS]', 'i', 'paid', '$', '3', '0', 'for', 'the', 'car', '[SEP]']
input_text1 = "Hello, y'all!"input_text2 = "How are you?"decoded_text = tokenizer.encode(input_text1, input_text2)print(decoded_text.tokens)
['[CLS]', 'hell', 'o', ',', 'y', "'", 'all', '!', '[SEP]', 'how', 'are', 'you', '?', '[SEP]']
Se salvarmos o tokenizador agora, o tokenizador de postagem será salvo com ele.
Codificação
Depois de treinar o tokenizador, podemos usá-lo para tokenizar textos.
input_text = "I love tokenizers!"encoded_text = tokenizer.encode(input_text)
Vejamos o que obtemos ao tokenizar um texto
input_text = "I love tokenizers!"encoded_text = tokenizer.encode(input_text)type(encoded_text)
tokenizers.Encoding
Obtemos um objeto do tipo Encoding, contendo os tokens e os ids dos tokens.
Os ids
são os id
s dos tokens no vocabulário do tokenizador.
encoded_text.ids
[1, 17, 383, 10694, 17, 3533, 3, 586, 2]
Tokens são os tokens aos quais os ids
são equivalentes.
encoded_text.tokens
['[CLS]', 'i', 'love', 'token', 'i', 'zer', 's', '!', '[SEP]']
Se tivermos várias sequências, poderemos codificá-las todas de uma vez
encoded_texts = tokenizer.encode(input_text1, input_text2)print(encoded_texts.tokens)print(encoded_texts.ids)print(encoded_texts.type_ids)
['[CLS]', 'hell', 'o', ',', 'y', "'", 'all', '!', '[SEP]', 'how', 'are', 'you', '?', '[SEP]'][1, 2215, 7, 5, 22, 26, 81, 586, 2, 98, 59, 213, 902, 2][0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
No entanto, quando você tem várias sequências, é melhor usar o método encode_batch
.
encoded_texts = tokenizer.encode_batch([input_text1, input_text2])type(encoded_texts)
list
Vemos que obtemos uma lista
print(encoded_texts[0].tokens)print(encoded_texts[0].ids)print(encoded_texts[1].tokens)print(encoded_texts[1].ids)
['[CLS]', 'hell', 'o', ',', 'y', "'", 'all', '!', '[SEP]'][1, 2215, 7, 5, 22, 26, 81, 586, 2]['[CLS]', 'how', 'are', 'you', '?', '[SEP]'][1, 98, 59, 213, 902, 2]
Decodificação
Além de codificar os textos de entrada, um Tokenizer também tem um método para decodificar, ou seja, converter os IDs gerados pelo seu modelo de volta para um texto. Isso é feito pelos métodos Tokenizer.decode
(para um texto previsto) e Tokenizer.decode_batch
(para um lote de previsões).
Os tipos de decodificação que podem ser usados são:
Decodificación | Descripción |
---|---|
BPEDecoder | Revierte el modelo BPE |
ByteLevel | Revierte el ByteLevel PreTokenizer. Este PreTokenizer codifica a nivel de byte, utilizando un conjunto de caracteres Unicode visibles para representar cada byte, por lo que necesitamos un Decoder para revertir este proceso y obtener algo legible de nuevo. |
CTC | Revierte el modelo CTC |
Metaspace | Revierte el PreTokenizer de Metaspace. Este PreTokenizer utiliza un identificador especial ▁ para identificar los espacios en blanco, por lo que este Decoder ayuda con la decodificación de estos. |
WordPiece | Revierte el modelo WordPiece. Este modelo utiliza un identificador especial ## para las subpalabras continuas, por lo que este decodificador ayuda a decodificarlas. |
O decodificador primeiro converterá os IDs em tokens (usando o vocabulário do tokenizador) e removerá todos os tokens especiais e, em seguida, juntará esses tokens com espaços em branco.
Vamos criar um decodificador
from tokenizers import decodersdecoder = decoders.ByteLevel()
Nós o adicionamos ao tokenizador
from tokenizers import decodersdecoder = decoders.ByteLevel()tokenizer.decoder = decoder
Nós decodificamos
from tokenizers import decodersdecoder = decoders.ByteLevel()tokenizer.decoder = decoderdecoded_text = tokenizer.decode(encoded_text.ids)input_text, decoded_text
('I love tokenizers!', 'ilovetokenizers!')
decoded_texts = tokenizer.decode_batch([encoded_texts[0].ids, encoded_texts[1].ids])print(input_text1, decoded_texts[0])print(input_text2, decoded_texts[1])
Hello, y'all! hello,y'all!How are you? howareyou?
BERT tokenizer
Com tudo o que aprendemos, vamos criar o tokenizador BERT do zero. O Bert usa o WordPiece
como modelo, então o passamos para o inicializador do tokenizador.
from tokenizers import Tokenizerfrom tokenizers.models import WordPiecebert_tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))
O BERT pré-processa os textos removendo acentos e letras minúsculas. Também usamos um normalizador unicode
from tokenizers import Tokenizerfrom tokenizers.models import WordPiecebert_tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))from tokenizers import normalizersfrom tokenizers.normalizers import NFD, Lowercase, StripAccentsbert_tokenizer.normalizer = normalizers.Sequence([NFD(), Lowercase(), StripAccents()])
O pretokenizador divide apenas espaços em branco e sinais de pontuação.
from tokenizers import Tokenizerfrom tokenizers.models import WordPiecebert_tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))from tokenizers import normalizersfrom tokenizers.normalizers import NFD, Lowercase, StripAccentsbert_tokenizer.normalizer = normalizers.Sequence([NFD(), Lowercase(), StripAccents()])from tokenizers.pre_tokenizers import Whitespacebert_tokenizer.pre_tokenizer = Whitespace()
E o pós-processamento usa o modelo que vimos na seção anterior
from tokenizers import Tokenizerfrom tokenizers.models import WordPiecebert_tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))from tokenizers import normalizersfrom tokenizers.normalizers import NFD, Lowercase, StripAccentsbert_tokenizer.normalizer = normalizers.Sequence([NFD(), Lowercase(), StripAccents()])from tokenizers.pre_tokenizers import Whitespacebert_tokenizer.pre_tokenizer = Whitespace()from tokenizers.processors import TemplateProcessingbert_tokenizer.post_processor = TemplateProcessing(single="[CLS] $A [SEP]",pair="[CLS] $A [SEP] $B:1 [SEP]:1",special_tokens=[("[CLS]", 1),("[SEP]", 2),],)
Treinamos o tokenizador com o conjunto de dados wikitext-103.
from tokenizers import Tokenizerfrom tokenizers.models import WordPiecebert_tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))from tokenizers import normalizersfrom tokenizers.normalizers import NFD, Lowercase, StripAccentsbert_tokenizer.normalizer = normalizers.Sequence([NFD(), Lowercase(), StripAccents()])from tokenizers.pre_tokenizers import Whitespacebert_tokenizer.pre_tokenizer = Whitespace()from tokenizers.processors import TemplateProcessingbert_tokenizer.post_processor = TemplateProcessing(single="[CLS] $A [SEP]",pair="[CLS] $A [SEP] $B:1 [SEP]:1",special_tokens=[("[CLS]", 1),("[SEP]", 2),],)from tokenizers.trainers import WordPieceTrainertrainer = WordPieceTrainer(vocab_size=30522, special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"])
from tokenizers import Tokenizerfrom tokenizers.models import WordPiecebert_tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))from tokenizers import normalizersfrom tokenizers.normalizers import NFD, Lowercase, StripAccentsbert_tokenizer.normalizer = normalizers.Sequence([NFD(), Lowercase(), StripAccents()])from tokenizers.pre_tokenizers import Whitespacebert_tokenizer.pre_tokenizer = Whitespace()from tokenizers.processors import TemplateProcessingbert_tokenizer.post_processor = TemplateProcessing(single="[CLS] $A [SEP]",pair="[CLS] $A [SEP] $B:1 [SEP]:1",special_tokens=[("[CLS]", 1),("[SEP]", 2),],)from tokenizers.trainers import WordPieceTrainertrainer = WordPieceTrainer(vocab_size=30522, special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"])files = [f"wikitext-103/wiki.{split}.tokens" for split in ["test", "train", "valid"]]bert_tokenizer.train(files, trainer)
Agora vamos testá-lo
input_text = "I love tokenizers!"encoded_text = bert_tokenizer.encode(input_text)decoded_text = bert_tokenizer.decode(encoded_text.ids)print(f"El texto de entrada '{input_text}' se convierte en los tokens {encoded_text.tokens}, que tienen las ids {encoded_text.ids} y luego se decodifica como '{decoded_text}'")
El texto de entrada 'I love tokenizers!' se convierte en los tokens ['[CLS]', 'i', 'love', 'token', '##izers', '!', '[SEP]'], que tienen las ids [1, 51, 2867, 25791, 12213, 5, 2] y luego se decodifica como 'i love token ##izers !'