Speculative Decoding 가이드¶
LLM 추론 가속화를 위한 Speculative Decoding 기법 실무 가이드.
개요¶
Speculative Decoding은 작은 Draft 모델이 여러 토큰을 미리 생성하고, 큰 Target 모델이 한 번에 검증하는 방식으로 추론 속도를 높이는 기법이다.
| 구분 | 설명 |
|---|---|
| 핵심 아이디어 | Draft-then-Verify 패러다임 |
| 속도 향상 | 2-3x (태스크/모델 의존) |
| 품질 | Lossless (동일한 출력 분포 보장) |
| 적용 대상 | Autoregressive LLM 전반 |
동작 원리¶
┌─────────────────────────────────────────────────────────┐
│ Speculative Decoding │
├─────────────────────────────────────────────────────────┤
│ │
│ 1. Draft Phase │
│ ┌─────────────┐ │
│ │ Draft Model │ ──→ [t1, t2, t3, t4, t5] │
│ │ (Small) │ 예측 토큰들 (γ개) │
│ └─────────────┘ │
│ │
│ 2. Verify Phase │
│ ┌─────────────┐ │
│ │Target Model │ ──→ 병렬 검증 (1 forward pass) │
│ │ (Large) │ │
│ └─────────────┘ │
│ │
│ 3. Accept/Reject │
│ [t1 ✓] [t2 ✓] [t3 ✓] [t4 ✗] [t5 -] │
│ accepted=3, 다음 토큰 = Target의 t4' 사용 │
│ │
└─────────────────────────────────────────────────────────┘
수학적 배경¶
Draft 모델 확률 분포 \(q(x)\), Target 모델 확률 분포 \(p(x)\)일 때:
Acceptance 확률: $\(\alpha = \min\left(1, \frac{p(x)}{q(x)}\right)\)$
Rejection Sampling: - \(q(x) \leq p(x)\): 항상 accept - \(q(x) > p(x)\): 확률적으로 reject
이 방식은 Target 모델의 출력 분포를 정확히 재현한다 (Lossless).
주요 변형¶
1. Standard Speculative Decoding¶
# 기본 구조
def speculative_decode(draft_model, target_model, prompt, gamma=5):
tokens = []
while not done:
# Draft: γ개 토큰 생성
draft_tokens = draft_model.generate(prompt, num_tokens=gamma)
# Verify: 한 번의 forward pass로 검증
logits = target_model.forward([prompt + draft_tokens])
# Accept/Reject
accepted = verify_and_accept(draft_tokens, logits)
tokens.extend(accepted)
return tokens
2. Self-Speculative Decoding¶
같은 모델의 조기 레이어(Early Exit)를 Draft로 사용:
| 장점 | 단점 |
|---|---|
| 별도 Draft 모델 불필요 | 모델 수정 필요 |
| 메모리 효율적 | 모든 아키텍처에 적용 어려움 |
| KV Cache 공유 가능 |
3. Staged Speculative Decoding¶
여러 단계의 Draft 모델 사용:
4. DistillSpec (Online Speculative Decoding)¶
Knowledge Distillation으로 Draft 모델을 온라인으로 개선:
- 런타임에 Draft 모델 adaptation
- Token acceptance rate 향상
- UC Berkeley 2025 연구
5. Mirror Speculative Decoding¶
Apple 2026 연구. 병렬 Draft 경로로 Serial 병목 해소:
성능 분석¶
Speedup 공식¶
\[\text{Speedup} = \frac{1 - \alpha^{\gamma+1}}{(1-\alpha)(c \cdot \gamma + 1)}\]
- \(\alpha\): 평균 acceptance rate
- \(\gamma\): speculation length (Draft 토큰 수)
- \(c\): Draft/Target 속도 비율
최적 γ 선택¶
| Acceptance Rate | 권장 γ |
|---|---|
| > 0.9 | 8-12 |
| 0.7-0.9 | 5-8 |
| 0.5-0.7 | 3-5 |
| < 0.5 | 2-3 |
태스크별 성능¶
| 태스크 | 예상 Speedup | 비고 |
|---|---|---|
| 번역 | 2.5-3.0x | 높은 예측 가능성 |
| 요약 | 2.0-2.5x | |
| 코드 생성 | 2.0-2.8x | 구조적 패턴 |
| 대화 | 1.5-2.0x | 다양한 응답 |
| 창작 | 1.3-1.8x | 낮은 예측 가능성 |
구현 가이드¶
vLLM 구현¶
from vllm import LLM, SamplingParams
# Draft + Target 모델 설정
llm = LLM(
model="meta-llama/Llama-3-70B",
speculative_model="meta-llama/Llama-3-8B",
num_speculative_tokens=5,
speculative_draft_tensor_parallel_size=1,
)
# 생성
outputs = llm.generate(prompts, SamplingParams(temperature=0.7))
HuggingFace 구현¶
from transformers import AutoModelForCausalLM, AutoTokenizer
target = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3-70B")
draft = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3-8B")
outputs = target.generate(
inputs,
assistant_model=draft,
do_sample=True,
temperature=0.7,
)
TensorRT-LLM 구현¶
# config 설정
config = {
"speculative_decoding_mode": "draft_tokens_external",
"max_draft_tokens": 5,
"draft_model_path": "/path/to/draft",
}
Draft 모델 선택¶
선택 기준¶
- 어휘 호환성: 동일한 tokenizer 또는 vocabulary alignment 필요
- 속도 비율: Draft는 Target의 10-20% 크기가 이상적
- 도메인 적합성: 태스크 도메인에 맞는 Draft 선택
추천 조합¶
| Target Model | Draft Model | 비고 |
|---|---|---|
| Llama 3 70B | Llama 3 8B | 동일 계열 |
| Mistral 7B | Mistral 7B (4bit) | 양자화 버전 |
| GPT-4 | GPT-3.5 | API 기반 |
| Qwen2 72B | Qwen2 7B | 동일 계열 |
Vocabulary Mismatch 해결¶
ICML 2025 연구 - Heterogeneous Vocabulary 지원:
# Vocabulary alignment layer
class VocabAligner:
def __init__(self, draft_vocab, target_vocab):
self.mapping = self._build_alignment(draft_vocab, target_vocab)
def align(self, draft_tokens):
return [self.mapping.get(t, t) for t in draft_tokens]
프로덕션 고려사항¶
메모리 관리¶
배치 처리¶
- Homogeneous Batch: 동일 prompt 길이 → 효율적
- Heterogeneous Batch: Padding 오버헤드 발생
- Continuous Batching: vLLM 권장
동적 γ 조정¶
class AdaptiveSpeculator:
def __init__(self, initial_gamma=5):
self.gamma = initial_gamma
self.acceptance_history = []
def adjust_gamma(self, accepted_count, total_count):
rate = accepted_count / total_count
if rate > 0.85:
self.gamma = min(12, self.gamma + 1)
elif rate < 0.5:
self.gamma = max(2, self.gamma - 1)
적용 시나리오¶
적합한 경우¶
- 긴 텍스트 생성 (요약, 번역, 문서 작성)
- 예측 가능한 패턴 (코드, 템플릿)
- Latency-sensitive 애플리케이션
- 단일 요청 처리
부적합한 경우¶
- 매우 짧은 응답 (< 20 토큰)
- 극도로 창의적인 태스크
- 높은 temperature (> 1.0)
- GPU 메모리가 제한적인 환경
비교: 다른 추론 가속 기법¶
| 기법 | Speedup | 품질 손실 | 복잡도 |
|---|---|---|---|
| Speculative Decoding | 2-3x | 없음 | 중간 |
| Quantization (INT8) | 1.5-2x | 약간 | 낮음 |
| Continuous Batching | 2-4x (처리량) | 없음 | 중간 |
| KV Cache Optimization | 1.3-1.5x | 없음 | 낮음 |
| Model Pruning | 1.5-2x | 있음 | 높음 |
핵심 논문¶
| 논문 | 연도 | 기여 |
|---|---|---|
| Fast Inference via Speculative Decoding | 2022 | 원본 제안 (Google) |
| SpecInfer | 2024 | Tree-based speculation |
| DistillSpec | 2025 | Online adaptation |
| Mirror Speculative Decoding | 2026 | Parallel draft paths |
| Heterogeneous Vocabulary SD | 2025 | Cross-vocab support |
요약¶
Speculative Decoding은 LLM 추론 속도를 2-3배 높이면서도 출력 품질을 완전히 보존하는 강력한 기법이다. Draft 모델 선택, γ 튜닝, 메모리 관리에 주의하면 프로덕션 환경에서 효과적으로 활용할 수 있다.