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 백엔드 (실험 기능)

methodcustom_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_sizespeculative_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

더 알아보기 (Learn more)