Hugging Face Tokenizers

Hugging Face Tokenizers Hugging Face Tokenizers

Hugging Face tokenizerslink image 0

La librería tokenizers de Hugging Face proporciona una implementación de los tokenizadores más utilizados en la actualidad, centrándose en el rendimiento y la versatilidad. En el post tokens ya vimos la importancia de los tokens a la hora de procesar textos, ya que los ordenadores no entienden de palabras, sino de números. Por tanto, es necesario convertir las palabras a números para que los modelos de lenguaje puedan procesarlos.

Instalaciónlink image 1

Para instalar tokenizers con pip:

pip install tokenizers
      

para instalar tokenizers con conda:

conda install conda-forge::tokenizers
      

El pipeline de tokenizaciónlink image 2

Para tokenizar una secuencia se usa Tokenizer.encode, el cual realiza los siguientes pasos:

  • Normalización
  • pre-tokenización
  • Tokenización
  • Post-tokenización

Vamos a ver cada una

Para realizar el post vamos a usar el dataset wikitext-103

!wget https://dax-cdn.cdn.appdomain.cloud/dax-wikitext-103/1.0.1/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.gz
      Resolving dax-cdn.cdn.appdomain.cloud (dax-cdn.cdn.appdomain.cloud)... 23.200.169.125
      Connecting to dax-cdn.cdn.appdomain.cloud (dax-cdn.cdn.appdomain.cloud)|23.200.169.125|:443... connected.
      HTTP request sent, awaiting response... 
200 OK
      Length: 189603606 (181M) [application/x-gzip]
      Saving to: ‘wikitext-103.tar.gz’
      
      wikitext-103.tar.gz 100%[===================>] 180,82M  6,42MB/s    in 30s     
      
      2024-02-26 08:14:42 (5,95 MB/s) - ‘wikitext-103.tar.gz’ saved [189603606/189603606]
      
      
	
!wget https://dax-cdn.cdn.appdomain.cloud/dax-wikitext-103/1.0.1/wikitext-103.tar.gz
!tar -xvzf wikitext-103.tar.gz
Copy
	
--2024-02-26 08:14:11-- https://dax-cdn.cdn.appdomain.cloud/dax-wikitext-103/1.0.1/wikitext-103.tar.gz
Resolving dax-cdn.cdn.appdomain.cloud (dax-cdn.cdn.appdomain.cloud)... 23.200.169.125
Connecting 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.tokens
wikitext-103/wiki.valid.tokens
wikitext-103/README.txt
wikitext-103/LICENSE.txt
wikitext-103/wiki.train.tokens
	
!rm wikitext-103.tar.gz
Copy

Normalizaciónlink image 3

