Phase 07 - Lesson 07
GPT — Modelagem de Linguagem Causal
This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.
O BERT vê ambos os lados. O GPT vê apenas o passado. A máscara triangular é a linha de código individual mais consequente na IA moderna.
Tipo: Build Linguagens: Python Pré-requisitos: Fase 7 · 02 (Self-Attention), Fase 7 · 05 (Full Transformer), Fase 7 · 06 (BERT) Tempo: ~75 minutos
O Problema
Um modelo de linguagem responde a uma pergunta: dados os primeiros t-1 tokens, qual é a distribuição de probabilidade sobre o token t? Treine nesse sinal — previsão do próximo token — e você obterá um modelo capaz de gerar texto arbitrário, um token por vez.
Para treiná-lo de ponta a ponta em uma sequência inteira em paralelo, você precisa que a previsão de cada posição dependa apenas das posições anteriores. Caso contrário, o modelo trapaceia trivialmente olhando para a resposta.
A máscara causal faz isso. É uma matriz triangular superior única de valores -inf adicionados aos scores de atenção antes do softmax. Após o softmax, essas posições tornam-se 0. Cada posição pode atentar apenas para si mesma e para as posições anteriores. E como você a aplica uma vez a toda a sequência, você obtém N previsões paralelas do próximo token em uma única passagem para a frente (forward pass).
GPT-1 (2018), GPT-2 (2019), GPT-3 (2020), GPT-4 (2023), GPT-5 (2024), Claude, Llama, Qwen, Mistral, DeepSeek, Kimi — todos eles são transformers causais apenas com decodificador (decoder-only) com o mesmo loop central. Apenas com dados maiores e melhores, e melhor RLHF.
O Conceito
A máscara
Dada uma sequência de comprimento N, construa uma matriz N × N:
M[i, j] = 0 if j <= i
M[i, j] = -inf if j > i
Adicione M aos scores de atenção brutos antes do softmax. exp(-inf) = 0, portanto, as posições mascaradas contribuem com peso zero. Cada linha da matriz de atenção é uma distribuição de probabilidade apenas sobre as posições anteriores.
Custo de implementação: uma única chamada a torch.tril(). Tempo de computação: nanossegundos. Impacto no campo: tudo.
Treinamento paralelo, inferência serial
Treinamento: execute o forward pass de toda a sequência (N, d_model) de uma vez, compute N perdas de entropia cruzada (uma por posição), some e faça o backprop. Paralelo ao longo da sequência. É por isso que o treinamento do GPT escala — você processa 1M de tokens em um lote (batch) em uma única passagem da GPU.
Inferência: você gera token por token. Alimente [t1, t2, t3], obtenha t4. Alimente [t1, t2, t3, t4], obtenha t5. Alimente [t1, t2, t3, t4, t5], obtenha t6. O cache KV (Lição 12) salva os estados ocultos (hidden states) de t1…tn para que você não os recompute a cada passo. Mas a profundidade serial na inferência = comprimento da saída. Esse é o imposto autorregressivo (autoregressive tax) e a razão pela qual a decodificação é o gargalo de latência de todo LLM.
A perda — deslocamento por um (shift-by-one)
Dados os tokens [t1, t2, t3, t4]:
- Entrada:
[t1, t2, t3] - Alvos:
[t2, t3, t4]
Para cada posição i, compute -log P(target_i | inputs[:i+1]). Some. Esta é a entropia cruzada para toda a sequência.
Todo transformer LM que você conhece treina com essa perda. Pré-treinamento, ajuste fino (fine-tuning), SFT — mesma perda, dados diferentes.
Estratégias de decodificação
Após o treinamento, as escolhas de amostragem (sampling) importam mais do que as pessoas imaginam.
| Método | O que faz | Quando usar |
|---|---|---|
| Greedy | Argmax a cada passo | Tarefas determinísticas, completamento de código |
| Temperatura | Divide os logits por T, amostra | Tarefas criativas, T maior = mais diversidade |
| Top-k | Amostra apenas dos top-k tokens | Elimina caudas de baixa probabilidade |
| Top-p (nucleus) | Amostra do menor conjunto com prob acumulada ≥ p | Padrão pós-2020; adapta-se ao formato da distribuição |
| Min-p | Mantém tokens com p > min_p * max_p |
Pós-2024; melhor em rejeitar caudas longas do que o top-p |
| Decodificação especulativa | Modelo de rascunho propõe N tokens, modelo grande verifica | Redução de 2 a 3 vezes na latência com a mesma qualidade |
Em 2026, min-p + temperatura 0.7 é um padrão razoável para modelos de pesos abertos (open-weights). A decodificação especulativa é um requisito básico para qualquer stack de inferência em produção.
O que fez a "receita do GPT" funcionar
- Apenas decodificador (Decoder-only). Sem o overhead do codificador (encoder). Uma passagem de atenção + FFN por camada.
- Escalonamento (Scaling). 124M → 1.5B → 175B → trilhões. As leis de escala de Chinchilla (Lição 13) dizem como gastar computação.
- Aprendizado em contexto (In-context learning). Surgiu em torno de 6B–13B. O modelo consegue seguir exemplos few-shot sem ajuste fino.
- RLHF. O pós-treinamento em preferências humanas converteu o texto bruto pré-treinado em assistentes de chat.
- Pre-norm + RoPE + SwiGLU. Treinamento estável em escala.
A arquitetura principal não mudou muito desde o GPT-2. Tudo de interessante aconteceu em dados, escala e pós-treinamento.
Build It
Passo 1: a máscara causal
Veja code/main.py. Uma única linha:
def causal_mask(n):
return [[0.0 if j <= i else float("-inf") for j in range(n)] for i in range(n)]
Adicione aos scores de atenção antes do softmax. Esse é todo o mecanismo.
Passo 2: um modelo estilo GPT de 2 camadas
Empilhe dois blocos decodificadores (self-attention mascarado + FFN, sem atenção cruzada/cross-attention). Adicione um embedding de token, uma codificação posicional (positional encoding) e um unembedding (vinculado à matriz de embedding de token — um truque padrão desde o GPT-2).
Passo 3: previsão do próximo token, ponta a ponta
Em um vocabulário de brinquedo de 20 tokens, produza logits em cada posição. Compute a perda de entropia cruzada em relação ao alvo deslocado por um. Sem gradiente — esta é uma verificação de sanidade do forward pass.
Passo 4: amostragem
Implemente os métodos greedy, temperatura, top-k, top-p e min-p. Execute cada um em um prompt fixo e compare os resultados. Uma função de amostragem tem cerca de 10 linhas.
Use It
PyTorch, estilo de 2026:
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-3B-Instruct")
tok = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-3B-Instruct")
prompt = "Attention is all you need because"
inputs = tok(prompt, return_tensors="pt")
out = model.generate(
**inputs,
max_new_tokens=64,
temperature=0.7,
top_p=0.9,
do_sample=True,
)
print(tok.decode(out[0]))
Por baixo dos panos, generate() executa o forward pass, extrai os logits da posição final, amostra o próximo token, o anexa e repete. Cada stack de inferência de LLM em produção (vLLM, TensorRT-LLM, llama.cpp, Ollama, MLX) implementa o mesmo loop com otimizações pesadas — prefill em lote (batched prefill), loteamento contínuo (continuous batching), paginação de cache KV (KV cache paging) e decodificação especulativa.
GPT vs BERT, uma linha cada: O GPT prevê P(x_t | x_{<t}). O BERT prevê P(x_masked | x_unmasked). A perda determina se o modelo é capaz de gerar.
Ship It
Veja outputs/skill-sampling-tuner.md. A habilidade (skill) escolhe os parâmetros de amostragem para uma nova tarefa de geração e sinaliza quando a decodificação determinística é necessária.
Exercícios
- Fácil. Execute
code/main.pye verifique se a matriz de atenção causal é triangular inferior após o softmax. Verificação rápida: a linha 3 deve ter pesos apenas nas colunas 0 a 3. - Médio. Implemente a busca por feixe (beam search) com largura 4. Compare a perplexidade do beam-4 versus greedy em 10 prompts curtos. O beam sempre vence? (Dica: geralmente sim para tradução, mas não para chat aberto.)
- Difícil. Implemente a decodificação especulativa: use um modelo minúsculo de 2 camadas como rascunho (draft) e um modelo de 6 camadas como verificador. Meça a aceleração de tempo de relógio (wall-clock speedup) em 100 conclusões de comprimento 64. Confirme se as saídas correspondem à decodificação greedy do verificador.
Termos-Chave
| Termo | O que as pessoas dizem | O que realmente significa |
|---|---|---|
| Máscara causal | "O triângulo" | Matriz triangular superior de -inf adicionada aos scores de atenção para que a posição i veja apenas as posições ≤ i. |
| Previsão do próximo token | "A perda (loss)" | Entropia cruzada da distribuição do modelo em relação ao verdadeiro próximo token em cada posição. |
| Autorregressivo | "Gerar um por vez" | Alimentar a saída de volta como entrada; paralelismo apenas durante o treinamento, não durante a geração. |
| Logits | "Scores pré-softmax" | Saída bruta da cabeça do LM (LM head) antes do softmax; a amostragem ocorre sobre estes valores. |
| Temperatura | "Botão de criatividade" | Divide os logits por T; T→0 = greedy, T→∞ = uniforme. |
| Top-p | "Amostragem de núcleo (nucleus)" | Trunca a distribuição para o menor conjunto cuja soma seja ≥p; amostra a partir do que resta. |
| Min-p | "Melhor que top-p" | Mantém os tokens onde p ≥ min_p × max_p; adapta o corte à nitidez da distribuição. |
| Decodificação especulativa | "Rascunho + verificação" | Modelo barato propõe N tokens; modelo grande verifica em paralelo. |
| Teacher forcing | "Truque de treinamento" | Durante o treinamento, alimenta o verdadeiro token anterior, não a previsão do modelo. Padrão para todo LM seq2seq. |
Leitura Adicional
- Radford et al. (2018). Improving Language Understanding by Generative Pre-Training — GPT-1.
- Radford et al. (2019). Language Models are Unsupervised Multitask Learners — GPT-2.
- Brown et al. (2020). Language Models are Few-Shot Learners — GPT-3 e in-context learning.
- Leviathan, Kalman, Matias (2023). Fast Inference from Transformers via Speculative Decoding — artigo sobre decodificação especulativa.
- HuggingFace
modeling_llama.py— código de referência canônico de causal-LM.