Ir para o conteúdo

Embeddings

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 é Embeddings. ATENÇÃO TRANSFORMERS Tokenstexto → ids Embeddingsids → X ▲ você está aqui Q · K · Vuma cabeça Máscaraduas cabeças BlocoLN · MLP Saídalogits → p Geraçãoescolher texto → → próximo token

Passo 2 de 7. Entra: os ids [0, 2, 4, 5, 1] do passo 1. Sai: a matriz \(X\), uma linha de \(d = 4\) números por token — a entrada de todos os passos seguintes. ← Tokens · próximo passo: Query, key, value →

Um id é um nome. O id 4 (␣sub) não é o dobro do id 2 (␣gato) e não está "mais perto" do id 5 do que do id 11; entregar o inteiro cru a uma rede afirmaria uma ordem e uma distância que não existem (o capítulo de dados diz o mesmo de qualquer coluna categórica). O que a rede precisa é de um vetor por token — uma lista de números com espaço para muitas propriedades ao mesmo tempo — e ela aprende esses vetores a partir dos dados.

Dos tokens aos vetores: a camada de embedding

Antes de haver o que comparar, o texto precisa virar vetores. Ele chega ao modelo como índices inteiros e a primeira camada é uma tabela \(E \in \mathbb{R}^{V \times d}\) com uma linha por token do vocabulário. A passagem direta é uma busca:

\[ y_t = E[i_t] \qquad\text{que é o mesmo que}\qquad y_t = \text{one-hot}(i_t)^\top E \]

\(E\) é aprendida como qualquer outra matriz de pesos. O GPT-2 small tem \(V = 50.257\) linhas de \(d = 768\) números: \(38{,}6\) milhões de parâmetros, 31% do modelo inteiro.

A consulta, no exemplo

A tabela do brinquedo tem \(V = 12\) linhas de \(d = 4\) números. As linhas dos cinco tokens de "o gato subiu no" estão marcadas:

id token \(E[\text{id}]\)
0 o [−0,5; −0,5; 0; 1]
1 ␣no [−0,5; 0; −0,5; 1]
2 ␣gato [1; −0,5; 0; −0,5]
3 ␣cão [1; −0,5; −0,5; 0]
4 ␣sub [−0,5; 1; 0; −0,5]
5 iu [0; 0,5; −0,5; 0]
6 ␣telhado [0; −0,5; 1; −0,5]
7 ␣muro [1; 0; −1; 0]
8 ␣sofá [0,5; −0,5; −0,5; 0,5]
9 ␣chão [0,5; 0; −0,5; 0]
10 . [0; 0; 1; −1]
11 <|endoftext|> [0,5; −0,5; 0,5; −0,5]

Os ids [0, 2, 4, 5, 1] pegam as linhas 0, 2, 4, 5 e 1, nessa ordem. Não há conta nenhuma; o mesmo id recebe a mesma linha onde quer que apareça e sejam quais forem os vizinhos — exatamente a limitação que a atenção vai resolver. (Os números do brinquedo foram escolhidos à mão. Uma tabela treinada não tem colunas legíveis: o que uma dimensão significa fica espalhado por muitas delas.)

De onde vem a posição

Nada na atenção das próximas duas páginas usa a ordem dos tokens: a atenção é equivariante a permutações: embaralhe os tokens e as saídas embaralham junto, com valores idênticos. Sozinha, ela não distingue "cachorro morde homem" de "homem morde cachorro". A posição precisa ser injetada e como ela é injetada acabou importando muito para contexto longo.

Esquema Mecanismo Veredito
Senoidal1 Vetores fixos de sen/cos somados aos embeddings de entrada Histórico. Extrapola mal.
Absoluta aprendida Um vetor treinável por posição Histórico (BERT, GPT-2). Não passa do comprimento treinado, de jeito nenhum.
ALiBi3 Uma penalidade linear na distância somada aos scores Extrapola bem; largamente superada
RoPE2 Girar os vetores Q e K por um ângulo proporcional à posição Universal. Llama, Qwen, Mistral, Gemma, DeepSeek
NoPE / híbrida Nenhum sinal posicional em algumas camadas; a causalidade sozinha carrega a ordem Cada vez mais comum em pilhas híbridas e de contexto longo

