적응형 추측 디코딩

적응형 추측 디코딩 (Adaptive Speculative Decoding)

적응형 추측 디코딩은 SGLang이 speculative_num_steps/speculative_num_draft_tokens을 런타임에 조정할 수 있게 해줍니다. 서버 전체 수명 동안 단일 고정 값을 유지하는 대신, 시간에 따라 accept 길이가 변하는 워크로드를 위해 설계됐어요. 하나의 정적 step 수로는 거의 최적이 되기 어렵습니다.

출처: 문서

본문

적응형 추측 디코딩은 SGLang이 speculative_num_steps/speculative_num_draft_tokens을 서버 전체 수명 동안 단일 고정 값 대신 런타임에 조정하게 합니다. 시간에 따라 accept 길이가 바뀌는 워크로드를 위해 설계되었으며, 하나의 정적 step 수가 거의 최적이 되기 어렵습니다.

현재 지원 (Current support)

  • --speculative-algorithm EAGLE 또는 EAGLE3
  • --speculative-eagle-topk 1
  • 어느 조건이든 충족되지 않으면 SGLang은 정적 추측 설정으로 폴백

적응형 step이 왜 도움이 되는가 (Why adaptive steps help)

speculative_num_steps는 각 추측 라운드에서 드래프트 모델의 자동회귀(autoregressive) step이 몇 개나 실행되는지 제어합니다. 실무에서 최적 값은 현재 워크로드에 따라 달라져요.

  • num_steps가 너무 작으면 드래프트 모델이 더 많은 토큰을 accept할 수 있었는데 라운드가 너무 일찍 멈춥니다.
  • num_steps가 너무 크면 드래프트 모델이 target 모델이 거부할 많은 후보 토큰을 만들어 추가 드래프트 작업이 낭비됩니다.
  • 높은 배치 크기에서는 낭비되는 각 드래프트 step의 비용이 배치 내 모든 시퀀스에 곱해지므로, 최적 step 수는 낮은 배치 크기보다 보통 더 낮습니다.

실제 트래픽은 종종 high-acceptance와 low-acceptance 단계 사이를 오가고, 배치 크기도 계속 변합니다. 적응형 모드는 단일 전역 num_steps를 하드코딩하는 대신 런타임에 두 신호를 둘 다 따릅니다.

설계 개요 (Design overview)

적응형 메커니즘은 세 부분으로 구성됩니다:

  • AdaptiveSpeculativeParams: EMA 기반 정책
  • SpecRuntimeState: tier별 런타임 상태 번들
  • AdaptiveController: 현재 배치 크기에 대해 정책을 조회하고 일치하는 런타임 상태를 활성화하는 코디네이터

배치 크기별 독립 추적 (Per-batch-size independent tracking)

컨트롤러는 각 배치 크기 범위에 대해 독립적인 EMA 트래커를 유지하므로, 작은 BS의 관측이 큰 BS 신호를 오염시키지 않습니다. 각 BS 범위는 자신의 후보 step, 히스테리시스 임계값, 천장 계수를 가질 수 있습니다.

BS 범위는 설정 파일에서 하한으로 정의됩니다(예: 키 "1""8"은 BS 1–7이 한 슬롯, BS 8+가 다른 슬롯을 사용함을 뜻합니다). SpecRuntimeState 객체는 step 수가 같은 BS 범위 간에 공유됩니다 — 각 상태는 해당 step의 도달 가능한 패딩 배치 크기에 대해 캡처된 CUDA 그래프를 소유합니다.

---
title: "SpecRuntimeState — speculative_num_steps / speculative_num_draft_tokens"
---
graph LR
  subgraph SR[" "]
    direction LR
    subgraph D["Draft stage"]
      direction TB
      d1[attn_backend]
      d2[cuda_graph]
    end
    subgraph V["Verify stage"]
      direction TB
      v1[attn_backend]
      v2[cuda_graph]
    end
    subgraph E["Extend stage"]
      direction TB
      e1[attn_backend]
      e2[cuda_graph]
    end
  end

이것은 CudaGraphRunner가 형태 의존적이기 때문에 중요합니다. 각 후보 tier는 자신의 그래프와 백엔드 상태를 소유하므로, 런타임 전환은 참조 교환이지 온라인 그래프 재캡처가 아닙니다.

런타임 흐름 (Runtime flow)

