Phase 05 - Lesson 19
Tokenização de subpalavras — BPE, WordPiece, Unigram, SentencePiece
This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.
Tokenizadores de palavras engasgam com palavras desconhecidas. Tokenizadores de caracteres explodem o comprimento da sequência. Tokenizadores de subpalavras dividem a diferença. Todo LLM moderno é entregue com um deles.
Tipo: Aprender Linguagens: Python Pré-requisitos: Fase 5 · 01 (Processamento de Texto), Fase 5 · 04 (GloVe / FastText / Subpalavra) Tempo: ~60 minutos
O Problema
Seu vocabulário tem 50.000 palavras. Um usuário digita "untokenizable". Seu tokenizador retorna [UNK]. O modelo agora não tem nenhum sinal sobre a palavra. Pior: o documento no percentil 90 do seu corpus tem 40 palavras raras, o que significa 40 bits de informação descartada por documento.
A tokenização de subpalavras resolve isso. Palavras comuns permanecem como tokens únicos. Palavras raras se decompõem em pedaços significativos: untokenizable → un, token, izable. Os dados de treinamento cobrem tudo porque qualquer cadeia de caracteres é, em última instância, uma sequência de bytes.
Todo LLM de fronteira em 2026 é entregue com um de três algoritmos (BPE, Unigram, WordPiece), envolvido em uma de três bibliotecas (tiktoken, SentencePiece, HF Tokenizers). Você não consegue entregar um modelo de linguagem sem escolher um.
O Conceito
BPE (Byte-Pair Encoding). Comece com um vocabulário em nível de caractere. Conte cada par adjacente. Mescle o par mais frequente em um novo token. Repita até atingir o tamanho de vocabulário alvo. Algoritmo dominante: GPT-2/3/4, Llama, Gemma, Qwen2, Mistral.
BPE em nível de byte. O mesmo algoritmo, mas sobre bytes brutos (256 tokens base) em vez de caracteres Unicode. Garante zero tokens [UNK] — qualquer sequência de bytes é codificável. O GPT-2 usa 50.257 tokens (256 bytes + 50.000 merges + 1 especial).
Unigram. Comece com um vocabulário enorme. Atribua a cada token uma probabilidade unigram. Pode tokens, iterativamente, cuja remoção menos aumenta a log-verossimilhança do corpus. Probabilístico na inferência: pode amostrar tokenizações (útil para aumento de dados via regularização de subpalavras). Usado por T5, mBART, ALBERT, XLNet, Gemma.
WordPiece. Mescle pares que maximizam a verossimilhança do corpus de treinamento em vez da frequência bruta. Usado por BERT, DistilBERT, ELECTRA.
SentencePiece vs tiktoken. SentencePiece é a biblioteca que treina vocabulários (BPE ou Unigram) diretamente sobre texto Unicode bruto, codificando espaços em branco como ▁. tiktoken é o codificador rápido da OpenAI contra vocabulários pré-construídos; ele não treina.
Regra geral:
- Treinar um novo vocabulário: SentencePiece (multilíngue, sem pré-tokenização) ou HF Tokenizers.
- Inferência rápida contra o vocabulário do GPT: tiktoken (cl100k_base, o200k_base).
- Ambos: HF Tokenizers — uma biblioteca, treinamento + serviço.
Construa
Passo 1: BPE do zero
Veja code/main.py. O laço:
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
Três fatos que o algoritmo codifica. </w> marca o fim da palavra para que "low" (sufixo) e "lower" (prefixo) permaneçam distintos. A ponderação por frequência faz com que pares de alta frequência vençam cedo. A lista de merges é ordenada — a inferência aplica os merges na ordem do treinamento.
Passo 2: codificar com os merges aprendidos
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
Ingênuo, O(n·|merges|). Implementações de produção (tiktoken, HF Tokenizers) usam busca por rank de merge com filas de prioridade e rodam em tempo quase linear.
Passo 3: SentencePiece na prática
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']
Observe: nenhuma pré-tokenização necessária, espaço codificado como ▁, character_coverage controla quão agressivamente caracteres raros são preservados em vez de mapeados para <unk>.
Passo 4: tiktoken para vocabulários compatíveis com a OpenAI
import tiktoken
enc = tiktoken.get_encoding("o200k_base")
print(enc.encode("untokenizable")) # [127340, 101028]
print(len(enc.encode("Hello, world!"))) # 4
Apenas codificação. Rápido (backend em Rust). Correspondência exata com a tokenização do GPT-4/5 para contagem de bytes, estimativa de custo e orçamento de janela de contexto.
Armadilhas que ainda chegam à produção em 2026
- Deriva do tokenizador (tokenizer drift). Treinar com o vocabulário A, implantar contra o vocabulário B. Os IDs de token diferem; o modelo produz lixo. Verifique o hash de
tokenizer.jsonna CI. - Ambiguidade de espaço em branco. "hello" vs " hello" no BPE produzem tokens diferentes. Sempre especifique
add_special_tokenseadd_prefix_spaceexplicitamente. - Subtreinamento multilíngue. Corpora dominados pelo inglês produzem vocabulários que dividem scripts não latinos em 5 a 10 vezes mais tokens. O mesmo prompt custa de 5 a 10 vezes mais em japonês/árabe no GPT-3.5. O o200k_base corrigiu isso parcialmente.
- Divisões de emoji. Um único emoji pode ocupar 5 tokens. Verifique o tratamento de emojis ao orçar o contexto.
Use
A pilha de 2026:
| Situação | Escolha |
|---|---|
| Treinar um modelo monolíngue do zero | HF Tokenizers (BPE) |
| Treinar um modelo multilíngue | SentencePiece (Unigram, character_coverage=0.9995) |
| Servir uma API compatível com a OpenAI | tiktoken (o200k_base para GPT-4+) |
| Vocabulário específico de domínio (código, matemática, proteína) | Treine um BPE customizado no corpus de domínio, mescle com o vocabulário base |
| Inferência na borda (edge), modelo pequeno | Unigram (vocabulários menores funcionam melhor) |
O tamanho do vocabulário é uma decisão de escalonamento, não uma constante. Heurística aproximada: 32k para <1B de parâmetros, 50-100k para 1-10B, 200k+ para multilíngue/fronteira.
Entregue
Salve 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.
Exercícios
- Fácil. Treine um BPE de 500 merges no pequeno corpus de
code/main.py. Codifique três palavras separadas (held-out). Quantas produziram exatamente 1 token vs >1 token? - Médio. Compare as contagens de tokens em 100 frases da Wikipédia em inglês entre
cl100k_base,o200k_basee um BPE de SentencePiece que você treine com vocab=32k. Reporte a razão de compressão de cada um. - Difícil. Treine o mesmo corpus com BPE, Unigram e WordPiece. Meça a acurácia em tarefa posterior usando cada um em um pequeno classificador de sentimento. A escolha move o ponteiro em mais de 1 ponto de F1?
Termos-chave
| Termo | O que as pessoas dizem | O que realmente significa |
|---|---|---|
| BPE | Byte-Pair Encoding | Mesclagem gulosa dos pares de caracteres mais frequentes até atingir o tamanho de vocabulário alvo. |
| BPE em nível de byte | Nunca há tokens desconhecidos | BPE sobre os 256 bytes brutos; GPT-2 / Llama usam isso. |
| Unigram | Tokenizador probabilístico | Poda a partir de um grande conjunto de candidatos usando log-verossimilhança; usado por T5, Gemma. |
| SentencePiece | O do espaço em branco | Biblioteca que treina BPE/Unigram sobre texto bruto; espaço codificado como ▁. |
| tiktoken | O rápido | Codificador BPE da OpenAI baseado em Rust para vocabulários pré-construídos. Sem treinamento. |
| Lista de merges | Os números mágicos | Lista ordenada de merges (a, b) → ab; a inferência aplica em ordem. |
| Cobertura de caracteres | Quão raro é raro demais? | Fração dos caracteres no corpus de treinamento que o tokenizador deve cobrir; ~0,9995 típico. |
Leitura Adicional
- Sennrich, Haddow, Birch (2015). Neural Machine Translation of Rare Words with Subword Units — o artigo do BPE.
- Kudo (2018). Subword Regularization with Unigram Language Model — o artigo do Unigram.
- Kudo, Richardson (2018). SentencePiece: A simple and language independent subword tokenizer — a biblioteca.
- Hugging Face — Summary of the tokenizers — referência concisa.
- Repositório tiktoken da OpenAI — cookbook + lista de codificações.