Fundamentos

Tokenization I: caracteres, palavras e subpalavras

A tokenization decide as unidades que um modelo consegue enxergar; o tokenizer publicado do Qwen3.8-27B mapeia 248.077 ids, enquanto seus tensores de embedding e saída reservam 248.320 linhas.

Atualizada em

01 · Conceito

Conceito

Pegue a palavra inglesa unbelievability e faça uma pergunta de projetista: quantas unidades o modelo deveria gastar com ela? Três respostas já foram tentadas em produção, e vale trabalhar as consequências de cada uma antes de qualquer terminologia chegar.

Soletre um caractere por vez e ela custa quinze unidades. O vocabulário necessário é minúsculo, algumas centenas de entradas cobrem quase todo texto em escrita latina, e nenhuma palavra fica irrepresentável. Mas agora toda frase se estica por cinco ou seis vezes mais posições e, como a track 4 vai mostrar, o trabalho de um transformer cresce com as posições e não com os caracteres. Você deixou o modelo barato de armazenar e caro de rodar.

Guarde-a como uma palavra inteira e ela custa uma unidade — desde que alguém a tenha colocado no vocabulário. Se não colocou, o modelo recebe um símbolo desconhecido e a distinção entre unbelievability e incomprehensibility é destruída na porta de entrada. Nomes, flexões, jargão de domínio, erros de digitação e palavras inventadas terça-feira passada caem todos no mesmo buraco. Nenhuma lista finita de palavras fecha sobre texto aberto, e aumentá-la tem um preço próprio ao qual chegaremos.

Divida-a como un, believ, abil, ity e ela custa quatro unidades, com pedaços reutilizáveis em milhares de outras palavras. Isso é tokenization por subpalavras, e é o que essencialmente todo modelo moderno faz, o Qwen3.8-27B incluído. Strings frequentes ficam inteiras; as raras são compostas. Os pedaços são aprendidos de um corpus por um algoritmo, e a lição 1.3 acompanha um desses algoritmos merge a merge.

A variante do Qwen desce mais um degrau. Seu tokenizer aplica normalização NFC e um pré-tokenizador ByteLevel antes do BPE. A base derivada de bytes soletra todo byte UTF-8 produzido por uma string Unicode válida, então escritas desconhecidas e emoji não precisam colapsar num token desconhecido. Isso não é uma rota de fallback — a configuração BPE publicada diz byte_fallback: false e não declara token desconhecido — nem faz a API pública de texto aceitar binário arbitrário. A cobertura de texto Unicode normalizado é ampla; a eficiência não, pois strings incomuns podem se expandir em cadeias longas de pedaços derivados de bytes.

Note que nenhuma dessas divisões é um fato sobre a língua. Até palavra é ambíguo. Dá-lhe é uma palavra ou duas? A pontuação gruda? O chinês não coloca espaço nenhum entre palavras. O alemão solda alegremente quatro conceitos num composto só. Ainda assim, um tokenizer precisa devolver uma resposta determinística para toda string Unicode válida, inclusive strings que seus projetistas jamais imaginaram, então as fronteiras que ele traça são estatísticas, não linguísticas. Uma divisão pode parecer absurda para uma pessoa e ainda assim ser a escolha certa de engenharia.

Agora o número no arquivo de configuração, que é onde esta lição justifica seu lugar. O Qwen3.8-27B declara 248.320 linhas de vocabulário. O erro óbvio é ler isso como o modelo conhece 248.320 palavras, e o erro mais sofisticado — o que pega quem já sabe melhor — é ler como o tokenizer pode emitir 248.320 tokens distintos. Nenhum dos dois é garantido por esse campo. O que vocab_size governa é um shape de tensor: o número de linhas da matriz de embeddings e o número de colunas da projeção de saída que produz os logits.

Os artefatos do tokenizer tornam a diferença mensurável. O modelo BPE contém 248.044 entradas, e 33 tokens adicionados ocupam ids até 248.076, totalizando 248.077 ids mapeados. A configuração do modelo define vocab_size=248,320\text{vocab\_size}=248{,}320, então os tensores de embedding e saída reservam 243 linhas adicionais. O shape é divisível por 512 — 248,320=512×485248{,}320 = 512 \times 485 —, algo conveniente para sharding, mas os artefatos publicados não informam por que esse tamanho exato foi escolhido, que sinal de treino as linhas não mapeadas receberam nem como todo servidor trata seus logits. A configuração de geração fixada não declara uma lista genérica de suppress_tokens. Inspecione o runtime real antes de afirmar mascaramento.

O tamanho do vocabulário não é de graça, e o custo é fácil de subestimar. Cada linha é um vetor de 5120 números e, neste modelo, o embedding de entrada e a projeção de saída são matrizes separadas em vez de uma compartilhada, então cada linha adicional custa armazenamento duas vezes. A lição 1.5 faz a contabilidade completa e o total é surpreendente. A tensão de projeto é, portanto, genuína: mais entradas de vocabulário significam sequências mais curtas e attention mais barata, mas uma tabela maior para armazenar, carregar e multiplicar a cada passo de decodificação. Não existe resposta universalmente correta, só um ponto numa curva escolhido para um conjunto específico de idiomas, hardware e cargas de trabalho.