Vale entender a RoPE em vez de decorá-la. Imagine um relógio: o ponteiro de cada token é girado um tanto a mais a cada posição. O ângulo entre dois ponteiros não depende de que horas são, só de quantas posições os separam. Em símbolos: tome Q e K em pares de dimensões, trate cada par como um número complexo e multiplique por \(e^{i\,m\theta}\), onde \(m\) é a posição. Como rotações se compõem somando ângulos, o produto escalar entre a posição \(m\) e a posição \(n\) depende apenas de \(m - n\):

\[ \langle R_m q,\; R_n k \rangle \;=\; \langle q,\; R_{n-m} k \rangle \]

Rotações absolutas entram, posição relativa sai — sem parâmetros extras e sem tensor extra a somar. Cada par de dimensões gira numa velocidade \(\theta\) diferente, como os ponteiros de horas, minutos e segundos: os rápidos distinguem vizinhos próximos, os lentos distinguem distâncias longas. É também por essa propriedade que janelas de contexto podem ser estendidas depois do treino: reescale as frequências \(\theta\) e os mesmos pesos endereçam uma sequência mais longa (interpolação de posição, escala NTK, YaRN4). Todo anúncio de "estendemos para 1M de tokens" é, mecanicamente, isso mais fine-tuning.

A posição no exemplo

O GPT-2 usa a segunda linha dessa tabela, posições absolutas aprendidas: uma segunda tabela \(P\), com uma linha por posição (1024 × 768 no GPT-2), somada à linha do token. O brinquedo faz o mesmo com 8 posições:

\[ x_t = E[i_t] + P_t \]
posição \(t\) token (id) \(E[i_t]\) \(P_t\) \(x_t\)
1 o (0) [−0,5; −0,5; 0; 1] [0; 0; 0; 0] [−0,5; −0,5; 0; 1]
2 ␣gato (2) [1; −0,5; 0; −0,5] [0,5; 0; −0,5; 0] [1,5; −0,5; −0,5; −0,5]
3 ␣sub (4) [−0,5; 1; 0; −0,5] [0; 0,5; 0; −0,5] [−0,5; 1,5; 0; −1]
4 iu (5) [0; 0,5; −0,5; 0] [−0,5; 0; 0,5; 0] [−0,5; 0,5; 0; 0]
5 ␣no (1) [−0,5; 0; −0,5; 1] [0; −0,5; 0; 0,5] [−0,5; −0,5; −0,5; 1,5]

Empilhadas, as cinco linhas são a matriz de onde todas as páginas seguintes partem:

\[ X = \begin{bmatrix} -0{,}5 & -0{,}5 & 0 & 1 \\ 1{,}5 & -0{,}5 & -0{,}5 & -0{,}5 \\ -0{,}5 & 1{,}5 & 0 & -1 \\ -0{,}5 & 0{,}5 & 0 & 0 \\ -0{,}5 & -0{,}5 & -0{,}5 & 1{,}5 \end{bmatrix} \qquad (n \times d = 5 \times 4) \]

(Cada linha de \(E\) e de \(P\) do brinquedo soma zero, então cada linha de \(X\) tem média 0; isso só deixa a conta da próxima página mais curta.) Os outros esquemas, para comparar:

  • Senoidal (2017): não há tabela, a posição é calculada. Com \(d = 4\) ela vale \([\operatorname{sen} t,\ \cos t,\ \operatorname{sen}(t/100),\ \cos(t/100)]\), com \(t\) contado a partir de 0: a posição 0 é \([0; 1; 0; 1]\), a posição 1 é \([0{,}841; 0{,}540; 0{,}010; 1{,}000]\), a posição 2 é \([0{,}909; -0{,}416; 0{,}020; 1{,}000]\). O primeiro par gira rápido e separa vizinhos; o segundo gira devagar e separa distâncias longas.
  • RoPE: nada é somado aqui. Dentro da atenção, cada par de números de \(q\) e de \(k\) é girado por um ângulo proporcional à posição. Com um par só e \(\theta = 0{,}5\), o mesmo \(q = k = [1; 0]\) nas posições \((3, 1)\) e \((10, 8)\) dá o mesmo score, \(\cos(2 \times 0{,}5) = 0{,}540\); em \((4, 1)\) o score é \(\cos(1{,}5) = 0{,}071\). Só a distância conta.