La normalización son operaciones que se aplican al texto antes de la tokenización, como la eliminación de espacios en blanco, la conversión a minúsculas, la eliminación de caracteres especiales, etc. En Hugging Face están implementadas las siguientes normalizaciones:

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 (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 (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 a crear un normalizador para ver cómo funciona

	
!rm wikitext-103.tar.gz
from tokenizers import normalizers
bert_normalizer = normalizers.BertNormalizer()
input_text = "Héllò hôw are ü?"
normalized_text = bert_normalizer.normalize_str(input_text)
normalized_text
Copy
	
'hello how are u?'

Para usar varios normalizadores podemos usar el método Sequence

	
custom_normalizer = normalizers.Sequence([normalizers.NFKC(), normalizers.BertNormalizer()])
normalized_text = custom_normalizer.normalize_str(input_text)
normalized_text
Copy
	
'hello how are u?'

Para modificar el normalizador de un tokenizador

	
import tokenizers
tokenizer = tokenizers.BertWordPieceTokenizer() # or any other tokenizer
Copy
	
import tokenizers
tokenizer = tokenizers.BertWordPieceTokenizer() # or any other tokenizer
tokenizer.normalizer = custom_normalizer
Copy

Pre-tokenizaciónlink image 4

La pretokenización es el acto de dividir un texto en objetos más pequeños. El pretokenizador dividirá el texto en "palabras" y los tokens finales serán partes de esas palabras.

El PreTokenizer se encarga de dividir la entrada según un conjunto de reglas. Este preprocesamiento le permite asegurarse de que el tokenizador no construye tokens a través de múltiples "divisiones". Por ejemplo, si no quieres tener espacios en blanco dentro de un token, entonces puedes tener un pre tokenizer que divide en las palabras a partir de espacios en blanco.

En Hugging Face están implementados los siguientes pre tokenizadores

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 a crear un pre tokenizador para ver cómo funciona

	
import tokenizers
tokenizer = tokenizers.BertWordPieceTokenizer() # or any other tokenizer
tokenizer.normalizer = custom_normalizer
from tokenizers import pre_tokenizers
pre_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
Copy
	
[('I paid $', (0, 8)),
('3', (8, 9)),
('0', (9, 10)),
(' for the car', (10, 22))]

Para usar varios pre tokenizadores podemos usar el 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
Copy
	
[('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 el pre tokenizador de un tokenizador

	
tokenizer.pre_tokenizer = custom_pre_tokenizer
Copy

Tokenizaciónlink image 5

Una vez normalizados y pretokenizados los textos de entrada, el tokenizador aplica el modelo a los pretokens. Esta es la parte del proceso que debe entrenarse con el corpus (o que ya se ha entrenado si se utiliza un tokenizador preentrenado).

La función del modelo es dividir las "palabras" en tokens utilizando las reglas que ha aprendido. También es responsable de asignar esos tokens a sus ID correspondientes en el vocabulario del modelo.

El modelo tiene un tamaño de vocabulario, es decir, tiene una cantidad finita de tokens, por lo que tiene que descomponer las palabras y asignarlas a uno de esos tokens.

Este modelo se pasa al inicializar el Tokenizer. Actualmente, la librería 🤗 Tokenizers soporta:

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.

Cuando se crea un tokenizador se le tiene que pasar el modelo

	
tokenizer.pre_tokenizer = custom_pre_tokenizer
from tokenizers import Tokenizer, models
tokenizer = Tokenizer(models.Unigram())
Copy

Vamos a pasarle el normalizador y el pre tokenizador que hemos creado

	
tokenizer.pre_tokenizer = custom_pre_tokenizer
from tokenizers import Tokenizer, models
tokenizer = Tokenizer(models.Unigram())
tokenizer.normalizer = custom_normalizer
tokenizer.pre_tokenizer = custom_pre_tokenizer
Copy

Ahora hay que entrenar el modelo o cargar uno preentrenado. En este caso vamos a entrenar uno con el corpus que nos hemos descargado

Entrenamiento del modelolink image 6

Para entrenar el modelo tenemos varios tipos de Trainers

Trainer Descripción
WordLevelTrainer Entrena un tokenizador WordLevel
BpeTrainer Entrena un tokenizador BPE
WordPieceTrainer Entrena un tokenizador WordPiece
UnigramTrainer Entrena un tokenizador Unigram

Casi todos los trainers tienen los mismos parámetros, que son:

  • vocab_size: El tamaño del vocabulario final, incluidos todos los tokens y el alfabeto.
  • show_progress: Mostrar o no barras de progreso durante el entrenamiento
  • special_tokens: Una lista de fichas especiales que el modelo debe conocer

A parte de estos parámetros, cada trainer tiene sus propios parámetros, para verlos mirar la documentación de los Trainers

Para entrenar tenemos que crear un Trainer, como el modelo que hemos creado es un Unigram vamos a crear un UnigramTrainer

	
tokenizer.pre_tokenizer = custom_pre_tokenizer
from tokenizers import Tokenizer, models
tokenizer = Tokenizer(models.Unigram())
tokenizer.normalizer = custom_normalizer
tokenizer.pre_tokenizer = custom_pre_tokenizer
from tokenizers.trainers import trainers
trainer = trainers.UnigramTrainer(
vocab_size=20000,
initial_alphabet=pre_tokenizers.ByteLevel.alphabet(),
special_tokens=["<PAD>", "<BOS>", "<EOS>"],
)
Copy

Una vez hemos creado el Trainer hay dos maneras de entrear, mediante el método train, al que se le pasa una lista de archivos, o mediante el método train_from_iterator al que se le pasa un iterador

Entrenamiento del modelo con el método trainlink image 7

Primero creamos una lista de archivos con el corpus

	
tokenizer.pre_tokenizer = custom_pre_tokenizer
from tokenizers import Tokenizer, models
tokenizer = Tokenizer(models.Unigram())
tokenizer.normalizer = custom_normalizer
tokenizer.pre_tokenizer = custom_pre_tokenizer
from tokenizers.trainers import trainers
trainer = 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
Copy
	
['wikitext-103/wiki.test.tokens',
'wikitext-103/wiki.train.tokens',
'wikitext-103/wiki.valid.tokens']

Y ahora entrenamos el modelo

	
tokenizer.train(files, trainer)
Copy
	
Entrenamiento del modelo con el método train_from_iteratorlink image 8

Primero creamos una función que nos devuelva un iterador

	
def iterator():
for file in files:
with open(file, "r") as f:
for line in f:
yield line
Copy

Ahora volvemos a entrenar el modelo

	
def iterator():
for file in files:
with open(file, "r") as f:
for line in f:
yield line
tokenizer.train_from_iterator(iterator(), trainer)
Copy
	
Entrenamiento del modelo con el método train_from_iterator desde un dataset de Hugging Facelink image 9

Si nos hubiésemos descargado el dataset de Hugging Face, podríamos haber entrenado el modelo directamente desde el dataset

	
import datasets
dataset = datasets.load_dataset("wikitext", "wikitext-103-raw-v1", split="train+test+validation")
Copy

Ahora podemos crear un iterador

	
import datasets
dataset = 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"]
Copy

Volvemos a entrenar el modelo

	
import datasets
dataset = 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))
Copy
	

Guardando el modelolink image 10

Una vez se ha entrenado el modelo, se puede guardar para usarlo en el futuro. Para guardar el modelo hay que hacerlo en un archivo json

	
tokenizer.save("wikitext-103-tokenizer.json")
Copy

Cargando el modelo preentrenadolink image 11

Podemos cargar un modelo preentrenado a partir de un json en vez de tener que entrenarlo

	
tokenizer.save("wikitext-103-tokenizer.json")
tokenizer.from_file("wikitext-103-tokenizer.json")
Copy
	
<tokenizers.Tokenizer at 0x7f1dd7784a30>

También podemos cargar un modelo preentrenado disponible en el Hub de Hugging Face

	
tokenizer.from_pretrained('bert-base-uncased')
Copy
	
<tokenizers.Tokenizer at 0x7f1d64a75e30>

Post procesamientolink image 12

Es posible que queramos que nuestro tokenizador añada automáticamente tokens especiales, como [CLS] o [SEP].

En Hugging Face están implementados los siguientes post procesadores

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 a crear un post tokenizador para ver cómo funciona

	
from tokenizers.processors import TemplateProcessing
post_processor = TemplateProcessing(
single="[CLS] $A [SEP]",
pair="[CLS] $A [SEP] $B:1 [SEP]:1",
special_tokens=[("[CLS]", 1), ("[SEP]", 2)],
)
Copy

Para modificar el post tokenizador de un tokenizador

	
from tokenizers.processors import TemplateProcessing
post_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
Copy

Veamos cómo funciona

	
from tokenizers.processors import TemplateProcessing
post_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
input_text = "I paid $30 for the car"
decoded_text = tokenizer.encode(input_text)
decoded_text.tokens
Copy
	
['[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)
Copy
	
['[CLS]', 'hell', 'o', ',', 'y', "'", 'all', '!', '[SEP]', 'how', 'are', 'you', '?', '[SEP]']

Si ahora guardásemos el tokenizador, el post tokenizador se guardaría con él

Encodinglink image 13

Una vez tenemos el tokenizador entrenado, podemos usarlo para tokenizar textos

	
input_text = "I love tokenizers!"
encoded_text = tokenizer.encode(input_text)
Copy

Vamos a ver qué obtenemos al tokenizar un texto

	
input_text = "I love tokenizers!"
encoded_text = tokenizer.encode(input_text)
type(encoded_text)
Copy
	
tokenizers.Encoding

Obtenemos un objeto de tipo Encoding, que contiene los tokens y los ids de los tokens

Los ids son los ids de los tokens en el vocabulario del tokenizador

	
encoded_text.ids
Copy
	
[1, 17, 383, 10694, 17, 3533, 3, 586, 2]

Los tokens son los tokens a los que equivalen los ids

	
encoded_text.tokens
Copy
	
['[CLS]', 'i', 'love', 'token', 'i', 'zer', 's', '!', '[SEP]']

Si tenemos varias secuencias podemos codificarlas todas a la vez

	
encoded_texts = tokenizer.encode(input_text1, input_text2)
print(encoded_texts.tokens)
print(encoded_texts.ids)
print(encoded_texts.type_ids)
Copy
	
['[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]

Sin embargo, cuando se tienen varias secuencias es mejor usar el método encode_batch

	
encoded_texts = tokenizer.encode_batch([input_text1, input_text2])
type(encoded_texts)
Copy
	
list

Vemos que obtenemos una lista

	
print(encoded_texts[0].tokens)
print(encoded_texts[0].ids)
print(encoded_texts[1].tokens)
print(encoded_texts[1].ids)
Copy
	
['[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]

Decodinglink image 14

Además de codificar los textos de entrada, un Tokenizer también tiene un método para decodificar, es decir, convertir los ID generados por su modelo de nuevo a un texto. Esto se hace mediante los métodos Tokenizer.decode (para un texto predicho) y Tokenizer.decode_batch (para un lote de predicciones).

Los tipos de decodificación que se pueden usar son:

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.

El decodificador convertirá primero los IDs en tokens (usando el vocabulario del tokenizador) y eliminará todos los tokens especiales, después unirá esos tokens con espacios en blanco.

Vamos a crear un decoder

	
from tokenizers import decoders
decoder = decoders.ByteLevel()
Copy

Lo añadimos al tokenizador

	
from tokenizers import decoders
decoder = decoders.ByteLevel()
tokenizer.decoder = decoder
Copy

Decodificamos

	
from tokenizers import decoders
decoder = decoders.ByteLevel()
tokenizer.decoder = decoder
decoded_text = tokenizer.decode(encoded_text.ids)
input_text, decoded_text
Copy
	
('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])
Copy
	
Hello, y'all! hello,y'all!
How are you? howareyou?

BERT tokenizerlink image 15

Con todo lo aprendido vamos a crear el tokenizador de BERT desde cero, primero creamos el tokenizador. Bert usa WordPiece como modelo, por lo que lo pasamos al inicializar del tokenizador

	
from tokenizers import Tokenizer
from tokenizers.models import WordPiece
bert_tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))
Copy

BERT preprocesa los textos eliminando los acentos y las minúsculas. También utilizamos un normalizador unicode

	
from tokenizers import Tokenizer
from tokenizers.models import WordPiece
bert_tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))
from tokenizers import normalizers
from tokenizers.normalizers import NFD, Lowercase, StripAccents
bert_tokenizer.normalizer = normalizers.Sequence([NFD(), Lowercase(), StripAccents()])
Copy

El pretokenizador sólo divide los espacios en blanco y los signos de puntuación.

	
from tokenizers import Tokenizer
from tokenizers.models import WordPiece
bert_tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))
from tokenizers import normalizers
from tokenizers.normalizers import NFD, Lowercase, StripAccents
bert_tokenizer.normalizer = normalizers.Sequence([NFD(), Lowercase(), StripAccents()])
from tokenizers.pre_tokenizers import Whitespace
bert_tokenizer.pre_tokenizer = Whitespace()
Copy

