Ir para o conteúdo

Tokens

O caminho do texto ao próximo token em sete passos: tokens, embeddings, query/key/value, máscara e cabeças, o bloco, a saída e a geração. O passo atual é Tokens. ATENÇÃO TRANSFORMERS Tokenstexto → ids ▲ você está aqui Embeddingsids → X Q · K · Vuma cabeça Máscaraduas cabeças BlocoLN · MLP Saídalogits → p Geraçãoescolher → próximo token

Passo 1 de 7. Entra: o texto "o gato subiu no". Sai: cinco inteiros, [0, 2, 4, 5, 1]. ← Visão geral · próximo passo: Embeddings →

Uma rede neural calcula com números; então, antes de qualquer coisa, o texto precisa virar números. A unidade em que ele é cortado é o token: um pedaço de texto tirado de uma lista fixa, o vocabulário, em que cada pedaço tem um inteiro, o seu id. Um token pode ser uma palavra inteira (gato), parte de uma palavra (iu), um caractere ou até um byte. O modelo nunca vê letras, só a sequência de ids; tudo o que ele prevê também é um id.

Por que não palavras? Por que não caracteres?

As duas escolhas óbvias falham:

  • Palavras. "subir", "sobe", "subiu" e "subindo" seriam quatro entradas sem relação, assim como cada nome, erro de digitação, número e palavra de cada língua: a lista nunca acaba. Pior: uma palavra que não estava na lista quando o modelo foi treinado não tem id nenhum.
  • Caracteres (ou bytes). Nada fica desconhecido: 256 bytes escrevem qualquer texto. Mas "o gato subiu no" vira 15 símbolos em vez de 4 palavras, o custo da atenção cresce com o quadrado do comprimento (passo 3) e cada posição sozinha quase não carrega significado.

Os subwords ficam no meio: palavras frequentes ficam inteiras, as mais raras são escritas com alguns pedaços frequentes e o que sobra cai para bytes soltos, então nada é desconhecido. O GPT-2 escreve "the cat climbed the" com 4 tokens: the, cat, climbed, the.

Primeiro, bytes

O texto é guardado em bytes, em UTF-8: um byte para cada caractere ASCII, de dois a quatro para os outros — "a" é o byte 97, "ã" são dois bytes, 195 e 163. Um tokenizador em nível de byte como o do GPT-2 parte dos 256 bytes possíveis, então qualquer texto, em qualquer língua, pode ser codificado. O nosso brinquedo parte dos caracteres de um corpus pequeno (são 23), o que deixa as tabelas curtas; o algoritmo é o mesmo.

BPE: fundir o par mais frequente, de novo e de novo

O vocabulário é aprendido de um corpus pelo byte-pair encoding (BPE)1, antes de o modelo ser treinado e separado dele:

  1. Corte o corpus em palavras e cada palavra em caracteres (bytes, no GPT-2).
  2. Conte cada par de símbolos vizinhos. Funda o par mais frequente num símbolo novo e anote essa fusão.
  3. Repita até o vocabulário ter o tamanho desejado.

Para tokenizar um texto novo, aplique as fusões anotadas na mesma ordem. O GPT-2 aprendeu 50.000 fusões em texto da web, quase todo em inglês2. O nosso tokenizador de brinquedo aprende com oito frases:

o gato sentou no telhado. · o cão sentou no chão. · o gato pulou no muro. · o cão dormiu no sofá. · o gato quer subir no muro. · o cão quer subir no sofá. · o gato fugiu do telhado. · o cão dormiu no chão.

Como o GPT-2, ele primeiro corta antes de cada espaço e de cada pontuação; o espaço fica no começo da palavra seguinte (escrito ␣ abaixo). Depois, conta. O par mais frequente do corpus é ␣ + n, 7 vezes (cada "no"), então a fusão 1 é ␣n; depois ␣n + o (7), t + o (6), ␣ + s (6)… Depois de 41 fusões todo pedaço de que o modelo de brinquedo precisa existe; o vocabulário do tokenizador tem 23 caracteres + 41 fusões = 64 entradas.

