nemo_automodel.components.speculative.eagle.vllm_runner
nemo_automodel.components.speculative.eagle.vllm_runner
vLLM forward for the EAGLE-3 target (server-side, GPU only).
This module owns every vLLM-internal touch point so the rest of the speculative
stack stays vLLM-agnostic and importable without vLLM. It is imported lazily
(only from :meth:VLLMEagle3TargetModel.from_pretrained) and implements the
engine-agnostic
:class:~nemo_automodel.components.speculative.eagle.target_runner.TargetRunner
surface, exactly like sglang_runner.SGLangTargetRunner.
Mechanism (vLLM’s native extract_hidden_states speculative method, the
supported way to pull EAGLE-3 supervision out of vLLM without driving v1 worker
internals):
- Build an offline
LLMwithspeculative_config={"method": "extract_hidden_states", ...}and the three EAGLE-3 capture layers (plusnum_hidden_layersso the final pre-norm hidden is captured too) indraft_model_config.hf_config.eagle_aux_hidden_state_layer_ids. Chunked prefill is disabled so every prompt is captured in one prefill. generate(max_tokens=1)over the batch; vLLM writes the captured hidden states to disk throughExampleHiddenStatesConnector(a KV connector), and each request output carries the path underkv_transfer_params.- Read the per-prompt
[seq, num_capture_layers, hidden]tensor back, split the three EAGLE-3 layers (concatenated into[seq, 3 * hidden]) from the final-layer hidden, and rebuild full-vocab logits in-process by applying the target’s final RMSNorm + LM head (loaded once from the model’s safetensors).
vLLM’s extract_hidden_states API is version-coupled: the calls here track
vllm==0.23.0. This forward path requires a GPU and vLLM, so it is validated
on the training server, not in CPU unit tests; the CPU tests exercise the
shared contract layer against a fake runner instead.
Module Contents
Classes
Functions
Data
API
Offline vLLM engine that returns EAGLE-3 supervision tensors.
Built via :meth:build; consumed through the engine-agnostic
:class:~nemo_automodel.components.speculative.eagle.target_runner.TargetRunner
surface (model / set_aux_layers / forward_eagle3 /
input_embedding_weight). The vLLM LLM is constructed lazily in
:meth:set_aux_layers, because the capture layers must be known up front.
Rebuild full-vocab logits from the captured pre-norm final hidden state.
Capture id num_hidden_layers yields the pre-(final-norm) residual hidden
(verified for vllm==0.23.0), so apply the target’s final RMSNorm + LM
head here; if a future vLLM captures post-norm, drop the RMSNorm below.
Load the final-norm + LM-head + input embeddings once and cache them.
norm is kept in fp32 and lm_head is cast to fp32 and transposed to
[hidden, vocab] here so the per-microbatch forward_eagle3 does no
redundant cast/transpose (the LM head is multi-GB at large vocab).
Construct the runner for a standalone target server.
vllm_kwargs are forwarded to vllm.LLM (e.g. gpu_memory_utilization,
max_model_len, quantization). GPU/vLLM-only.
Release the vLLM engine (best effort).
Run one prefill per row and return (logits, aux_hidden_states).
logits is [batch, seq, vocab] (full vocab, unshifted) rebuilt from
the captured final hidden via the target’s final RMSNorm + LM head;
aux_hidden_states is [batch, seq, 3 * hidden] (the three capture
layers concatenated, unshifted). Sequences must share a length (training
batches are right-padded); attention_mask is unused because each row
is a full causal prefill in vLLM (trailing pad tokens do not affect
earlier positions under causal attention).
Return the target input-embedding weight [vocab, hidden].
Record the 3 capture layers and build the vLLM engine around them.
Lightweight stand-in exposing .config + .parameters().
The target’s real parameters live in the vLLM engine process, so this only
carries the HF config (for num_hidden_layers / hidden_size /
vocab_size) and a single device-marker tensor so the remote server can
still infer the target’s device via next(model.parameters()).device.
Load (embed, final_norm, lm_head) weights straight from the safetensors.
The real weights live inside the vLLM engine (a separate process), so the
final-norm + LM-head used to rebuild logits, and the input embeddings the
draft copies, are read directly off disk here instead. lm_head falls back
to the input embeddings for tied-embedding models (e.g. Qwen3).
Map a torch dtype to the string form vLLM’s dtype argument expects.
None means “let vLLM pick” ("auto").