Speculative Decoding
Speculative Decoding (추측 디코딩)
Speculative Decoding(추측 디코딩)은 중간~낮은 QPS(초당 쿼리 수, queries per second)의 메모리 바운드 워크로드에서 토큰 간 지연 시간(inter-token latency)을 줄여주는 기법이에요. 이 문서에서는 vLLM에서 Speculative Decoding을 설정하고 활용하는 방법을 설명해요. 자체 드래프트 모델을 학습해 vLLM과 최적화된 추측 디코딩을 구성하고 싶다면 vllm-project/speculators를 참고하면 돼요.
출처: 문서
본문
vLLM의 추측(Speculation) 방법
vLLM은 다양한 종류의 추측 디코딩 방법을 지원해요. EAGLE, MTP, 드래프트 모델, PARD, MLP 같은 모델 기반 방법이 가장 큰 지연 시간 감소 효과를 주고, n-gram이나 suffix 디코딩 같은 더 단순한 방법은 피크 트래픽 동안 워크로드를 늘리지 않으면서 적당한 속도 향상을 제공해요.
- EAGLE
- Multi-Token Prediction (MTP)
- Draft Model (드래프트 모델)
- Parallel Draft Model (PARD)
- Multi-Layer Perceptron (MLP)
- N-Gram
- Suffix Decoding
- Hidden State Extraction (히든 스테이트 추출)
- Custom Proposer Backend (실험 기능)
- Dynamic Speculative Decoding
- Adaptive Verification (적응형 검증)
- Per-Request Acceptance Metrics (요청별 수락 지표)
방법 선택 요약
방법 선택의 출발점으로 아래 정성적 표를 활용해 보세요. 실제 성능 향상은 모델 계열, 트래픽 패턴, 하드웨어, 샘플링 설정에 따라 달라져요.
| Method | Low QPS (지연 시간 중점) | High QPS (처리량 중점) | 비고 |
|---|---|---|---|
| EAGLE | 높은 이득 | 중~높은 이득 | 강력한 범용 모델 기반 방법 |
| MTP | 높은 이득 | 중~높은 이득 | 타깃 모델이 네이티브 MTP를 지원할 때 최고 |
| Draft model | 높은 이득 | 중간 이득 | 별도의 드래프트 모델이 필요 |
| Parallel Draft Model | 높은 이득 | 중~높은 이득 | 드래프트 모델 지연 시간이 낮음 |
| MLP speculator | 중~높은 이득 | 중간 이득 | 호환되는 MLP 스펙큘레이터가 있을 때 좋음 |
| N-gram | 낮~중간 이득 | 중간 이득 | 가볍고 켜기 쉬움 |
| Suffix decoding | 낮~중간 이득 | 중간 이득 | 추가 드래프트 모델 없음, 동적 추측 깊이 |
| Custom Proposer | 다양함 | 다양함 | 직접 만든 proposer 클래스 (실험 기능) |
| Dynamic Speculative Decoding | 높은 이득 | 기본 SD 방법보다 높음 | RL이나 QPS가 변동하는 워크로드에 유용 |
| Adaptive Verification | 높은 이득 | 기본 SD 방법보다 높음 | drafter 신뢰도에 따라 요청별 검증 크기 조정, 현재는 DSpark 전용 |
자신의 환경에서 재현 가능한 측정을 하려면 examples/features/speculative_decoding/spec_decode_offline.py 또는 벤치마크 CLI 가이드를 사용하면 돼요.
커스텀 Proposer 백엔드 (실험 기능)
method를 custom_class로 설정하고 클래스의 전체 모듈 경로를 제공하면, 자신만의 커스텀 proposer 클래스를 스펙큘레이티브 디코딩에 끼워 넣을 수 있어요. 커스텀 클래스는 인스턴스화 시 VllmConfig를 받아야 하고 propose 메서드를 구현해야 해요.
설정 예시:
speculative_config.method = "custom_class"speculative_config.model = "your_module.YourCustomProposerClass"
--speculative-config 스키마
CLI에서 --speculative-config를 사용해 추측 디코딩 설정을 JSON 객체로 전달할 수 있어요:
vllm serve <target-model> \
--speculative-config '{
"method": "draft_model",
"model": "<draft-model>",
"num_speculative_tokens": 5
}'
동일한 키는 Python에서 LLM(..., speculative_config={...})로도 받을 수 있어요. 아래 표는 이 JSON 객체에서 자주 쓰는 사용자 대상 키를 정리한 것으로, 완전한 스키마 참조는 아니에요. 자세한 내용은 생성된 engine arguments 참조와 vllm.config.SpeculativeConfig API 문서를 확인하세요.
공통 키
각종 추측 디코딩 설정에서 공통으로 쓰는 키들이에요. 다만 일부는 draft_model, mtp, eagle3, dflash 같은 모델 기반 방법에만 적용돼요.
| Key | Type | Default | 허용 값 / 의미 |
|---|---|---|---|
method |
string | None | 추측 방법. 흔한 값: draft_model, ngram, suffix, mtp, eagle3, dflash. 생략 시 vLLM이 가능하면 주어진 설정에서 방법을 유추 |
model |
string | None | 드래프트 모델, EAGLE head, 또는 보조 모델 식별자. ngram, ngram_gpu, suffix, mtp에서는 보통 생략 가능 |
num_speculative_tokens |
integer > 0 | None | 스텝마다 제안할 추측 토큰 수. 모델 메타데이터에서 추론되지 않는 방법에 필수 |
draft_tensor_parallel_size |
integer >= 1 | None | 드래프트 모델의 텐서 병렬 크기 |
max_model_len |
integer >= 1 | None | 드래프트 모델의 최대 컨텍스트 길이 |
parallel_drafting |
boolean | false | 병렬 드래프트 토큰 생성을 활성화. EAGLE와 드래프트 모델 방법에서만 호환 |
rejection_sample_method |
string | standard | standard, synthetic, 또는 block |
synthetic_acceptance_rates |
list[float] | None | 합성 리젝션 샘플링용 위치별 무조건 수락율. 각 항목은 [0, 1] 범위, 길이는 num_speculative_tokens와 같아야 하며 비증가(non-increasing)여야 함 |
synthetic_acceptance_length |
float | None | 합성용 목표 평균 수락 길이. [1, num_speculative_tokens + 1] 범위. synthetic_acceptance_rates와 상호 배타적 |
use_heterogeneous_vocab |
boolean | false | 드래프트와 타깃 모델이 서로 다른 어휘를 쓰도록 허용. 초기화 시 토큰 수준 교집합을 만들고 드래프트 logit을 공유 토큰으로만 제한. method=draft_model에서만 호환. 활성화 시 확률적 드래프트 샘플링(draft_sample_method='probabilistic')은 아직 미지원 |
참고: Gemma 4 assistant 체크포인트는 일반 드래프트 모델이 아니라 Gemma 4 MTP 스펙큘레이터로 처리돼요. assistant 체크포인트를
model에 넣고"method": "mtp"를 사용하세요 (MTP 가이드 참고). 시작 로그에 Gemma 4 assistant 체크포인트에 대해SpeculativeConfig(method='draft_model', ...)가 보인다면 설치된 vLLM 버전에 해당 경로의 Gemma 4 MTP 지원이 없는 것이니, generic 드래프트 모델로 강제하지 말고 Gemma 4 MTP 지원이 포함된 버전으로 업그레이드하세요.
방법별 키
N-gram
| Key | Type | Default | 의미 |
|---|---|---|---|
prompt_lookup_max |
integer >= 1 | 조회 범위가 둘 다 생략되면 5, 아니면 prompt_lookup_min을 따름 |
최대 n-gram 윈도우 크기 |
prompt_lookup_min |
integer >= 1 | 조회 범위가 둘 다 생략되면 5, 아니면 prompt_lookup_max를 따름 |
최소 n-gram 윈도우 크기 |
예시:
vllm serve <target-model> \
--speculative-config '{
"method": "ngram",
"num_speculative_tokens": 4,
"prompt_lookup_min": 2,
"prompt_lookup_max": 5
}'
Suffix 디코딩
| Key | Type | Default | 의미 |
|---|---|---|---|
suffix_decoding_max_tree_depth |
integer | 24 | 접두사 매칭과 추측 트리의 최대 결합 깊이 |
suffix_decoding_max_cached_requests |
integer | 10000 | 전역 suffix 트리에 캐시하는 최대 요청 수. 0이면 전역 캐시 비활성화 |
suffix_decoding_max_spec_factor |
float | 1.0 | 추측 길이를 접두사 매칭 길이의 배수로 제한 |
suffix_decoding_min_token_prob |
float | 0.1 | 토큰을 추측하기 위해 필요한 최소 추정 토큰 확률 |
예시:
vllm serve <target-model> \
--speculative-config '{
"method": "suffix",
"num_speculative_tokens": 8,
"suffix_decoding_max_tree_depth": 24,
"suffix_decoding_max_cached_requests": 10000,
"suffix_decoding_max_spec_factor": 1.0,
"suffix_decoding_min_token_prob": 0.1
}'
교차 어휘 드래프트 모델 (TLI)
기본적으로 vLLM은 드래프트와 타깃 모델이 동일한 어휘(vocabulary)를 공유할 것을 요구해요. use_heterogeneous_vocab: true를 설정하면 Token-Level Intersection (TLI) 알고리즘이 활성화되어, 다른 tokenizer를 가진 다른 모델 계열의 드래프트 모델을 사용할 수 있게 돼요.
초기화 시 vLLM은 토큰 문자열을 정규화해 두 어휘 간의 매핑을 만들고 그 교집합을 계산해요. 샘플링 전에 드래프트 logit을 공유 토큰으로 제한하고, 리젝션 샘플링 전에 샘플링된 토큰 ID를 타깃 어휘로 변환해요.
from vllm import LLM, SamplingParams
llm = LLM(
model="Qwen/Qwen3-8B",
speculative_config={
"method": "draft_model",
"model": "HuggingFaceTB/SmolLM2-135M-Instruct",
"num_speculative_tokens": 3,
"use_heterogeneous_vocab": True,
},
gpu_memory_utilization=0.5,
)
참고 사항
--speculative-config는 CLI에서 JSON 객체를 기대해요. YAML 설정 파일에서는 이스케이프된 JSON 문자열 대신 중첩 매핑(nested mapping)을 사용하세요.tensor_parallel_size는speculative_config에서 유효한 키가 아니에요. 대신draft_tensor_parallel_size를 사용하세요.temperature,top_p같은 키는 샘플링 파라미터이지--speculative-config필드가 아니에요.target_model_config,draft_model_config,target_parallel_config,draft_parallel_config,draft_load_config같은 내부 필드는 vLLM이 채우는 것이므로 사용자가 직접 설정해서는 안 돼요.use_heterogeneous_vocab는 현재 greedy 드래프트 샘플링만 지원해요. 확률적 수락(temperature > 0드래프트 샘플링)은 아직 미지원이며 향후 릴리스에서 추가될 예정이에요.
Speculative Decoding의 무손실 보장
vLLM의 추측 디코딩은 정확도를 유지하면서 추론 효율을 높이는 것을 목표로 해요. 여기서는 추측 디코딩의 무손실 보장을 세 가지 영역으로 나눠 설명할게요.
- 이론적 무손실 (Theoretical Losslessness) — 추측 디코딩 샘플링은 하드웨어 수치 정밀도의 한계까지 이론적으로 무손실이에요. 부동소수점 오차로 출력 분포에 약간의 변동이 생길 수 있는데, 이는 "Accelerating Large Language Model Decoding with Speculative Sampling"에서 논의돼요.
- 알고리즘적 무손실 (Algorithmic Losslessness) — vLLM의 추측 디코딩 구현은 알고리즘적으로 무손실임이 검증돼 있어요. 핵심 검증 테스트는 다음과 같아요.
- Rejection Sampler Convergence: vLLM의 rejection sampler 샘플이 타깃 분포와 일치하는지 확인해요.
- Greedy Sampling Equality: 추측 디코딩이 있는 greedy 샘플링이 없는 경우와 일치하는지 확인해요. 이는 vLLM의 추측 디코딩 프레임워크가 vLLM forward pass와 vLLM rejection sampler와 결합될 때 무손실 보장을 제공한다는 것을 검증해요.
tests/spec_decode/e2e의 거의 모든 테스트가 이 속성을 확인해요.
- vLLM Logprob 안정성 — vLLM은 현재 토큰 로그 확률(logprobs)의 안정성을 보장하지 않아요. 같은 요청이라도 실행에 따라 출력이 달라질 수 있어요. 자세한 내용은 FAQ의 "Can the output of a prompt vary across runs in vLLM?" 항목을 참고하세요.
vLLM은 추측 디코딩에서 무손실을 위해 노력하지만, 추측 디코딩 사용 유무에 따라 출력 변동이 생길 수 있는 요인이 다음과 같아요.
- 부동소수점 정밀도: 하드웨어 수치 정밀도의 차이가 출력 분포의 미세한 불일치를 일으킬 수 있어요.
- 배치 크기와 수치 안정성: 배치 크기 변화가 logprobs와 출력 확률 변동을 일으킬 수 있는데, 이는 배치 연산의 비결정적 동작이나 수치 불안정성 때문일 수 있어요.
완화 전략은 FAQ의 "Can the output of a prompt vary across runs in vLLM?" 항목을 참고하세요.
알려진 기능 비호환성
- 파이프라인 병렬화(pipeline parallelism)는
vllm<=0.15.0에서 추측 디코딩과 함께 사용할 수 없어요. - 드래프트 모델을 사용한 추측 디코딩은
vllm<=0.10.0에서 지원되지 않아요.
vLLM 기여자를 위한 리소스
- [vLLM Office Hours #40] Intro to Speculators
- A Hacker's Guide to Speculative Decoding in vLLM
- What is Lookahead Scheduling in vLLM?
- 배치 확장(batch expansion) 관련 정보
- Dynamic speculative decoding