Phase 07 - Lesson 14
Construa um Transformer do Zero — O Projeto Final
Treze lições. Um modelo. Sem atalhos.
Tipo: Construção Linguagens: Python Pré-requisitos: Fase 7 · 01 a 13. Não pule. Tempo: ~120 minutos
O Problema
Você leu todos os artigos. Você implementou atenção, divisões multi-head, codificações posicionais, blocos de codificador (encoder) e decodificador (decoder), perdas do BERT e GPT, MoE, KV cache. Agora faça-os funcionar juntos em uma tarefa real.
O projeto final: treinar um pequeno transformer apenas-decodificador (decoder-only) de ponta a ponta em uma tarefa de modelagem de linguagem em nível de caractere. Ele lê Shakespeare. Ele gera novos textos no estilo de Shakespeare. Ele é pequeno o suficiente para ser treinado em um notebook em menos de 10 minutos. Ele é correto o suficiente para que a substituição por um conjunto de dados maior e um treinamento mais longo resulte em um LM real.
Este é o "nanoGPT" do curso. Não é original — o tutorial nanoGPT de 2023 do Karpathy é a implementação de referência que todo estudante escreve pelo menos uma vez. Nós adaptamos a estrutura e a reorganizamos em torno do que cobrimos.
O Conceito
A arquitetura, anotada:
input tokens (B, N)
│
▼
token embedding + positional embedding ◀── Lesson 04 (RoPE option)
│
▼
┌──── block × L ────────────────────┐
│ RMSNorm │ ◀── Lesson 05
│ MultiHeadAttention (causal) │ ◀── Lesson 03 + 07 (causal mask)
│ residual │
│ RMSNorm │
│ SwiGLU FFN │ ◀── Lesson 05
│ residual │
└────────────────────────────────── ┘
│
▼
final RMSNorm
│
▼
lm_head (tied to token embedding)
│
▼
logits (B, N, V)
│
▼
shift-by-one cross-entropy ◀── Lesson 07
O que entregamos
GPTConfig— um único lugar para configurar todos os hiperparâmetros.MultiHeadAttention— causal, em lotes (batched), com caminho opcional no estilo Flash (oscaled_dot_product_attentiondo PyTorch).SwiGLUFFN— um FFN moderno.Block— pré-normalização (pre-norm), atenção envolvida em resíduos (residual-wrapped) + FFN.GPT— embeddings, blocos empilhados, cabeça LM (LM head), generate().- Loop de treinamento com AdamW, taxa de aprendizado com decaimento de cosseno (cosine LR), corte de gradiente (gradient clipping).
- Tokenizador em nível de caractere em texto de Shakespeare.
O que não entregamos
- RoPE — implementado conceitualmente na Lição 04. Aqui usamos embeddings posicionais aprendidos para simplificar. Os exercícios pedem para você substituí-los por RoPE.
- KV cache durante a geração — cada etapa de geração recalcula a atenção sobre o prefixo completo. Mais lento, mas mais simples. Os exercícios pedem para você adicionar um KV cache.
- Flash Attention — o PyTorch 2.0+ faz o auto-despacho se as entradas corresponderem; nós usamos
F.scaled_dot_product_attention. - MoE — um único FFN por bloco. Você viu MoE na Lição 11.
Métricas alvo
Em um notebook Mac M2, um GPT com 4 camadas, 4 cabeças e d_model=128 treinado por 2.000 etapas em tinyshakespeare.txt:
- A perda de treinamento converge de ~4,2 (aleatório) para ~1,5 em cerca de 6 minutos.
- A saída amostrada parece no estilo de Shakespeare: surgem palavras arcaicas, quebras de linha e nomes próprios como "ROMEO:".
- A perda de validação (últimos 10% do texto mantidos em reserva) acompanha de perto a perda de treinamento; sem overfitting neste tamanho/orçamento.
Construa
Esta lição usa PyTorch. Instale o torch (a versão de CPU é suficiente). Consulte code/main.py. O script lida com:
- Download de
tinyshakespeare.txtse estiver ausente (ou leitura de uma cópia local). - Tokenizador de caracteres em nível de byte.
- Divisão de treino/val em 90/10.
- Loop de treinamento com bf16 autocast em hardware suportado.
- Amostragem após a conclusão do treinamento.
Passo 1: dados
text = open("tinyshakespeare.txt").read()
chars = sorted(set(text))
stoi = {c: i for i, c in enumerate(chars)}
itos = {i: c for c, i in stoi.items()}
encode = lambda s: [stoi[c] for c in s]
decode = lambda xs: "".join(itos[x] for x in xs)
65 caracteres únicos. Vocabulário minúsculo. Cabe em um vocab_size de 4 bytes. Sem BPE, sem drama com tokenizador.
Passo 2: modelo
Consulte code/main.py. O bloco é clássico da Lição 05 — pré-normalização (pre-norm), RMSNorm, SwiGLU, MHA causal. Contagem de parâmetros para 4/4/128: ~800K.
Passo 3: loop de treinamento
Obtenha um lote (batch) aleatório de janelas de tokens de comprimento 256. Forward. Entropia cruzada deslocada por um (shift-by-one cross-entropy). Backward. Etapa do AdamW. Log. Repita.
for step in range(max_steps):
x, y = get_batch("train")
logits = model(x)
loss = F.cross_entropy(logits.view(-1, vocab_size), y.view(-1))
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
opt.step()
opt.zero_grad()
Passo 4: amostragem
Dado um prompt, execute repetidamente o forward, faça a amostragem a partir dos logits top-p, anexe e continue. Pare após 500 tokens.
Passo 5: leia a saída
Após 2.000 etapas:
ROMEO:
Away and mild will not thy friend, that thou shalt wit:
The chief that well shame and hath been his friends,
...
Não é Shakespeare. Mas no estilo de Shakespeare. Uma vitória clara para ~800K parâmetros e 6 minutos em um notebook.
Use
Este projeto final é uma arquitetura de referência. Três extensões para torná-lo algo real:
- Substitua o tokenizador. Use BPE (por exemplo,
tiktoken.get_encoding("cl100k_base")). O tamanho do vocabulário salta de 65 para ~50.000. A capacidade do modelo precisa aumentar para compensar. - Treine em um corpus maior. Use
OpenWebTextoufineweb-edu(HuggingFace). 10 bilhões de tokens em uma única GPU A100 levam cerca de 24 horas para um GPT de 125M parâmetros. - Adicione RoPE + KV cache + Flash Attention. Os exercícios abaixo guiam você por cada um deles.
Isso resulta em um GPT de 125 milhões de parâmetros que gera inglês fluente. Não é um modelo de fronteira. Mas o mesmo caminho de código — apenas maior — é o que Karpathy, EleutherAI e o Allen Institute usam para treinar checkpoints de pesquisa em 2026.
Entregue
Consulte outputs/skill-transformer-review.md. A habilidade avalia a corretude de uma implementação de transformer do zero ao longo de todas as 13 lições anteriores.
Exercícios
- Fácil. Execute
code/main.py. Verifique se a perda de validação da etapa final do seu modelo treinado está abaixo de 2,0. Alteremax_stepsde 2.000 para 5.000 — a perda de validação continua melhorando? - Médio. Substitua os embeddings posicionais aprendidos por RoPE. Aplique a rotação a Q e K dentro de
MultiHeadAttention. Treine e verifique se a perda de validação é pelo menos tão baixa quanto antes. - Médio. Implemente um KV cache no loop de amostragem. Gere 500 tokens com e sem cache. O tempo real de execução (wall-clock) deve melhorar de 5 a 20 vezes em um notebook.
- Difícil. Adicione uma segunda cabeça ao modelo que preveja o token seguinte ao próximo (MTP — Multi-Token Prediction do DeepSeek-V3). Treine de forma conjunta. Isso ajuda?
- Difícil. Substitua o FFN único por bloco por um MoE de 4 especialistas. Roteador + roteamento top-2. Veja como a perda de validação muda com os mesmos parâmetros ativos.
Termos-Chave
| Termo | O que as pessoas dizem | O que realmente significa |
|---|---|---|
| nanoGPT | "Repositório de tutorial do Karpathy" | Código de treinamento minimalista de transformer apenas-decodificador, ~300 linhas de código (LOC); a referência canônica. |
| tinyshakespeare | "O corpus de brinquedo padrão" | ~1,1 MB de texto; todos os tutoriais de LM de caracteres desde 2015 o utilizam. |
| Tied embeddings | "Compartilhar matriz de entrada/saída" | Peso da cabeça LM = transposta da matriz de embedding de token; economiza parâmetros, melhora a qualidade. |
| bf16 autocast | "Truque de precisão de treinamento" | Executa forward/backward em bf16, mantém o estado do otimizador em fp32; padrão desde 2021. |
| Gradient clipping | "Impede picos" | Limita a norma global do gradiente em 1,0; evita explosões de treinamento. |
| Cosine LR schedule | "O padrão pós-2020" | A taxa de aprendizado (LR) aumenta linearmente (warmup) e depois decai em formato de cosseno até 10% do pico. |
| MFU | "Utilização de FLOPs do Modelo" | FLOPs alcançados / pico teórico; 40% denso, 30% MoE é considerado forte em 2026. |
| Val loss | "Perda em dados reservados" | Entropia cruzada em dados que o modelo nunca viu; detector de overfitting. |
Leituras Adicionais
- The Annotated Transformer (Harvard NLP) — a clássica implementação anotada.