O painel monta \(X\) passo a passo. Troque o esquema de posição ou troque ␣gato e ␣sub de lugar: sem posição, a troca só troca duas linhas de \(X\).

A volta: um gradiente esparso

As duas formas da consulta dão o mesmo vetor, mas a segunda explica a volta. Multiplicar por um vetor que é zero em toda parte menos numa posição produz um gradiente que também é zero em toda parte menos naquela linha, com as repetições somadas:

\[ \frac{\partial L}{\partial E[i]} \;=\; \sum_{t \,:\, i_t = i} \frac{\partial L}{\partial y_t} \]

Três consequências:

  • A atualização é esparsa. Num passo com poucos milhares de tokens, a maior parte das linhas de \(E\) recebe gradiente exatamente zero. É por isso que os frameworks têm um caminho separado para embeddings (sparse=True, IndexSelect) em vez de tratar \(E\) como uma matriz densa qualquer.
  • Token raro aprende devagar. O painel sorteia tokens por uma lei de Zipf, como a linguagem de verdade: os primeiros aparecem várias vezes por sequência, a cauda longa aparece quase nunca e as linhas dela quase não se movem.
  • A tabela é enorme e muitas vezes é reaproveitada. Com 128 mil linhas e 4096 colunas são 525 milhões de parâmetros só na entrada. Amarrar essa matriz à camada de saída, que projeta de volta para o vocabulário, guarda uma tabela dessas em vez de duas — e funciona porque as duas falam do mesmo espaço.
Verifique você mesmo — troque “␣gato” e “␣sub” de lugar. O que acontece com X, com e sem posições?

Sem posições, \(X\) fica com as mesmas cinco linhas em outra ordem: as linhas 2 e 3 trocam de lugar e nada mais muda. A atenção sem máscara daria então as mesmas saídas, trocadas, sem distinguir "gato sub" de "sub gato". Com posições aprendidas as próprias linhas mudam: ␣gato na posição 3 vale \(E[2] + P_3 = [1; -0{,}5; 0; -0{,}5] + [0; 0{,}5; 0; -0{,}5] = [1; 0; 0; -1]\), não o \([1{,}5; -0{,}5; -0{,}5; -0{,}5]\) que tinha na posição 2.

Verifique você mesmo — num batch de 4.000 tokens, quais linhas de E recebem gradiente?

Só as linhas dos ids que aparecem no batch — no máximo 4.000 dos 50.257 do GPT-2, em geral bem menos, porque tokens frequentes se repetem. Todas as outras recebem exatamente zero; é por isso que o vetor de um token raro aprende devagar.


← Tokens · próximo passo: Query, key, value →


  1. Vaswani, A., et al. (2017). Attention Is All You Need — NeurIPS. Atenção escalada por produto escalar, multi-cabeça, posições senoidais. ↩

  2. Su, J., Lu, Y., Pan, S., Murtadha, A., Wen, B., & Liu, Y. (2021). RoFormer: Enhanced Transformer with Rotary Position Embedding. Publicado na Neurocomputing 568 (2024). RoPE. ↩

  3. Press, O., Smith, N., & Lewis, M. (2022). Train Short, Test Long: Attention with Linear Biases Enables Input Length Extrapolation — ICLR. ↩

  4. Peng, B., Quesnelle, J., Fan, H., & Shippole, E. (2024). YaRN: Efficient Context Window Extension of Large Language Models — ICLR. Reescala das frequências da RoPE, feita com cuidado. ↩