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:

  1. Vanilla speculative (Leviathan 2023). Modelo de esboço separado (ex: Llama 3 1B) + verificador (ex: Llama 3 70B).
  2. Medusa (Cai 2024). Múltiplas cabeças de decodificação no verificador preveem as posições t+1..t+k em paralelo. Sem modelo de esboço separado.
  3. 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.
  4. 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:

  1. Seja x_1..x_k o prefixo já decodificado.
  2. Esboço (Draft): use M_p para propor de forma autorregresiva d_{k+1}, d_{k+2}, ..., d_{k+N} com probabilidades de esboço p_1..p_N.
  3. Verificar em paralelo: execute M_q uma vez em x_1..x_k, d_{k+1}, ..., d_{k+N}, obtendo probabilidades do verificador q_1..q_{N+1} para as posições k+1..k+N+1.
  4. Aceitar/rejeitar cada token de esboço da esquerda para a direita: para cada i, aceite com probabilidade min(1, q_i(d_i) / p_i(d_i)).
  5. Na primeira rejeição na posição j: amostre t_j a partir da distribuição "residual" (q_j - p_j)_+ normalizada. Todos os esboços depois de j são descartados.
  6. Ao aceitar todos os N: amostre um token extra t_{N+1} de q_{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

  1. 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.
  2. Médio. Plote o ganho de velocidade (tokens por passo forward do modelo robusto) como uma função de N para α = 0.5, 0.7, 0.85. Identifique o N ideal para cada α. (Dica: tokens esperados por chamada de verificação = (1 - α^{N+1}) / (1 - α).)
  3. 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.
  4. 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

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).