As 41 fusões, na ordem em que foram aprendidas (em negrito, as que mudam a nossa frase)
# fusão vezes # fusão vezes
1 ␣ + n → ␣n 7 22 ␣telh + a → ␣telha 2
2 ␣n + o → ␣no 7 23 ␣telha + do → ␣telhado 2
3 t + o → to 6 24 ␣c + h → ␣ch 2
4 ␣ + s → ␣s 6 25 ␣ch + ão → ␣chão 2
5 ␣ + c → ␣c 6 26 ␣ + m → ␣m 2
6 ã + o → ão 6 27 ␣m + u → ␣mu 2
7 d + o → do 5 28 ␣mu + r → ␣mur 2
8 ␣ + g → ␣g 4 29 ␣mur + o → ␣muro 2
9 ␣g + a → ␣ga 4 30 ␣do + r → ␣dor 2
10 ␣ga + to → ␣gato 4 31 ␣dor + m → ␣dorm 2
11 ␣c + ão → ␣cão 4 32 ␣dorm + iu → ␣dormiu 2
12 ␣ + do → ␣do 3 33 ␣s + o → ␣so 2
13 i + u → iu 3 34 ␣so + f → ␣sof 2
14 ␣s + e → ␣se 2 35 ␣sof + á → ␣sofá 2
15 ␣se + n → ␣sen 2 36 ␣ + q → ␣q 2
16 ␣sen + to → ␣sento 2 37 ␣q + u → ␣qu 2
17 ␣sento + u → ␣sentou 2 38 ␣qu + e → ␣que 2
18 ␣ + t → ␣t 2 39 ␣que + r → ␣quer 2
19 ␣t + e → ␣te 2 40 ␣s + u → ␣su 2
20 ␣te + l → ␣tel 2 41 ␣su + b → ␣sub 2
21 ␣tel + h → ␣telh 2

A frase do exemplo não está no corpus. Tokenizá-la é partir dos seus 15 caracteres e aplicar as 41 fusões em ordem; só 10 delas acham um par para fundir:

depois da fusão pedaços quantos
início: caracteres o ␣ g a t o ␣ s u b i u ␣ n o 15
1: ␣ + n o ␣ g a t o ␣ s u b i u ␣n o 14
2: ␣n + o o ␣ g a t o ␣ s u b i u ␣no 13
3: t + o o ␣ g a to ␣ s u b i u ␣no 12
4: ␣ + s o ␣ g a to ␣s u b i u ␣no 11
8: ␣ + g o ␣g a to ␣s u b i u ␣no 10
9: ␣g + a o ␣ga to ␣s u b i u ␣no 9
10: ␣ga + to o ␣gato ␣s u b i u ␣no 8
13: i + u o ␣gato ␣s u b iu ␣no 7
40: ␣s + u o ␣gato ␣su b iu ␣no 6
41: ␣su + b o ␣gato ␣sub iu ␣no 5

"subiu" não aparece no corpus e o BPE o escreve mesmo assim, com dois pedaços aprendidos em outras palavras: ␣sub (de "subir") e iu (de "dormiu" e "fugiu"). As fusões que não tocam a frase (␣sentou, ␣muro, ␣quer…) são de palavras que ela não contém. O GPT-2, coincidência, corta "subiu" do mesmo jeito: sub + iu.

O espaço pertence à palavra seguinte

"o" no começo do texto e " o" depois de um espaço seriam dois tokens diferentes; o mesmo vale para "the" e " the" no GPT-2 (ids 1169 e 262; "The", com maiúscula, é um terceiro, 464). Nem o tokenizador nem o modelo sabem que são "a mesma palavra". É também por isso que um prompt terminado em espaço muda o que o modelo prevê: o espaço normalmente seria o começo do próximo token (o capítulo de LLMs mede isso).

Vocabulário e ids

O modelo de brinquedo fica com 12 tokens: 11 dos 64 pedaços (os cinco da frase e outros seis que ele pode prever) mais o token especial <|endoftext|> (abaixo).

