Train an EAGLE Drafter for Speculative Decoding — End-to-End Guide
Train an EAGLE Drafter for Speculative Decoding — End-to-End Guide
A step-by-step guide for training an EAGLE speculative decoding drafter to accelerate LLM inference using NeMo AutoModel.
What is EAGLE Speculative Decoding?
Large language models generate text one token at a time — each token requires a full forward pass through the entire model. Speculative decoding speeds this up by pairing the large target model with a small, fast drafter model. The drafter guesses multiple tokens ahead; the target model then verifies them all in a single forward pass, accepting correct guesses and rejecting wrong ones. The output is mathematically identical to running the target model alone, but 2-3x faster.
EAGLE (Extrapolation Algorithm for Greater Language-model Efficiency) is a family of speculative decoding methods. NeMo AutoModel supports three variants:
The Task
We train an EAGLE-3 drafter for Llama 3.1 8B Instruct on the PerfectBlend dataset — a chat corpus whose assistant turns were generated by the same Llama 3.1 8B model, ensuring distribution alignment between training data and target.
After training, we serve the target + drafter together via SGLang for accelerated inference.
Guide Overview
Hardware Requirements
On CUDA, the target model is loaded in BF16 and frozen during training (the CPU fallback uses FP32). Only the small drafter is trained; standard EAGLE-3 uses one fused decoder layer plus an auxiliary projection. GPU memory is therefore dominated by the target model size.
Step 0 — Environment Setup
This guide runs inside the NeMo AutoModel Docker container:
For SGLang serving (Step 5), install it in the same environment:
SGLang / transformers version compatibility. SGLang 0.5.9 pins
transformers==4.57.1. The SGLang target backend (target_model_backend: sglang)
and serve_sglang run in that environment without issue. The --compare-hf
check in smoke_sglang_target.py additionally builds the HuggingFace target
through NeMoAutoModelForCausalLM, which imports AutoModelForMultimodalLM
(available only in transformers 5.x), so that single-process comparison cannot
run as written under transformers==4.57.1. To compare the two backends, use a
transformers build that satisfies both, or load the HuggingFace side with plain
transformers.AutoModelForCausalLM wrapped in HFEagle3TargetModel.
Step 1 — Understand EAGLE Architecture
How EAGLE-3 Works
EAGLE-3 pairs a frozen target LLM with a small trainable drafter. During training, the drafter learns to predict what the target model would produce next, using a technique called test-time training (TTT) unroll:
Key components:
- Target model: The full LLM (e.g., Llama 3.1 8B), completely frozen. Provides hidden states from selected intermediate layers as auxiliary inputs to the drafter.
- Draft model: A shallow transformer (a single fused decoder layer) with:
- A fusion layer (
fc) that combines auxiliary hidden states from 3 target layers - Its own attention layers, MLP, and layer norm
- A smaller output vocabulary (e.g., 8192 or 32000 tokens instead of 128k) to reduce compute
- A fusion layer (
- TTT unroll: The drafter runs the configured number of autoregressive steps
during training; the maintained Llama examples use 4. Loss weights decay as
0.8^i, teaching the drafter to make multi-step predictions — exactly what speculative decoding needs.
Supported Target Architectures
The target is resolved from its HF config.architectures string through the
registry in components/speculative/eagle/registry.py. Most dense and MoE
decoders reuse the config-driven Llama-style draft (a one-line registry entry);
architectures whose RoPE or attention layout the shared draft cannot represent
get a thin dedicated draft class.
Gemma4. Gemma4 ships as a multimodal Gemma4ForConditionalGeneration whose
text decoder config is nested under config.text_config; the draft is built
from that inner config automatically. Set target_force_hf: true so the stock
HuggingFace text-capable model is loaded (the draft hooks the decoder under
model.language_model.layers). The draft consumes only post-block hidden states,
so it is the same Llama-style dense draft used elsewhere, with two Gemma quirks
reconciled: the hidden_activation (GeGLU) key and Gemma4’s nested
per-attention-type rope_parameters, which is flattened to a standard
full-rotary Llama RoPE on the global (full-attention) base. The saved checkpoint
keeps the canonical architectures: ["LlamaEagle3DraftModel"] layout, so SGLang
and vLLM serve it with their existing EAGLE-3 Llama head. See
examples/speculative/eagle3/gemma4_e2b_eagle3.yaml.
EAGLE-3.1 Drafter Toggles
The same train_eagle3 recipe supports the EAGLE-3.1 drafter variant via two
optional flags in recipe_args. Both default to false, so existing EAGLE-3
configs and checkpoints behave identically. Setting them applies the EAGLE-3.1
architectural changes from
vllm-project/vllm#42764 to
the Llama-style draft. The MLA-backbone community release
lightseekorg/kimi-k2.6-eagle3.1-mla
is a separate architecture (Eagle3DeepseekV2ForCausalLM) and is not
produced by this recipe.
Together they remove the “attention drift” pattern (loss of focus on sink tokens at deeper speculation depths) reported by the EAGLE-3.1 paper and let the drafter behave more like a recurrently applied module than a stack of extra layers bolted onto the target.
How EAGLE-1 Differs
EAGLE-1 is simpler: it uses a single transformer layer, predicts the full
vocabulary, and trains with a combined loss of SmoothL1 (Huber) on hidden states
(hidden_loss_weight) and cross-entropy on tokens (token_loss_weight).
No TTT unroll, no vocabulary mapping.
Step 2 — Prepare the Training Dataset
Data format
EAGLE training accepts chat data in the OpenAI messages format—either JSONL
files or HuggingFace datasets with a messages column—and automatically
converts supported ShareGPT-style conversations rows to that format:
Option A: Use a pre-regenerated dataset (recommended)
For best results, the assistant turns in your training data should come from the same model you’ll use as the target at inference time. The PerfectBlend dataset already has answers regenerated by Llama 3.1 8B Instruct:
Expected output:
ChatDataset automatically converts supported ShareGPT-style rows from the
conversations column to OpenAI-style messages, including PerfectBlend’s
role/content records. A manual conversion is only needed for a dataset with
unsupported role names or a different conversation schema.
Option B: Regenerate answers from your target model
If you have a chat dataset whose answers were generated by a different model, you can regenerate them using your target. This aligns the training data distribution with the model the drafter will actually assist at inference time.
Step B.1 — Start the target server (in one shell):
Wait for Uvicorn running on http://0.0.0.0:30000 before proceeding.
Step B.2 — Regenerate (in another shell):
For each sample, the script:
- Loads the conversation from the input dataset
- Drops the trailing assistant turn, keeping the user prompt context
- Calls the target server to generate a new assistant response
- Saves the rebuilt conversation to parquet shards
The output directory contains parquet files with a messages column — ready
for EAGLE training. The script is resumable: rerun with --resume to skip
completed shards.
Step 3 — Configure and Launch EAGLE-3 Training
YAML config
Save the following as eagle3_llama8b.yaml:
Config field reference
Launch training
Multi-GPU (8x A100, production):
Single-GPU (quick test with Llama 3.2 1B):
For a quick test, use the MVP config with Llama 3.2 1B and a small dataset:
For GPUs with FlashAttention support, add draft_attn_implementation: flash_attention_2
to recipe_args for faster training. See
llama_eagle3_mvp_flash_attn.yaml
for a complete example.
Step 4 — Monitor Training and Inspect Checkpoints
What to watch
At each logging interval, the recipe emits epoch, step, train_loss,
train_acc, an optional train_tau_sim, and lr. The values below illustrate
the log format:
Checkpoint layout
The shown 200k-sample, 8-GPU config does not enable step or epoch checkpoint cadence, so it saves only the final checkpoint after 6250 optimizer steps:
Resume from checkpoint
To create intermediate checkpoints that can recover an interrupted run, first
set a cadence in recipe_args, for example ckpt_every_steps: 1000. Then resume
from the latest checkpoint:
Or point to a specific checkpoint:
Step 5 — Serve with SGLang
The serve_sglang helper resolves the current HF-style training checkpoint and
launches the server in one command. It also converts older bare-weight
checkpoints as a compatibility fallback.
Launch the server
For a current checkpoint, the helper:
- Resolves the checkpoint’s HF-style
model/directory directly - Rewrites the architecture name for SGLang compatibility when needed (
LlamaEagle3DraftModel->LlamaForCausalLMEagle3) - Uses an existing
model/speculative_token_map.pt, or generates it from the siblingeagle_meta.ptfor EAGLE-3 - Launches SGLang with the correct speculative decoding flags
For a legacy checkpoint containing draft_model.pt and config.json, the helper
exports the weights and rewritten config into model/. For EAGLE-3, it uses the
legacy eagle3_meta.pt when present to generate model/speculative_token_map.pt.
Serving parameters
Pass extra SGLang flags after --:
Smoke-test the server
Once you see Uvicorn running on http://0.0.0.0:30000, test it:
Expected output:
The accept_length_per_step metric shows how many tokens the target model
accepts per speculative step on average. Higher is better — a value of 3.0+
indicates the drafter is accurately predicting the target’s behavior.
OpenAI-compatible endpoint
SGLang also exposes an OpenAI-compatible API:
Expected output:
Step 6 — (Bonus) Train an EAGLE-1 Drafter
EAGLE-1 is simpler and faster to train, making it a good starting point for experimentation. It uses a single transformer layer and trains with a combined hidden-state SmoothL1 (Huber) + token cross-entropy loss.
YAML config
Save as eagle1_llama8b.yaml:
Launch
Serve
Use --algorithm EAGLE (not EAGLE3) for EAGLE-1/2 drafters: