Phase 07 - Lesson 16
Decodificação Especulativa — Esboçar, Verificar, Repetir
This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.
A decodificação autorregresiva é serial. Cada token espera pelo anterior. A decodificação especulativa quebra essa cadeia: um modelo leve esboça N tokens, e o modelo robusto verifica todos os N em um único passo de inferência (forward pass). Quando o esboço está correto, você paga apenas uma inferência do modelo robusto para N gerações.
Tipo: Build Linguagens: Python Pré-requisitos: Phase 7 · 07 (GPT Causal LM), Phase 7 · 12 (KV Cache & Flash Attention) Tempo: ~60 minutos
O Problema
Uma LLM de 70B amostrando um único token leva cerca de ~30 ms em uma H100. Um modelo de esboço de 3B leva cerca de ~3 ms. Se permitirmos que o modelo de 3B esboce 5 tokens à frente e então executarmos o modelo de 70B uma única vez para verificar todos os 5, o total é 5×3 + 30 = 45 ms para até 5 tokens aceitos — contra 5×30 = 150 ms para a geração linear padrão. Essa é a proposta principal da decodificação especulativa: trocar uma pequena quantidade de memória GPU extra (o modelo de esboço) por uma latência de decodificação 2 a 4 vezes menor.
O truque consiste em preservar a distribuição. A amostragem especulativa, introduzida por Leviathan et al. (2023) e concorrentemente por Chen et al., garante que a sequência de saída seja identicamente distribuída em relação ao que o modelo robusto produziria por conta própria. Sem perda de qualidade. Apenas mais rápido.
Quatro famílias de pares de esboço-verificador dominam a inferência em 2026:
- Vanilla speculative (Leviathan 2023). Modelo de esboço separado (ex: Llama 3 1B) + verificador (ex: Llama 3 70B).
- Medusa (Cai 2024). Múltiplas cabeças de decodificação no verificador preveem as posições
t+1..t+kem paralelo. Sem modelo de esboço separado. - Família EAGLE (Li 2024, 2025). Esboço leve que reutiliza os estados ocultos (hidden states) do verificador; taxa de aceitação mais próxima do que a vanilla; tipicamente de 3 a 4 vezes mais rápida.
- Lookahead decoding (Fu 2024). Iteração de Jacobi; nenhum modelo de esboço é necessário. Autoespeculação. De nicho, mas sem dependências.
Toda stack de inferência em produção em 2026 vem com decodificação especulativa por padrão. vLLM, TensorRT-LLM, SGLang e llama.cpp suportam, no mínimo, vanilla + EAGLE-2.
O Conceito
O algoritmo principal
Dado um verificador M_q e um modelo de esboço mais barato M_p:
- Seja
x_1..x_ko prefixo já decodificado. - Esboço (Draft): use
M_ppara propor de forma autorregresivad_{k+1}, d_{k+2}, ..., d_{k+N}com probabilidades de esboçop_1..p_N. - Verificar em paralelo: execute
M_quma vez emx_1..x_k, d_{k+1}, ..., d_{k+N}, obtendo probabilidades do verificadorq_1..q_{N+1}para as posiçõesk+1..k+N+1. - Aceitar/rejeitar cada token de esboço da esquerda para a direita: para cada
i, aceite com probabilidademin(1, q_i(d_i) / p_i(d_i)). - Na primeira rejeição na posição
j: amostret_ja partir da distribuição "residual"(q_j - p_j)_+normalizada. Todos os esboços depois dejsão descartados. - Ao aceitar todos os
N: amostre um token extrat_{N+1}deq_{N+1}(o token bônus gratuito).
O truque da distribuição residual é a sacada matemática que mantém a saída distribuída exatamente como se M_q tivesse feito a amostragem do zero.
O que determina o ganho de velocidade
Seja α = taxa de aceitação esperada por token de esboço. Seja c = razão de custo entre o esboço e o verificador. Por passo:
- A geração simples (naive) faz 1 chamada ao modelo robusto por token.
- A decodificação especulativa faz 1 chamada ao modelo robusto a cada
(1 - α^{N+1}) / (1 - α) ≈ 1/(1-α)tokens quandoαé alto.
Regra geral típica com α = 0.75 e N = 5: 3 vezes menos chamadas ao modelo robusto. O custo do esboço é 5 vezes menor. O tempo total de execução cai cerca de ~2.5×.
α depende de:
- Quão bem o esboço se aproxima do verificador. Mesma família / mesmos dados de treinamento aumentam significativamente o valor de α.
- Estratégia de decodificação. Esboço guloso (greedy) contra verificador guloso: α alto. Amostragem por temperatura: mais difícil de combinar; a aceitação diminui.
- Tipo de tarefa. Códigos e saídas estruturadas aceitam mais (são mais previsíveis); redação criativa de formato livre aceita menos.
Medusa — esboços sem um modelo de esboço
O Medusa substitui o modelo de esboço por cabeças de saída extras no verificador. Na posição t:
shared trunk → hidden h_t
├── head_0: predict token at t+1 (standard LM head)
├── head_1: predict token at t+2
├── head_2: predict token at t+3
├── head_3: predict token at t+4
Cada cabeça gera seus próprios logits. Na inferência, você amostra de cada cabeça para obter uma sequência candidata e, em seguida, verifica com um único passo de inferência usando um esquema de atenção em árvore (tree-attention) que considera todas as continuações candidatas de uma só vez.
Prós: sem necessidade de um segundo modelo. Contras: adiciona parâmetros treináveis; precisa de uma etapa de ajuste fino supervisionado (SFT) de cerca de ~1B de tokens; a taxa de aceitação é um pouco menor que a decodificação especulativa vanilla com um bom esboço.
EAGLE — melhor esboço reutilizando estados ocultos
O EAGLE-1/2/3 (Li et al., 2024–2025) torna o modelo de esboço um transformador minúsculo (geralmente de 1 camada) que ingere os estados ocultos da última camada do verificador. Como o esboço vê a representação de características do verificador, suas previsões se correlacionam fortemente com a distribuição de saída do verificador. As taxas de aceitação sobem de cerca de ~0.6 (vanilla) para mais de 0.85.
O EAGLE-3 (2025) adicionou busca em árvore sobre as continuações candidatas. O vLLM e o SGLang fornecem o EAGLE-2/3 como o caminho de especulação padrão para o Llama 3/4 e o Qwen 3.
A dança do KV cache
A verificação alimenta N tokens de esboço no verificador em um único passo de inferência. Isso estende o KV cache do verificador em N entradas. Se alguns esboços forem rejeitados, você deve reverter o cache para o comprimento do prefixo aceito.
Implementações de produção (como o --speculative-model do vLLM, e o LookaheadDecoder do TensorRT-LLM) lidam com isso por meio de buffers temporários de KV. Escreva primeiro, confirme após a aceitação. Não é conceitualmente complexo, mas é trabalhoso de implementar.
Build It
Consulte code/main.py. Nós implementamos o algoritmo principal de amostragem especulativa (etapa de rejeição + distribuição residual) com:
- Um "modelo grande" (big model) que é uma softmax determinística sobre uma distribuição codificada manualmente (para que possamos verificar a matemática de aceitação de forma analítica).
- Um "modelo de esboço" (draft model) que é uma perturbação do modelo grande.
- Um loop de aceitação/rejeição que produz a mesma distribuição marginal da amostragem direta.
Passo 1: a etapa de rejeição
def accept_or_reject(q_prob, p_prob, draft_token, u):
ratio = q_prob / p_prob if p_prob > 0 else float("inf")
return u < min(1.0, ratio)
u é um número aleatório uniforme. q_prob is a probabilidade do verificador para o token esboçado. p_prob é a probabilidade do modelo de esboço. O teorema de Leviathan garante que essa decisão de Bernoulli, seguida pela amostragem do residual em caso de rejeição, preserva exatamente a distribuição do verificador.
Passo 2: distribuição residual
def residual_dist(q, p):
raw = [max(0.0, qi - pi) for qi, pi in zip(q, p)]
s = sum(raw)
return [r / s for r in raw]
Subtraia p de q elemento a elemento, limite os valores negativos a zero e renormalize. Amostre desta distribuição em qualquer rejeição.
Passo 3: um passo especulativo
def spec_step(prefix, q_model, p_model, N, rng):
drafts = []
p_probs = []
ctx = list(prefix)
for _ in range(N):
p_dist = p_model(ctx)
d = sample(p_dist, rng)
drafts.append(d)
p_probs.append(p_dist[d])
ctx.append(d)
q_dists = [q_model(prefix + drafts[:i]) for i in range(N + 1)]
for i, d in enumerate(drafts):
u = rng.random()
q_prob = q_dists[i][d]
p_prob = p_probs[i]
if u < min(1.0, q_prob / p_prob if p_prob > 0 else float("inf")):
prefix = prefix + [d]
else:
res = residual_dist(q_dists[i], p_model(prefix))
prefix = prefix + [sample(res, rng)]
return prefix
prefix = prefix + [sample(q_dists[N], rng)]
return prefix
Cinco aceitos → um bônus → seis tokens produzidos em uma única passagem do verificador.
Passo 4: medir a taxa de aceitação
Execute 10.000 passos especulativos em diferentes níveis de qualidade de esboço. Plote a taxa de aceitação contra a divergência KL entre as distribuições do esboço e do verificador. Você deve ver uma relação monotonamente limpa.
Passo 5: verificar equivalência de distribuição
Empiricamente: o histograma de tokens produzidos pelo loop especulativo deve corresponder ao histograma produzido pela amostragem direta do verificador. Este é o teorema de Leviathan na prática. Um teste de qui-quadrado (chi-square test) confirma isso dentro do erro de amostragem.
Use It
# vLLM with EAGLE
vllm serve meta-llama/Llama-3.1-70B-Instruct \
--speculative-model /models/llama-3.1-eagle-70b \
--speculative-draft-tensor-parallel-size 1 \
--num-speculative-tokens 5
# vLLM with vanilla draft model
vllm serve meta-llama/Llama-3.1-70B-Instruct \
--speculative-model meta-llama/Llama-3.2-1B-Instruct \
--num-speculative-tokens 5
O TensorRT-LLM possui o caminho Medusa mais rápido a partir de meados de 2026. O faster-whisper envolve decodificação especulativa para o Whisper-large com um pequeno modelo de esboço.
Escolhendo um esboço:
| Estratégia | Quando escolher | Aceleração (Speedup) |
|---|---|---|
| Esboço Vanilla (Família Llama de 1B/3B) | Protótipo rápido, sem treinamento | 1.8–2.3× |
| Cabeças Medusa | Você pode ajustar (fine-tune) o verificador | 2–3× |
| EAGLE-2 / 3 | Produção, velocidade máxima | 3–4× |
| Lookahead | Sem esboço, sem treinamento, sem parâmetros extras | 1.3–1.6× |
Quando NÃO usar decodificação especulativa:
- Geração de sequência única de 1 a 5 tokens. O custo fixo (overhead) domina.
- Amostragem altamente criativa / com alta temperatura (α cai).
- Ambientes com restrição de memória (o modelo de esboço consome VRAM adicional).
Ship It
Consulte outputs/skill-spec-decode-picker.md. A skill escolhe uma estratégia de decodificação especulativa (vanilla / Medusa / EAGLE / lookahead) e parâmetros de ajuste (N, temperatura do esboço) para uma nova carga de trabalho de inferência.
Exercícios
- Fácil. Execute
code/main.py. Confirme se a distribuição de tokens especulativa corresponde à distribuição de amostragem direta do verificador em 50.000 tokens com chi-square p > 0.05. - Médio. Plote o ganho de velocidade (tokens por passo forward do modelo robusto) como uma função de
Nparaα = 0.5, 0.7, 0.85. Identifique oNideal para cada α. (Dica: tokens esperados por chamada de verificação =(1 - α^{N+1}) / (1 - α).) - Difícil. Implemente um Medusa minúsculo: pegue o GPT final da Lição 14, adicione 3 cabeças LM extras que preveem as posições t+2, t+3, t+4. Treine no tinyshakespeare com uma perda conjunta de múltiplas cabeças (multi-head loss). Compare as taxas de aceitação com as de um esboço vanilla feito ao truncar o mesmo modelo.
- Difícil. Implemente a reversão (rollback): comece com um KV cache de prefixo de 10 tokens, forneça 5 tokens de esboço, simule uma rejeição na posição 3. Verifique se as leituras do seu cache correspondem corretamente a "prefixo + primeiros 2 esboços aceitos" na próxima iteração.
Termos-Chave
| Termo | O que as pessoas dizem | O que realmente significa |
|---|---|---|
| Modelo de esboço (Draft model) | "O mais barato" | Um modelo menor que propõe tokens candidatos; geralmente de 10 a 50 vezes mais barato que o verificador. |
| Verificador (Verifier) | "O grandão" | O modelo alvo cuja distribuição nós preservamos; roda uma vez por passo especulativo. |
| Taxa de aceitação (α) | "Com que frequência o esboço acerta" | Probabilidade por token de que o verificador aceite o esboço. Tipicamente de 0.7 a 0.9. |
| Distribuição residual | "A alternativa na rejeição" | (q - p)_+ normalizada; amostrar a partir dela na rejeição preserva a distribuição do verificador. |
| Token bônus (Bonus token) | "O gratuito" | Quando todos os N esboços são aceitos, amostra-se mais um da distribuição do próximo passo do verificador. |
| Medusa | "Especulativa sem modelo de esboço" | Múltiplas cabeças de LM no verificador preveem as posições t+1..t+k em paralelo. |
| EAGLE | "Esboço por estado oculto" | Um esboço de transformador minúsculo condicionado nos estados ocultos da última camada do verificador. |
| Decodificação lookahead | "Iteração de Jacobi" | Autoespeculação que usa uma iteração de ponto fixo; sem modelo de esboço. |
| Atenção em árvore (Tree attention) | "Verifique muitos candidatos de uma vez" | Verificação ramificada que considera várias continuações de esboço simultaneamente. |
| Reversão de KV (KV rollback) | "Desfazer esboços rejeitados" | Buffer temporário de KV; confirma na aceitação, descarta na rejeição. |
Leituras Adicionais
- Leviathan, Kalman, Matias (2023). Fast Inference from Transformers via Speculative Decoding — o algoritmo principal e o teorema de equivalência.
- Chen et al. (2023). Accelerating Large Language Model Decoding with Speculative Sampling — introdução simultânea; prova clara de rejeição de Bernoulli.
- Cai et al. (2024). Medusa: Simple LLM Inference Acceleration Framework with Multiple Decoding Heads — artigo do Medusa; verificação por atenção em árvore (tree-attention).
- Li et al. (2024). EAGLE: Speculative Sampling Requires Rethinking Feature Uncertainty — EAGLE-1; esboço condicionado por estados ocultos.
- Li et al. (2024). EAGLE-2: Faster Inference of Language Models with Dynamic Draft Trees — EAGLE-2; profundidade dinâmica de árvore.
- Li et al. (2025). EAGLE-3: Scaling up Inference Acceleration of Large Language Models via Training-Time Test — EAGLE-3.
- Fu et al. (2024). Break the Sequential Dependency of LLM Inference Using Lookahead Decoding — abordagem lookahead, sem modelo de esboço.
- vLLM docs — Speculative Decoding — referência canônica de produção com as quatro estratégias conectadas.
- SafeAILab / EAGLE reference implementation — o código de referência para EAGLE-1/2/3.