id pedaço id pedaço id pedaço
0 o 4 ␣sub 8 ␣sofá
1 ␣no 5 iu 9 ␣chão
2 ␣gato 6 ␣telhado 10 .
3 ␣cão 7 ␣muro 11 <|endoftext|>

"o gato subiu no" → o ␣gato ␣sub iu ␣no → [0, 2, 4, 5, 1]

Um modelo de verdade tem uma linha para cada entrada do seu tokenizador: o vocabulário do GPT-2 tem 256 bytes + 50.000 fusões + 1 token especial = 50.257; ele lê a frase como [78, 308, 5549, 850, 16115, 645]. O brinquedo fica com 12 para que as suas tabelas caibam na página.

Os ids são nomes, não quantidades: 4 não é "o dobro" de 2 e nada no número diz "verbo". O próximo passo transforma cada id num vetor.

Tokens especiais

Algumas entradas não vêm do BPE. Elas são acrescentadas à mão e texto comum nunca as produz:

  • <|endoftext|> (id 50256 no GPT-2, 11 no nosso) separa documentos nos dados de treino e deixa o modelo terminar o próprio texto: quando a geração o sorteia, ela para (passo 7).
  • Modelos de chat acrescentam marcadores de quem tem a vez; o BERT usa [CLS], [SEP] e [MASK]. Um batch de frases de tamanhos diferentes é completado com um token de padding, que uma máscara depois esconde (passo 4).

O português custa mais

Um tokenizador é ajustado ao seu corpus; uma língua que ele viu pouco é escrita com pedaços menores. O GPT-2 foi ajustado em inglês:

texto palavras tokens do GPT-2 tokens por palavra
the cat climbed the 4 4 1,00
o gato subiu no 4 6: o g ato sub iu no 1,50
The cat climbed onto the roof of the house because it was scared of the dog. 16 17 1,06
O gato subiu no telhado da casa porque estava com medo do cachorro. 13 25 1,92

Os dois tokenizadores de brinquedo destas páginas mostram o mesmo efeito pelo outro lado: o português, ajustado em frases em português, mantém gato inteiro (o GPT-2 não), enquanto o inglês corta "the cat climbed the roof." em 22 pedaços. Mais tokens quer dizer mais conta (a atenção cresce com \(n^2\)), menos texto na mesma janela de contexto e uma conta maior para a mesma frase3.

Veja rodar

O simulador roda o tokenizador de brinquedo, fusão a fusão, em qualquer texto que você digitar. Teste os casos: a frase com a resposta, uma palavra que o corpus nunca viu ("pássaro", escrita letra a letra) e a frase em inglês passando pelo tokenizador português.

Verifique você mesmo — o tokenizador de brinquedo nunca viu “subiu”. Por que ele não falha?

Porque o BPE nunca precisa que uma palavra inteira esteja no vocabulário. Ele parte dos caracteres (que estão todos lá) e funde o que consegue: "subiu" termina como ␣sub + iu, dois pedaços aprendidos de "subir", "dormiu" e "fugiu". Mesmo uma palavra feita de caracteres que ele nunca viu seria escrita, um caractere (um byte, no GPT-2) de cada vez.

Verifique você mesmo — “o” e “no” terminam em “o”. Eles dividem algum token?

Não. O primeiro é o (id 0) e o segundo é ␣no (id 1): a fusão ␣n + o acontece antes de qualquer outra coisa olhar para aquele "o". O próximo passo dá aos dois vetores diferentes e só o treino pode aproximá-los, se isso ajudar.


← Visão geral · próximo passo: Embeddings →


  1. Sennrich, R., Haddow, B., & Birch, A. (2016). Neural Machine Translation of Rare Words with Subword Units — ACL. O BPE trazido para o processamento de linguagem. ↩

  2. Radford, A., Wu, J., Child, R., Luan, D., Amodei, D., & Sutskever, I. (2019). Language Models are Unsupervised Multitask Learners. O GPT-2 e o seu BPE em nível de byte. ↩

  3. Petrov, A., La Malfa, E., Torr, P. H. S., & Bibi, A. (2023). Language Model Tokenizers Introduce Unfairness Between Languages — NeurIPS. ↩