Y el post-procesamiento utiliza la plantilla que vimos en la sección anterior

	
from tokenizers import Tokenizer
from tokenizers.models import WordPiece
bert_tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))
from tokenizers import normalizers
from tokenizers.normalizers import NFD, Lowercase, StripAccents
bert_tokenizer.normalizer = normalizers.Sequence([NFD(), Lowercase(), StripAccents()])
from tokenizers.pre_tokenizers import Whitespace
bert_tokenizer.pre_tokenizer = Whitespace()
from tokenizers.processors import TemplateProcessing
bert_tokenizer.post_processor = TemplateProcessing(
single="[CLS] $A [SEP]",
pair="[CLS] $A [SEP] $B:1 [SEP]:1",
special_tokens=[
("[CLS]", 1),
("[SEP]", 2),
],
)
Copy

Entrenamos el tokenizador con el dataset de wikitext-103

	
from tokenizers import Tokenizer
from tokenizers.models import WordPiece
bert_tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))
from tokenizers import normalizers
from tokenizers.normalizers import NFD, Lowercase, StripAccents
bert_tokenizer.normalizer = normalizers.Sequence([NFD(), Lowercase(), StripAccents()])
from tokenizers.pre_tokenizers import Whitespace
bert_tokenizer.pre_tokenizer = Whitespace()
from tokenizers.processors import TemplateProcessing
bert_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 WordPieceTrainer
trainer = WordPieceTrainer(vocab_size=30522, special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"])
Copy
	
from tokenizers import Tokenizer
from tokenizers.models import WordPiece
bert_tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))
from tokenizers import normalizers
from tokenizers.normalizers import NFD, Lowercase, StripAccents
bert_tokenizer.normalizer = normalizers.Sequence([NFD(), Lowercase(), StripAccents()])
from tokenizers.pre_tokenizers import Whitespace
bert_tokenizer.pre_tokenizer = Whitespace()
from tokenizers.processors import TemplateProcessing
bert_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 WordPieceTrainer
trainer = 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)
Copy
	