Como o tokenizer é fixado quando o treino começa, ele faz parte do contrato do modelo e não é uma conveniência de pré-processamento. A matriz de embeddings tem uma linha por entrada do vocabulário, e essas linhas aprenderam seus valores sob um mapeamento específico de texto para ids. Troque o tokenizer depois e todo id aponta para uma linha que aprendeu outra coisa. É por isso que você não pode misturar os pesos de um modelo com o tokenizer de outro, por mais parecidos que os dois pareçam.

Quando você inspeciona qualquer tokenizer, quatro perguntas resolvem a maior parte do que importa. Ele consegue representar o texto válido que sua interface aceita? Quantas linhas de tensor há, e quantos ids os artefatos do tokenizer mapeiam? Quantos tokens o texto típico dos seus idiomas exige? E os idiomas e domínios com que você se importa são fragmentados de forma justa em relação aos que não são? Essas perguntas mostram por que tokenization não é mero pré-processamento. Ela fixa o alfabeto disponível ao modelo e define o preço de toda sequência que esse modelo vai processar na vida.

02 · Analogia

Analogia

Suponha que toda frase precise ser montada com uma caixa de ímãs de geladeira. Uma caixa só de letras soltas soletra qualquer coisa, mas um bilhete curto engole a caixa inteira. Uma caixa de palavras completas deixa os bilhetes comuns rápidos e torna um sobrenome desconhecido impossível. A caixa de subpalavras é o meio-termo funcional: palavras frequentes ficam inteiras, e o resto é montado com pedaços reutilizáveis como un, believ e able. A caixa do Qwen desce mais um nível: no fundo dela estão os 256 valores possíveis de byte, então nada que você consiga digitar fica sem soletração.

03 · Explique de volta

Explique de volta

Explique por que modelos modernos usam tokens de subpalavra em vez de caracteres ou palavras inteiras, e diga o que o número 248.320 na configuração do Qwen3.8-27B de fato conta.

Mínimo: 80 caracteres e 15 palavras. Seu texto fica somente neste navegador.

Aguardando sua explicação.

Comparar com uma resposta-modelo

Tokens de caractere mantêm o vocabulário minúsculo e soletram qualquer coisa, mas esticam toda frase por muito mais posições, e o custo cresce com as posições. Tokens de palavra inteira encurtam a prosa comum, mas exigem um vocabulário ilimitado e falham em nomes, flexões, erros de digitação e neologismos. A tokenization por subpalavras mantém strings frequentes inteiras e compõe as raras a partir de pedaços. O pré-tokenizador ByteLevel do Qwen fornece uma base derivada de bytes para texto Unicode válido após normalização NFC; sua configuração BPE define byte fallback explicitamente como falso. O modelo do tokenizer mapeia 248.044 ids e 33 tokens adicionados estendem o maior id mapeado até 248.076, portanto 248.077 ids são mapeados. O 248.320 da configuração conta linhas de tensor, deixando 243 linhas sem mapeamento no tokenizer publicado. Esses artefatos não documentam como essas linhas foram treinadas nem como todo runtime trata seus logits.

04 · Teste seu entendimento

Teste seu entendimento

01A configuração do Qwen3.8-27B declara 248.320 linhas de vocabulário. Qual é a leitura mais segura desse número?
Resposta e explicação

Ele dimensiona as matrizes de embedding e de saída e pode estar preenchido acima da contagem de tokens que o tokenizer realmente emite — A configuração governa shapes de tensores. Preencher até um múltiplo conveniente é rotina, então podem existir linhas que nenhum token mapeia; os arquivos do tokenizer são a autoridade sobre o que o texto vira.

02Que problema um vocabulário fixo de palavras inteiras trata mal?
Resposta e explicação

Palavras raras, com erro de digitação ou recém-inventadas — Qualquer coisa fora da lista fixa precisa de um símbolo desconhecido, o que destrói exatamente a distinção de que o modelo talvez precise. Pedaços de subpalavra a compõem em vez disso.

03A lição 0.1 disse que um forward pass produz um score para cada linha de saída. O que custa aumentar o vocabulário mapeado e seus tensores?
Resposta e explicação

Uma matriz de saída maior e mais scores a computar em cada posição, em troca de sequências mais curtas — Tamanho de vocabulário troca com comprimento de sequência: vocabulário maior significa menos posições, mas uma tabela de embeddings mais larga, uma projeção de saída mais larga e mais logits por passo.

Conclua o teach-back e acerte o quiz para finalizar a aula.

◎ · Marcador de evidência

Fontes

  1. Rico Sennrich, Barry Haddow e Alexandra Birch (2016). Neural Machine Translation of Rare Words with Subword Units.
  2. Taku Kudo e John Richardson (2018). SentencePiece: A simple and language independent subword tokenizer and detokenizer for Neural Text Processing.
  3. Qwen Team (2026). tokenizer.json do Qwen3.8-27B (revisão fixada).
  4. Qwen Team (2026). config.json do Qwen3.8-27B (revisão fixada).
  5. Qwen Team (2026). generation_config.json do Qwen3.8-27B (revisão fixada).
  6. Qwen Team (2026). Qwen3.8-27B Model Card.