적응형 업데이트는 두 곳에서 일어납니다:

  1. Pre-draft: 현재 배치 크기에 대한 최적 step을 조회하고 다르면 활성화
  2. Post-verify: 관측된 accept 길이로 일치하는 BS 슬롯의 EMA를 업데이트
---
title: "EAGLEWorker.forward_batch_generation() — decode path"
---
flowchart TD
  Z["⓪ activate_step_by_batch(batch_size)<br/>query optimal step for current BS range, activate if different"]
  A["① draft(batch)<br/>draft model multi-step generation with current tier"]
  B["② verify(batch, spec_info)<br/>target model tree verification → produces num_correct_drafts_per_req"]
  C["③ forward_draft_extend_after_decode(batch)<br/>draft model KV-cache catch-up"]
  D["④ adaptive_controller.on_verify_complete(num_correct_drafts_per_req, batch_size)<br/>update EMA for matching BS slot, apply warmup / interval / hysteresis gates<br/>if tier changed, select a pre-built state from pool"]
  E["worker.apply_runtime_state(state)"]
  Z --> A --> B --> C --> D --> E

Tier 전환은 현재 라운드가 끝난 후에 일어납니다. 백엔드와 CUDA 그래프는 라운드 중간에 절대 교체되지 않습니다.

정책이 결정하는 방식 (How the policy decides)

각 verify 패스 후 SGLang은 요청당 accept된 드래프트 길이를 읽고, 배치 평균을 계산한 뒤 지수 이동 평균(EMA)으로 평활화하고, 일치하는 BS 슬롯에 대해 후보 tier 사이를 전환합니다.

결정 로직은 의도적으로 보수적입니다:

  • warmup_batches는 처음 몇 배치를 건너뜀
  • update_interval은 매 배치마다 전환하는 것을 피함
  • down_hysteresisup_hysteresis는 진동을 줄임
  • ceiling_coeff — 선택적 EMA 천장 규칙이 드래프트 품질에 비례해 num_steps를 상한으로 제한, 높은 BS에서 과도한 추측 방지

개념적으로 정책은 관측된 acceptance를 한 step 넘어 탐색합니다:

target_steps ≈ clamp(round(ema_accept_len) + 1, min(candidate_steps), max(candidate_steps))

그래서 최근 요청이 더 많은 드래프트 토큰을 일관되게 accept하면 정책은 위로 움직이려 하고, 더 일찍 거부하기 시작하면 아래로 움직이려 합니다.

사용법 (Usage)

--speculative-adaptive-config는 선택 사항이지만, 추측 설정 자체는 적응형 모드에 유효해야 합니다.

python3 -m sglang.launch_server \
    --model meta-llama/Llama-2-7b-chat-hf \
    --speculative-algorithm EAGLE \
    --speculative-draft-model-path lmsys/sglang-EAGLE-llama2-chat-7B \
    --speculative-eagle-topk 1 \
    --speculative-num-steps 3 \
    --speculative-num-draft-tokens 4 \
    --speculative-adaptive

기본값을 오버라이드하려면 --speculative-adaptive-config /path/to/adaptive_spec.json을 추가하세요.

예제 설정:

{
  "ema_alpha": 0.2,
  "warmup_batches": 10,
  "update_interval": 5,
  "1": {"candidate_steps": [1, 3, 7], "up_hysteresis": 0.0, "down_hysteresis": -0.25, "ceiling_coeff": 0},
  "8": {"candidate_steps": [1],       "up_hysteresis": 0.0, "down_hysteresis": 0.0,   "ceiling_coeff": 0}
}

정수가 아닌 키(ema_alpha, warmup_batches, update_interval)는 모든 BS 슬롯에 적용되는 전역 오버라이드입니다. 정수 키("1", "8")는 BS별 슬롯을 정의합니다.

설정 파일 참조 (Config file reference)

설정 파일은 선택 사항입니다. 제공되면 각 정수 BS-슬롯 키가 candidate_steps를 지정해야 하며, 다른 모든 키는 기본값으로 폴백합니다.

BS별 슬롯 파라미터 (Per-BS slot parameters)