Ahora lo probamos

	
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}'")
Copy
	
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 !'

Seguir leyendo

DoLa – Decoding by Contrasting Layers Improves Factuality in Large Language Models

DoLa – Decoding by Contrasting Layers Improves Factuality in Large Language Models

¿Alguna vez has hablado con un LLM y te ha respondido algo que suena como si hubiera estado bebiendo café de máquina durante toda la noche? 😂 ¡Eso es lo que llamamos una alucinación en el mundo de los LLMs! Pero no te preocupes, porque no es que tu modelo de lenguaje esté loco (aunque a veces puede parecerlo 🤪). La verdad es que los LLMs pueden ser un poco... creativos cuando se trata de generar texto. Pero gracias a DoLa, un método que utiliza capas de contraste para mejorar la factibilidad de los LLMs, podemos evitar que nuestros modelos de lenguaje se conviertan en escritores de ciencia ficción 😂. En este post, te explicaré cómo funciona DoLa y te mostraré un ejemplo de código para que puedas entender mejor cómo hacer que tus LLMs sean más fiables y menos propensos a inventar historias. ¡Vamos a salvar a nuestros LLMs de la locura y hacer que sean más útiles! 🚀

Últimos posts -->

¿Has visto estos proyectos?

Subtify

Subtify Subtify

Generador de subtítulos para videos en el idioma que desees. Además a cada persona le pone su subtítulo de un color

Ver todos los proyectos -->

¿Quieres aplicar la IA en tu proyecto? Contactame!

¿Quieres mejorar con estos tips?

Últimos tips -->

Usa esto en local

Los espacios de Hugging Face nos permite ejecutar modelos con demos muy sencillas, pero ¿qué pasa si la demo se rompe? O si el usuario la elimina? Por ello he creado contenedores docker con algunos espacios interesantes, para poder usarlos de manera local, pase lo que pase. De hecho, es posible que si pinchas en alún botón de ver proyecto te lleve a un espacio que no funciona.

Ver todos los contenedores -->

¿Quieres aplicar la IA en tu proyecto? Contactame!

¿Quieres entrenar tu modelo con estos datasets?

short-jokes-dataset

Dataset de chistes en inglés

opus100

Dataset con traducciones de inglés a español

netflix_titles

Dataset con películas y series de Netflix

Ver más datasets -->