Phase 05 - Lesson 19
Tokenización de subpalabras — BPE, WordPiece, Unigram, SentencePiece
This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.
Los tokenizadores de palabras se atascan con palabras desconocidas. Los tokenizadores de caracteres disparan la longitud de la secuencia. Los tokenizadores de subpalabras encuentran el punto medio. Todo LLM moderno se distribuye con uno.
Tipo: Aprender Lenguajes: Python Prerrequisitos: Fase 5 · 01 (Procesamiento de Texto), Fase 5 · 04 (GloVe / FastText / Subpalabra) Tiempo: ~60 minutos
El Problema
Tu vocabulario tiene 50.000 palabras. Un usuario escribe "untokenizable". Tu tokenizador devuelve [UNK]. El modelo ahora no tiene ninguna señal sobre la palabra. Peor aún: el documento en el percentil 90 de tu corpus tiene 40 palabras raras, lo que significa 40 bits de información descartada por documento.
La tokenización de subpalabras resuelve esto. Las palabras comunes se mantienen como tokens únicos. Las palabras raras se descomponen en piezas significativas: untokenizable → un, token, izable. Los datos de entrenamiento lo cubren todo porque cualquier cadena es, en última instancia, una secuencia de bytes.
Todo LLM de frontera en 2026 se distribuye con uno de tres algoritmos (BPE, Unigram, WordPiece), envuelto en una de tres bibliotecas (tiktoken, SentencePiece, HF Tokenizers). No puedes lanzar un modelo de lenguaje sin elegir uno.
El Concepto
BPE (Byte-Pair Encoding). Comienza con un vocabulario a nivel de carácter. Cuenta cada par adyacente. Fusiona el par más frecuente en un nuevo token. Repite hasta alcanzar el tamaño de vocabulario objetivo. Algoritmo dominante: GPT-2/3/4, Llama, Gemma, Qwen2, Mistral.
BPE a nivel de byte. El mismo algoritmo pero sobre bytes en bruto (256 tokens base) en lugar de caracteres Unicode. Garantiza cero tokens [UNK] — cualquier secuencia de bytes se puede codificar. GPT-2 usa 50.257 tokens (256 bytes + 50.000 fusiones + 1 especial).
Unigram. Comienza con un vocabulario enorme. Asigna a cada token una probabilidad unigram. Poda iterativamente los tokens cuya eliminación menos incrementa la log-verosimilitud del corpus. Probabilístico en la inferencia: puede muestrear tokenizaciones (útil para aumento de datos mediante regularización de subpalabras). Usado por T5, mBART, ALBERT, XLNet, Gemma.
WordPiece. Fusiona pares que maximizan la verosimilitud del corpus de entrenamiento en lugar de la frecuencia en bruto. Usado por BERT, DistilBERT, ELECTRA.
SentencePiece vs tiktoken. SentencePiece es la biblioteca que entrena vocabularios (BPE o Unigram) directamente sobre texto Unicode en bruto, codificando los espacios en blanco como ▁. tiktoken es el codificador rápido de OpenAI contra vocabularios preconstruidos; no entrena.
Regla general:
- Entrenar un vocabulario nuevo: SentencePiece (multilingüe, sin pre-tokenización) o HF Tokenizers.
- Inferencia rápida contra el vocabulario de GPT: tiktoken (cl100k_base, o200k_base).
- Ambos: HF Tokenizers — una biblioteca, entrenamiento + servicio.
Constrúyelo
Paso 1: BPE desde cero
Ver code/main.py. El bucle:
def train_bpe(corpus, num_merges):
vocab = {tuple(word) + ("</w>",): count for word, count in corpus.items()}
merges = []
for _ in range(num_merges):
pairs = Counter()
for symbols, freq in vocab.items():
for a, b in zip(symbols, symbols[1:]):
pairs[(a, b)] += freq
if not pairs:
break
best = pairs.most_common(1)[0][0]
merges.append(best)
vocab = apply_merge(vocab, best)
return merges
Tres hechos que el algoritmo codifica. </w> marca el fin de la palabra para que "low" (sufijo) y "lower" (prefijo) se mantengan distintos. La ponderación por frecuencia hace que los pares de alta frecuencia ganen temprano. La lista de fusiones está ordenada — la inferencia aplica las fusiones en el orden del entrenamiento.
Paso 2: codificar con las fusiones aprendidas
def encode_bpe(word, merges):
symbols = list(word) + ["</w>"]
for a, b in merges:
i = 0
while i < len(symbols) - 1:
if symbols[i] == a and symbols[i + 1] == b:
symbols = symbols[:i] + [a + b] + symbols[i + 2:]
else:
i += 1
return symbols
Ingenuo, O(n·|merges|). Las implementaciones de producción (tiktoken, HF Tokenizers) usan búsqueda por rango de fusión con colas de prioridad y se ejecutan en tiempo casi lineal.
Paso 3: SentencePiece en la práctica
import sentencepiece as spm
spm.SentencePieceTrainer.train(
input="corpus.txt",
model_prefix="my_tokenizer",
vocab_size=8000,
model_type="bpe", # or "unigram"
character_coverage=0.9995, # lower for CJK (e.g. 0.9995 for English, 0.995 for Japanese)
normalization_rule_name="nmt_nfkc",
)
sp = spm.SentencePieceProcessor(model_file="my_tokenizer.model")
print(sp.encode("untokenizable", out_type=str))
# ['▁un', 'token', 'izable']
Observa: no se requiere pre-tokenización, el espacio se codifica como ▁, character_coverage controla con qué agresividad se preservan los caracteres raros en lugar de mapearse a <unk>.
Paso 4: tiktoken para vocabularios compatibles con OpenAI
import tiktoken
enc = tiktoken.get_encoding("o200k_base")
print(enc.encode("untokenizable")) # [127340, 101028]
print(len(enc.encode("Hello, world!"))) # 4
Solo codificación. Rápido (backend en Rust). Coincidencia exacta con la tokenización de GPT-4/5 para conteo de bytes, estimación de costos y presupuesto de ventana de contexto.
Trampas que aún llegan a producción en 2026
- Deriva del tokenizador (tokenizer drift). Entrenar con el vocabulario A, desplegar contra el vocabulario B. Los IDs de token difieren; el modelo produce basura. Verifica el hash de
tokenizer.jsonen la CI. - Ambigüedad de espacios en blanco. "hello" vs " hello" en BPE producen tokens diferentes. Especifica siempre
add_special_tokensyadd_prefix_spacede forma explícita. - Subentrenamiento multilingüe. Los corpus dominados por el inglés producen vocabularios que dividen los sistemas de escritura no latinos en 5 a 10 veces más tokens. El mismo prompt cuesta de 5 a 10 veces más en japonés/árabe en GPT-3.5. o200k_base corrigió esto parcialmente.
- Divisiones de emoji. Un solo emoji puede ocupar 5 tokens. Verifica el manejo de emojis al presupuestar el contexto.
Úsalo
El stack de 2026:
| Situación | Elección |
|---|---|
| Entrenar un modelo monolingüe desde cero | HF Tokenizers (BPE) |
| Entrenar un modelo multilingüe | SentencePiece (Unigram, character_coverage=0.9995) |
| Servir una API compatible con OpenAI | tiktoken (o200k_base para GPT-4+) |
| Vocabulario específico de dominio (código, matemáticas, proteínas) | Entrena un BPE personalizado en el corpus del dominio, fusiónalo con el vocabulario base |
| Inferencia en el borde (edge), modelo pequeño | Unigram (los vocabularios más pequeños funcionan mejor) |
El tamaño del vocabulario es una decisión de escalado, no una constante. Heurística aproximada: 32k para <1B de parámetros, 50-100k para 1-10B, 200k+ para multilingüe/frontera.
Entrégalo
Guarda como outputs/skill-tokenizer-picker.md:
---
name: tokenizer-picker
description: Pick tokenizer algorithm, vocab size, library for a given corpus and deployment target.
version: 1.0.0
phase: 5
lesson: 19
tags: [nlp, tokenization]
---
Given a corpus (size, languages, domain) and deployment target (training from scratch / fine-tuning / API-compatible inference), output:
1. Algorithm. BPE, Unigram, or WordPiece. One-sentence reason.
2. Library. SentencePiece, HF Tokenizers, or tiktoken. Reason.
3. Vocab size. Rounded to nearest 1k. Reason tied to model size and language coverage.
4. Coverage settings. `character_coverage`, `byte_fallback`, special-token list.
5. Validation plan. Average tokens-per-word on held-out set, OOV rate, compression ratio, round-trip decode equality.
Refuse to train a character-coverage <0.995 tokenizer on corpora with rare-script content. Refuse to ship a vocab without a frozen `tokenizer.json` hash check in CI. Flag any monolingual tokenizer under 16k vocab as likely under-spec.
Ejercicios
- Fácil. Entrena un BPE de 500 fusiones en el pequeño corpus de
code/main.py. Codifica tres palabras reservadas (held-out). ¿Cuántas produjeron exactamente 1 token vs >1 token? - Medio. Compara los conteos de tokens en 100 oraciones de la Wikipedia en inglés entre
cl100k_base,o200k_basey un BPE de SentencePiece que entrenes con vocab=32k. Reporta la razón de compresión de cada uno. - Difícil. Entrena el mismo corpus con BPE, Unigram y WordPiece. Mide la precisión en la tarea posterior usando cada uno en un pequeño clasificador de sentimiento. ¿La elección mueve la aguja en más de 1 punto de F1?
Términos Clave
| Término | Lo que la gente dice | Lo que realmente significa |
|---|---|---|
| BPE | Byte-Pair Encoding | Fusión voraz de los pares de caracteres más frecuentes hasta alcanzar el tamaño de vocabulario objetivo. |
| BPE a nivel de byte | Nunca hay tokens desconocidos | BPE sobre los 256 bytes en bruto; GPT-2 / Llama lo usan. |
| Unigram | Tokenizador probabilístico | Poda a partir de un gran conjunto de candidatos usando la log-verosimilitud; usado por T5, Gemma. |
| SentencePiece | El de los espacios en blanco | Biblioteca que entrena BPE/Unigram sobre texto en bruto; espacio codificado como ▁. |
| tiktoken | El rápido | Codificador BPE de OpenAI basado en Rust para vocabularios preconstruidos. Sin entrenamiento. |
| Lista de fusiones | Los números mágicos | Lista ordenada de fusiones (a, b) → ab; la inferencia aplica en orden. |
| Cobertura de caracteres | ¿Qué tan raro es demasiado raro? | Fracción de los caracteres del corpus de entrenamiento que el tokenizador debe cubrir; ~0,9995 típico. |
Lecturas Adicionales
- Sennrich, Haddow, Birch (2015). Neural Machine Translation of Rare Words with Subword Units — el artículo de BPE.
- Kudo (2018). Subword Regularization with Unigram Language Model — el artículo de Unigram.
- Kudo, Richardson (2018). SentencePiece: A simple and language independent subword tokenizer — la biblioteca.
- Hugging Face — Summary of the tokenizers — referencia concisa.
- Repositorio tiktoken de OpenAI — cookbook + lista de codificaciones.