Key Default Meaning
candidate_steps required 이 BS 범위의 후보 speculative_num_steps tier. 양의 정수의 비어 있지 않은 목록이어야 함. 생략하면 설정 오류 발생
down_hysteresis -0.25 더 작은 step으로 이동하기 전의 추가 마진
up_hysteresis 0.0 더 큰 step으로 이동하기 전의 추가 마진
ceiling_coeff 0 (disabled) EMA 천장 계수. > 0으로 설정하면 드래프트 품질에 비례해 step을 상한

전역 파라미터 (Global parameters)

Key Default Meaning
ema_alpha 0.2 Accept된 드래프트 길이의 EMA 평활화 계수
update_interval 5 Warmup 후 verify 배치 단위로 재계산 간격
warmup_batches 10 전환 전 관찰할 verify 배치 수

모니터링 (Monitoring)

/server_info로 활성 tier와 acceptance 메트릭을 확인할 수 있습니다:

curl -s http://127.0.0.1:30000/server_info | jq '.internal_states[0] | {speculative_num_steps, avg_spec_accept_length}'
  • speculative_num_steps는 현재 활성 tier
  • avg_spec_accept_length는 서버가 위로 갈지 아래로 갈지 설명하는 데 도움

튜닝 팁 (Tuning tips)

  • 내장 기본값(보수적)으로 시작하세요 — 모든 드래프트 모델 품질에 안전합니다
  • 강한 드래프트 모델에는 천장 규칙이 있는 공격적 설정을 사용하세요
  • 시작 GPU 메모리 오버헤드를 낮추려면 후보 step을 더 적게 사용하세요
  • 더 빠르게 반응하려면 ema_alpha를 올리고, 더 안정적으로 하려면 낮추세요
  • tier 전환이 너무 시끄러우면 warmup_batchesupdate_interval을 올리세요
  • 높은 배치 크기에서는 좁은 사다리(예: [1, 2] 또는 [1])가 넓은 것보다 종종 더 잘 동작합니다
  • 워크로드가 이미 안정적이고 정적 설정 하나가 잘 튜닝되어 있다면 적응형 모드가 크게 도움이 되지 않을 수 있습니다

내장 기본값은 보수적입니다 — 모든 드래프트 모델에 안전하지만 강한 모델에는 과소 추측할 수 있습니다. 아래 중 하나를 JSON 파일로 저장해 --speculative-adaptive-config로 전달하세요.

보수적 (Conservative) — 약한 드래프트 모델용

이것이 내장 기본값입니다. BS 8–31은 [1, 3]을 허용하고, BS≥32는 낭비된 계산을 피하기 위해 step=1로 고정합니다. MiniMax-M2.5, DSV4 같은 모델에 가장 좋아요.

{
  "1":  {"candidate_steps": [1, 3, 7], "up_hysteresis": 0.0, "down_hysteresis": -0.25, "ceiling_coeff": 0},
  "8":  {"candidate_steps": [1, 3],    "up_hysteresis": 0.0, "down_hysteresis": 0.0,   "ceiling_coeff": 0},
  "32": {"candidate_steps": [1],       "up_hysteresis": 0.0, "down_hysteresis": 0.0,   "ceiling_coeff": 0}
}

공격적 (Aggressive) — 강하거나 변동이 큰 드래프트 모델용

천장 규칙이 있는 더 넓은 사다리를 사용해 높은 BS에서 추측을 상한으로 제한합니다. GLM-4.7-FP8 같은 모델에 가장 좋아요.

{
  "1":   {"candidate_steps": [1, 3, 7], "up_hysteresis": 0.0, "down_hysteresis": -0.25, "ceiling_coeff": 0},
  "8":   {"candidate_steps": [1, 3, 7], "up_hysteresis": 0.0, "down_hysteresis": -0.25, "ceiling_coeff": 3.0},
  "64":  {"candidate_steps": [1, 3],    "up_hysteresis": 0.0, "down_hysteresis": -0.25, "ceiling_coeff": 1.67},
  "128": {"candidate_steps": [1, 3],    "up_hysteresis": 0.0, "down_hysteresis": -0.25, "ceiling_coeff": 1.2}
}

커스텀 모델별 설정 (Custom per-model config)

최상의 성능을 위해 다양한 배치 크기에서 서로 다른 정적 num_steps 값으로 특정 모델을 벤치마크한 다음, 각 범위의 최적 step과 일치하는 BS별 설정을 구축하세요. 잘 튜닝된 모델별 설정이 위의 일반 프리셋보다 더 좋을 수 있습니다.

더 알아보기 (Learn more)