Speculative Decoding¶
Speculative decoding (SpD) accelerates token generation by using a fast proposer to draft candidate tokens that the target model verifies in a single forward pass. When acceptance rates are high, effective tokens-per-second during decode can increase significantly (actual improvement is workload-dependent).
Quick recommendation
Start with ngram SpD — it requires no separate model binary or dedicated core allocation and works well for summarization and conversational workloads. Switch to draft_model if you need higher acceptance rates on diverse generation tasks.
Triton-CPU backend required for AOT SpD
For AOT mode, the rejection sampler uses Triton kernels running on CPU. Install the triton-cpu backend during setup:
Methods¶
Cloud AI supports three speculative decoding methods:
| Method | Proposer | Separate Model Binary | Dedicated Core Allocation | Best For |
|---|---|---|---|---|
ngram |
N-gram pattern matching | No | No | Summarization, repetitive output |
suffix |
Suffix array matching | No | No | Code completion, long-context echo |
draft_model |
Lightweight LLM | Yes | Yes | General text generation |
N-gram Speculative Decoding¶
Requires no separate model binary and no dedicated core allocation — runs within the target model's existing resources:
from vllm import LLM, SamplingParams
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
max_num_seqs=8,
max_model_len=2048,
long_prefill_token_threshold=128,
quantization="mxfp6",
kv_cache_dtype="mxint8",
speculative_config={
"method": "ngram",
"num_speculative_tokens": 5,
},
)
Docker example:
docker run --rm -it --network host \
--device /dev/accel/ \
--shm-size=4gb \
ghcr.io/quic/cloud_ai_inference_vllm:1.21.2.0 \
--host 127.0.0.1 --port 8000 \
--model TinyLlama/TinyLlama-1.1B-Chat-v1.0 \
--max-model-len 256 \
--max-num-seq 16 \
--max-seq-len-to-capture 128 \
--quantization mxfp6 \
--kv-cache-dtype mxint8 \
--speculative-config '{"method":"ngram","num_speculative_tokens":5}'
Draft-Model Speculative Decoding¶
Uses a lightweight model (e.g., Llama-3.2-1B) to propose tokens for a larger target model (e.g., Llama-3.1-8B):
from vllm import LLM, SamplingParams
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
max_num_seqs=4,
max_model_len=2048,
long_prefill_token_threshold=128,
quantization="mxfp6",
kv_cache_dtype="mxint8",
additional_config={
"override_qaic_config": {
"device_group": [0, 1, 2, 3],
"num_cores": 10, # 10 cores for target model
},
"draft_override_qaic_config": {
"device_group": [0, 1, 2, 3], # Same device
"num_cores": 6, # 6 cores for draft model
},
},
speculative_config={
"method": "draft_model",
"model": "meta-llama/Llama-3.2-1B-Instruct",
"num_speculative_tokens": 3,
},
)
Docker example:
docker run --rm -it --network host \
--device /dev/accel/ \
--shm-size=4gb \
-e HF_TOKEN=<your_hf_token> \
ghcr.io/quic/cloud_ai_inference_vllm:1.21.2.0 \
--host 127.0.0.1 --port 8000 \
--model meta-llama/Llama-3.1-8B-Instruct \
--max-model-len 2048 \
--max-num-seq 4 \
--max-seq-len-to-capture 128 \
--quantization mxfp6 \
--kv-cache-dtype mxint8 \
--speculative-config '{"method":"draft_model","model":"meta-llama/Llama-3.2-1B-Instruct","num_speculative_tokens":3}' \
--additional-config '{"override_qaic_config":{"device_group":[0,1,2,3],"num_cores":10},"draft_override_qaic_config":{"device_group":[0,1,2,3],"num_cores":6}}'
QEfficient Reference
Draft model compilation requires separate QPC generation. See the QEfficient SpD Guide for compilation details.
Core Allocation¶
On a Cloud AI 100 Ultra card (4 QIDs, 16 cores per QID), cores are split between the target model (TLM) and draft model (DLM) on each QID:
Per QID (16 NSP cores):
+--------------------+----------------+
| Target Model (10) | Draft Model (6)|
+--------------------+----------------+
Applied across QID 0-3 -- both models share the same device group.
No additional hardware is required — both models run on the same device.
Default allocation
When no explicit num_cores configuration is provided, cores are split 8/8 (equal between target and draft). The 10/6 split shown above is a recommended allocation for an 8B target + 1B draft.
Performance Tuning¶
Tuning parameters
| Parameter | Effect | Recommendation |
|---|---|---|
num_speculative_tokens |
Tokens proposed per step | 3-5 (higher = more aggressive) |
override_qaic_config.num_cores |
Compute for verification (target) | 10-12 for 8B models |
draft_override_qaic_config.num_cores |
Compute for proposing (draft) | 4-6 for 1B models |
max_num_seqs |
Batch size | Lower batch = higher acceptance rate |
LD_PRELOAD libiomp5 for CPU-bound SpD proposers (AOT mode)
For AOT mode, ngram/suffix SpD proposers run on host CPU and benefit
from Intel OpenMP (libiomp5.so) runtime tuning — on both Intel and
AMD hosts. Benchmarks on an AMD EPYC host showed meaningful throughput
gains for CPU-bound proposers like ngram, with the improvement growing
at higher batch sizes (actual gains are workload-dependent).
# install Intel OpenMP (provides libiomp5.so) into your active venv
pip install intel-openmp
# manually find the path
IOMP_PATH=$(find "$(python -c 'import sysconfig; print(sysconfig.get_paths()["data"])')" -iname "libiomp5.so" | head -1)
# add it to LD_PRELOAD
export LD_PRELOAD="$IOMP_PATH:$LD_PRELOAD"
Set VLLM_DISABLE_LD_PRELOAD_OPT=1 to opt out of this tuning.
SpD with Disaggregated Serving¶
SpD can be combined with disaggregated serving — proposals are generated and verified entirely on the decode node. See Disaggregated Serving.