Cap n_outputs_max on MTP draft contexts#2287
Merged
LostRuins merged 1 commit intoJun 25, 2026
Merged
Conversation
fb716f3 to
6f85a7c
Compare
LostRuins
approved these changes
Jun 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When using an MTP draft head, the draft context reserves a sampling/compute buffer scaling with
n_batch * n_vocab— on Gemma 4 (vocab 262144) ~0.5–2 GB depending on batch size.n_outputs_maxis simply never set on the draft context, while the built-in MTP path does set it.Root cause
mtp drafting added(40084bb) introduced two MTP paths:gpttype_adapter.cpp:884) correctly setsmtp_ctx_params.n_outputs_max = 1;speculative_decoding_setup()) buildsdraft_ctx_paramsfromllama_context_default_params()and copies many fields, but never setsn_outputs_max.It therefore stays at the default (0), which
llama-context.cppresolves ton_batch:The draft's backend sampling buffers are sized by
n_outputs_max:so the draft context reserves for
n_batchoutput positions even though it only ever produces a handful.draft-mtpgenerates tokens autoregressively — one output per sequence perllama_decode, looped up to--draftamount(seecommon_speculative_impl_draft_mtp::draft()incommon/speculative.cpp). The "multi-token" comes from the loop / chained heads, not from a wide forward, so the draft never needs more thann_seqoutputs — independent of--draftamount.Fix
Two spots, same omission. Mirror the built-in path and cap outputs at the sequence count (
n_seq_max, not a hard-coded1, to stay correct forn_seq > 1):speculative_decoding_setup()— the real draft context. This is what reserves the VRAM at runtime.estimate_draft_autofit_tax_mb()— the autofit pre-flight estimate (added in "another fix for drafting"). It builds an equivalentdraft_ctx_paramsto predict the drafter's VRAM cost for layer offloading; without the cap it over-estimates the MTP draft tax by the same ~0.5–2 GB, so autofit would offload fewer main-model layers than it could. Same one-liner keeps the estimate consistent with the real context.Measurements (Gemma 4 31B, vocab 262144, concedo_experimental)
Draft-context graph compute buffer (
sched_reserve), andn_outputs_maxof the draft context, before → after (same branch, single variable):n_outputs_maxTotal VRAM drops by more than the compute buffer alone (the separate logits/probs/candidates sampling buffers also scale with
n_outputs_max): ~0.7 GB at batch 512 / ~2 GB at batch 1024 on this model. Batch 1024 + f16 KV, which previously OOM'd at load and silently fell back to "Speculative Decoding will not be used!", now loads.Throughput and draft acceptance are unchanged (EvalScope perf, parallel 1: same tok/s and MTP acceptance before and after).
Effect scales with vocabulary size, so large-vocab models (Gemma 262k) are near worst case; the built-in MTP path (and integrated-MTP models such as Qwen via that path) were already unaffected.
Related upstream: ggml-org#24340.
AI disclosure