이 레포가 무엇을 하는 물건인가.
DeepSpec은 추측 디코딩(speculative decoding)에 쓰는 드래프트(초안) 모델을 만드는 도구 모음이다. 큰 모델(타깃)이 토큰을 한 개씩 느리게 뱉는 대신, 작고 빠른 드래프트 모델이 여러 토큰을 미리 추측해 두면, 큰 모델은 그 추측을 한 번의 계산으로 검증만 한다. 맞은 만큼은 공짜로 건너뛰니 전체 속도가 2~3배 빨라진다.
중요한 건 출력이 바뀌지 않는다는 점이다. 검증 단계가 수학적으로 "큰 모델 혼자 돌렸을 때와 똑같은 확률분포"를 보장한다(거절 샘플링). 즉 품질 손실 0으로 속도만 얻는다.
이 레포는 단순히 "드래프트 모델 하나"를 주는 게 아니라, 드래프트 모델을 밑바닥부터 만들어 쓰는 전 과정을 담은 풀스택이다: ① 학습 데이터 준비(프롬프트 다운로드 → 타깃 모델로 정답 재생성 → 은닉상태 캐시), ② 드래프트 모델 학습(지식 증류), ③ 9개 벤치마크로 "토큰을 평균 몇 개나 한 번에 통과시키는지(가속비)" 평가. 같은 틀 안에서 DSpark·DFlash·Eagle3 세 알고리즘을 갈아끼우며 비교한다.
트렌딩 이유, 경쟁 구현 대비 장점.
첫째, "DeepSeek"이라는 이름이다. 프론티어급 오픈 모델을 내놓는 연구소가 추론 가속 코드를 공개하면 자연히 시선이 쏠린다. 둘째, 추론 비용이 곧 돈인 시대에 품질 손실 없이 2~3배 가속은 모두가 원하는 것이다. 셋째, 이 레포는 드래프트 모델 분야의 최신 알고리즘 세 가지를 하나의 공정한 비교 틀에 모아놓았다는 점에서 연구자에게 특히 매력적이다.
특히 DSpark는 DeepSeek이 이 레포와 함께 공개한 자체 알고리즘(논문 PDF 동봉)으로, 기존 Eagle 계열이 토큰을 한 개씩 사슬처럼(autoregressive) 뽑던 방식을 깨고 블록을 한 번에 병렬로 제안한다. 거기에 "Markov head"와 "Confidence head"라는 두 개의 작은 보조 장치로 병렬화의 약점을 메운다(아래 4번에서 자세히).
| 알고리즘 | 드래프트 방식 | 특징 / 출처 |
|---|---|---|
| Eagle3 | 자기회귀(토큰 1개씩 사슬) | 가장 검증된 표준. 외부 SpecForge 코드를 차용·적응. 타깃의 여러 층 특징을 합쳐 씀 |
| DFlash | 경량 드래프트 레시피 | 외부 z-lab/dflash의 설계·학습법을 반영. 더 가벼운 구성 |
| DSpark | 블록 병렬(여러 토큰 동시) | DeepSeek 자체 신작. Markov+Confidence head로 병렬 드래프트의 의존성·조기중단 보완 |
드래프트가 틀려도 결과 품질은 떨어지지 않는다. 검증 단계의 거절 샘플링이 "타깃 모델 혼자 돌렸을 때와 정확히 같은 출력 분포"를 보장하기 때문이다. 빨라지지만 답이 달라지지 않는다 — 이게 추측 디코딩이 안전하게 쓰이는 이유다.
데이터 파이프라인·학습 루프·평가 벤치마크를 공유하므로, 세 알고리즘의 차이가 알고리즘 자체에서만 나온다. 논문 표(Table 1) 재현용 사전학습 체크포인트도 Hugging Face로 함께 공개해, "말로만 빠르다"가 아니라 숫자로 검증 가능하다.
이름만 보면 inference 라이브러리 같지만, 본질은 드래프트 모델을 처음부터 학습시키는 코드다. 기본 설정의 학습 데이터 캐시(타깃 은닉상태 저장)는 약 38TB의 디스크를 먹고, 기본 스크립트는 8×GPU 단일 노드를 가정한다. "내 노트북에서 바로 돌리는 가속기"가 아니다.
백엔드(학습/추론)·도구·데이터 파이프라인.
순수 Python + PyTorch 생태계다. 프론트엔드(웹 UI)는 없다 — 전부 학습/평가 스크립트와 모델 코드다. 핵심은 PyTorch의 분산학습(FSDP)·컴파일(torch.compile)·FlexAttention을 적극 활용한다는 점이다.
| 레이어 | 기술 / 버전 | 역할 |
|---|---|---|
| 딥러닝 코어 | PyTorch 2.9.1 | 모델·학습·분산·컴파일 전부의 토대. flex_attention으로 커스텀 어텐션 마스크 사용 |
| 모델 허브 | transformers 5.10.2 | 타깃 모델(Qwen3·Gemma) 로드, AutoConfig/DynamicCache(KV 캐시) 활용 |
| 분산 학습 | FSDP (PyTorch 내장) | 여러 GPU에 파라미터/그래디언트 분산. no_shard~hybrid_shard 전략 선택 가능 |
| 가속 커널 | triton 3.5.1 | 융합 손실 커널 등 저수준 GPU 커널(SpecForge에서 적응) |
| 정밀도 | bf16 + torch.compile | bfloat16 혼합정밀 + 그래프 컴파일로 학습 속도/메모리 최적화. 자체 BF16Optimizer |
| 저장 포맷 | safetensors 0.7.0 | 체크포인트 안전 직렬화 |
| 로깅/시각화 | tensorboard 2.20.0 · matplotlib | 학습 메트릭, 캘리브레이션 신뢰도 다이어그램(reliability diagram) 그림 출력 |
| 데이터 준비 | datasets 4.8.5 · openai 2.6.1 | open-perfectblend 데이터 로드 + OpenAI 호환 API로 타깃 답변 재생성 |
| 추론 서버(외부) | SGLang / vLLM (선택) | 데이터 준비 때 타깃 모델을 OpenAI 호환 /v1로 서빙. requirements 밖, 별도 설치 |
| 설정 시스템 | 순수 Python .py config | YAML 대신 파이썬 파일로 설정. --opts "key.path=value"로 개별 필드 오버라이드 |
먼저 전체 그림 → 그다음 흐름 한 줄기를 끝까지 추적.
DeepSpec은 "데이터 준비 → 학습 → 평가" 세 단계가 일렬로 이어진다. 각 단계의 출력이 다음 단계의 입력이 된다.
평가/추론에서 실제로 토큰이 어떻게 빨리 나오는지, 대표 흐름 하나를 손으로 따라가 보자. 핵심은 제안 → 검증 → 거절샘플링 → 커밋 네 박자다.
여기서 마법은 ②~④다. 타깃을 토큰마다 부르지 않고 블록 전체를 한 번에 검증한다(트랜스포머는 여러 토큰을 한 번에 처리하는 게 한 개씩 처리하는 것과 비용이 비슷하다 — 그게 GPU가 잘하는 일이다). 그리고 ④의 잔차 샘플링이 "손실 없음"을 보장한다.
"채택 확률 min(1, p_target/p_draft)로 받고, 거절되면 max(0, p_target − p_draft)를 정규화한 분포에서 다시 뽑는다"는 절차는, 최종적으로 토큰이 정확히 p_target에서 뽑힌 것과 동일함이 증명돼 있다(Leviathan 2023, Chen 2023). 그래서 드래프트가 아무리 엉터리여도 답의 품질은 타깃 단독과 같다 — 단지 적게 맞히면 덜 빨라질 뿐.
# deepspec/utils/sampling.py — 손실 없는 가속의 핵심 한 토막
# 채택 판정 (verify_draft_tokens 내부)
accept_prob = clamp(p_target(x) / p_draft(x), max=1.0) # x = 드래프트가 제안한 토큰
accepted = (rand() < accept_prob) # 동전 던지기
# 거절된 자리: 잔차분포에서 타깃이 직접 뽑음 → 분포 보존
residual = clamp(p_target - p_draft, min=0.0)
residual = residual / residual.sum() # 정규화
next_token = sample(residual)
Eagle3는 토큰을 한 개씩 사슬로 뽑는다(정확하지만 드래프트도 그만큼 여러 번 돈다). DSpark는 한 블록을 동시에 뽑아 드래프트 호출 수를 줄인다. 문제는, 동시에 뽑으면 "앞 토큰이 뭐가 나왔는지"를 못 보고 뽑으니 서로 어긋나기 쉽다는 점. DSpark는 작은 보조 장치 두 개로 이걸 보완한다.
block_size개의 빈 자리(mask 토큰)를 놓아 한 번에 채운다. 마치 빈칸 채우기 시험지를 동시에 푸는 것. 어텐션 마스크는 "내 블록 안 + 앵커 이전 문맥"만 보도록 FlexAttention으로 제한한다.어디에 무엇이 있나 (약 9천 줄 Python).
| 경로 | 역할 |
|---|---|
| train.py | 설정 로드 → torch.multiprocessing.spawn으로 GPU당 워커 1개 → trainer.train(). git 상태/diff도 찍어 재현성 확보 |
| eval.py | 드래프트 체크포인트의 아키텍처 이름을 읽어 알맞은 Evaluator 선택(Qwen3/Gemma4 × DSpark/Eagle3), 9개 태스크 실행 |
| modeling/dspark/loss.py | DSpark 손실 = CE + L1 + confidence BCE. 위치 감쇠 가중치·분산 all-reduce 처리 |
| modeling/dspark/markov_head.py | Vanilla / Gated / RNN 세 가지 Markov head 구현 + build_markov_head 팩토리 |
| modeling/dspark/common.py | 앵커 샘플링·블록 어텐션 마스크(FlexAttention)·noise 임베딩 등 블록 드래프트 핵심 유틸 |
| trainer/base_trainer.py | FSDP 셋업·학습 스케줄·그래디언트 누적·체크포인트·재개(resume) 공통 로직 |
| eval/base_evaluator.py | verify_draft_tokens(채택/거절)·생성 루프·가속비 집계 — 추측 디코딩의 심장 |
| eval/dspark/confidence_head.py | 신뢰도 예측의 캘리브레이션 측정(ECE·AUROC·Brier) + 신뢰도 다이어그램 PNG 출력 |
| utils/sampling.py | sample_residual 등 — 거절 샘플링의 잔차 분포 처리 |
| config/*/*.py | 알고리즘×타깃 조합별 하이퍼파라미터. --opts "key=value"로 즉석 오버라이드 |
이 레포로 무엇을 배울 수 있나 + 실습 아이디어.
교과서 설명만 읽으면 "왜 손실이 없지?"가 안 와닿는다. 이 레포의 verify_draft_tokens를 따라 읽으면 채택 확률·잔차 샘플링·EOS 처리·KV 캐시 되감기(crop)까지 한 함수에 다 들어 있어 한눈에 잡힌다.
드래프트는 "정답 토큰"만 따라하면 안 되고 "타깃의 확률분포"까지 닮아야 한다(그래야 채택률이 오른다). DSpark 손실이 그 균형을 보여준다.
# modeling/dspark/loss.py (개념 요약)
loss = α_ce · CE(draft_logits, target_id) # 어떤 토큰인지 (분류)
+ α_l1 · L1(softmax(draft), softmax(target)) # 분포가 닮았는지
+ α_cf · BCE(confidence, accept_rate) # 채택률 자기예측
# 블록 뒤쪽 자리일수록 가중치 ↓ (decay = exp(-k / γ))
l1_loss_alpha를 0으로 두고(=CE만) 학습해, 분포 매칭을 끄면 채택 길이 τ가 얼마나 떨어지는지 비교.장난감 예제가 아니라 실제로 도는 FSDP 셋업을 볼 수 있다. no_shard / shard_grad_op / full_shard / hybrid_shard 전략, 혼합정밀(bf16), 그래디언트 누적, 글로벌/로컬 배치 계산식이 base_trainer.py에 정리돼 있다.
global_batch_size = world_size × local_batch_size × grad_accum 관계를 코드에서 찾아, GPU 4장·local 2일 때 grad_accum이 몇이 되는지 손으로 맞춰보기."블록 안 토큰끼리 + 앵커 이전 문맥만 보기"라는 특이한 어텐션 규칙을 create_dspark_attention_mask가 mask_mod 함수 하나로 표현한다. 어텐션을 손으로 다뤄보고 싶은 사람에게 좋은 실전 예제.
mask_mod의 조건을 종이에 그려보고, block_size를 1로 줄이면 일반 인과(causal) 어텐션과 같아지는지 확인.Confidence head가 내놓는 채택 확률이 실제와 얼마나 일치하는지를 ECE·AUROC·Brier·신뢰도 다이어그램으로 잰다. 분류 모델의 신뢰도 평가 기법을 통째로 배울 수 있는 드문 실전 코드(eval/dspark/confidence_head.py).
순수 소프트웨어지만 "연구급" 자원을 전제한다.
| 항목 | 요구사항 / 권장 |
|---|---|
| GPU | 기본 설정은 단일 노드 8×GPU 가정(80GB급). 적으면 CUDA_VISIBLE_DEVICES로 줄이고 local_batch_size 조정 |
| 디스크 | 타깃 캐시 ≈ 38TB(Qwen3-4B 기본). 데이터 양·시퀀스 길이·캡처 층 수에 비례. 줄이려면 target_layer_ids를 줄이거나 데이터 축소 |
| Python/런타임 | PyTorch 2.9.1 + CUDA 빌드(자기 환경에 맞는 휠 설치). pip install -r requirements.txt |
| 데이터 준비용 | SGLang(또는 vLLM/TGI 등 OpenAI 호환 엔진) 별도 설치 — pip install "sglang[all]". requirements 밖 |
| 타깃 모델 | Qwen3-4B / 8B / 14B, google/gemma-4-12B-it 지원. 드래프트는 이 타깃에 맞춰 학습 |
| 출력 위치 | 체크포인트 ~/checkpoints/<project>/<exp>/step_*, 텐서보드 ~/tensorboard/... |
3단계 실행은 스크립트 한 줄씩이다(순서 중요):
# 1) 데이터 준비 (프롬프트→타깃답변 재생성→캐시) ※ 디스크 38TB 주의
bash scripts/data/prepare_data.sh
# 2) 드래프트 모델 학습 (config로 알고리즘·타깃 선택)
bash scripts/train/train.sh
# 내부: python train.py --config config/dspark/dspark_qwen3_4b.py \
# --opts "data.target_cache_path=..."
# 3) 평가 (9개 벤치마크에서 가속비 τ 측정)
bash scripts/eval/eval.sh
38TB 캐시 + 8GPU 학습이 부담되면, README의 Released Checkpoints(Hugging Face의 deepseek-ai/dspark_qwen3_4b_block7 등)를 draft_name_or_path에 넣어 평가만 돌려볼 수 있다. 단, 그래도 타깃 모델을 GPU에 올려야 하므로 추론용 GPU는 필요하다.
난이도순으로. 작은 것부터 손에 익히자.
드래프트가 5토큰을 제안하고 그중 3개가 통과, 4번째에서 거절되는 상황을 직접 그려보자. 채택 확률 min(1, p_target/p_draft)와 잔차 샘플링이 각 자리에서 어떻게 작동하는지 손으로 계산. 코드 한 줄 없이 개념을 잡는 단계.
config/dspark/dspark_qwen3_4b.py를 열어 block_size=7, num_draft_layers=5, markov_rank=256, 손실 가중치(ce/l1/confidence alpha)가 각각 무엇을 조절하는지 주석으로 정리. 이 레포의 "조절판"을 파악하는 단계.
transformers만으로 200줄 이내 추측 디코딩을 짠다. 드래프트=작은 모델, 타깃=큰 모델. sample_residual 로직을 그대로 옮기고, "그냥 타깃 단독"과 출력이 같은지 + 평균 채택 길이 τ를 출력. 손실 없음을 눈으로 확인하는 단계.
HF의 dspark_qwen3_4b_block7을 받아 eval.sh로 gsm8k·humaneval에서 τ를 측정하고, README/논문 Table 1 수치와 비교. (GPU 필요) 평가 파이프라인을 실제로 굴려보는 단계.
작은 데이터로 markov_head_type을 vanilla → gated → rnn으로 바꿔가며 학습하고, 셋의 채택 길이·학습 비용을 비교. "더 똑똑한 head가 항상 이득인가?"를 실험으로 답하는 단계(자원 소요 큼 — 축소 데이터 권장).
추측 디코딩을 제대로 파고드는 4주 코스.
| 주차 | 주제 | 학습 자료 / 행동 |
|---|---|---|
| 1주차 | 추측 디코딩 기초 | Leviathan(2023)·Chen(2023) 논문 읽기 → 손실 없음 증명 이해 → 미니 구현(실습 3) |
| 2주차 | 드래프트 모델 계열 | Medusa·Eagle·Eagle3 비교 → "다층 특징 융합"이 왜 채택률을 올리는지 → DeepSpec eagle3 코드 정독 |
| 3주차 | 병렬 드래프트 + DSpark | DSpark_paper.pdf 정독 → 블록 드래프트·Markov/Confidence head → modeling/dspark 코드와 대조 |
| 4주차 | 분산학습 · 캘리브레이션 | FSDP 공식 문서 → base_trainer 정독 → ECE/AUROC/Brier 개념 → confidence_head.py로 신뢰도 평가 |
레포에 등장하는 용어 빠른 참조.
| 용어 | 의미 |
|---|---|
| Speculative Decoding | 작은 드래프트가 여러 토큰을 미리 제안하고 큰 타깃이 한 번에 검증해 가속하는 기법. 출력 분포는 보존 |
| Draft / Target | 드래프트=빠른 보조 모델, 타깃=실제로 쓰는 큰 모델 |
| Acceptance Length (τ) | 타깃 1회 호출당 평균 확정 토큰 수. 클수록 가속이 큼. DeepSpec 평가의 주 지표 |
| Rejection Sampling | 채택 min(1,p_t/p_d) + 거절 시 잔차분포 재샘플 → 손실 없음 보장 |
| Block Drafting | 한 블록(여러 토큰)을 동시에 제안하는 DSpark 방식. 드래프트 호출 수 절감 |
| Markov head | 직전 토큰 의존성을 저랭크로 싸게 더해 병렬 드래프트의 어긋남을 보정 |
| Confidence head | 각 자리 채택 확률을 자기예측 → 조기중단. 캘리브레이션으로 신뢰도 검증 |
| Target Cache | 타깃의 은닉상태를 미리 계산해 디스크에 저장(≈38TB). 학습 때 타깃 재실행을 피함 |
| FSDP | 파라미터/그래디언트를 여러 GPU에 분산하는 학습 방식 |
| FlexAttention | 커스텀 어텐션 마스크를 함수로 정의하고 빠르게 도는 PyTorch 기능 |
| ECE / AUROC / Brier | 예측 확률이 실제와 얼마나 맞는지 재는 캘리브레이션 지표들 |
| open-perfectblend | 학습 프롬프트로 쓰는 공개 혼합 데이터셋(mlabonne) |
원문·논문·연관 프로젝트.