Dev.to AI 🤖 Ai 👁 0 📖 1 min read

수락 길이는 22.8% 늘었는데 처리량은 14.0%만 늘었습니다: DSpine 카드 수치와 공개 파일 헤더로 투기 디코딩 초안 모델을 읽는 법

TL;DR Tencent가 11월 7일 HF에 올린 Qwen3.8-27B-DSpine-b16은 Qwen3.8-27B의 속도를 높이기 위한 투기 디코딩 초안 모델입니다. 초안 모델이 한 번에 16토큰을 병렬로 제안하고, 큰 모델이 그것을 한꺼번에 검증하는 방식입니다. 카드에는 비교 대상인 DFlash2보다 수락 길이가 길다는 표와, 자기회귀 디코딩 대비 최대 3.84배라는 처리량 표가 있습

수락 길이는 22.8% 늘었는데 처리량은 14.0%만 늘었습니다: DSpine 카드 수치와 공개 파일 헤더로 투기 디코딩 초안 모델을 읽는 법

TL;DR

Tencent가 11월 7일 HF에 올린 Qwen3.8-27B-DSpine-b16은 Qwen3.8-27B의 속도를 높이기 위한 투기 디코딩 초안 모델입니다. 초안 모델이 한 번에 16토큰을 병렬로 제안하고, 큰 모델이 그것을 한꺼번에 검증하는 방식입니다. 카드에는 비교 대상인 DFlash2보다 수락 길이가 길다는 표와, 자기회귀 디코딩 대비 최대 3.84배라는 처리량 표가 있습니다.

저희는 이 체크포인트를 실행하지 않았습니다. 대신 카드의 에이전트 수치 10칸을 가져다 계산했고, 가중치 파일은 받지 않고 safetensors 헤더만 HTTP Range로 읽었습니다. 확인된 것은 네 가지입니다.

  • 수락 길이는 DFlash2 대비 평균 22.8% 늘었지만(최소 15.4%, 최대 32.8%), 처리량은 평균 14.0% 늘었습니다(최소 8.2%, 최대 21.2%). 열 칸 모두에서 처리량 증가율이 더 작았습니다.
  • 초안 모델은 BF16으로 20억 2,591만 개 파라미터(4.05GB)이고, 대상 모델 27.78B의 7.3%입니다. DFlash2(19억 2,440만 개)보다 5.3% 큽니다.
  • 일반 벤치마크에서 DSpine의 수락 길이 이득은 탐욕 디코딩(T=0) 평균 18.6%에서 샘플링(T=1) 평균 9.6%로 줄었습니다.
  • 이 수치는 전부 저자 보고이며 저희가 재현한 값이 아닙니다. 계산한 값은 "계산"이라고 표시했습니다. 비드래프트는 이 모델의 제작에 관여하지 않았습니다.

DSpine 대 DFlash2, 수락 길이 증가율과 처리량 증가율

수락 길이가 늘면 처리량도 그만큼 늘까요?

투기 디코딩은 작은 초안 모델이 토큰 여러 개를 먼저 써 보고, 큰 모델이 한 번의 순전파로 그 토큰들을 검증해서 맞는 만큼만 채택하는 방식입니다. 수락 길이는 한 번의 초안-검증 주기에서 채택된 토큰의 평균 개수입니다. 수락 길이가 5라면 큰 모델을 한 번 돌려 평균 5토큰을 얻는 셈입니다.

그래서 수락 길이가 속도의 지표처럼 쓰이지만, 속도 그 자체는 아닙니다. 주기 하나가 걸리는 시간이 같이 변하기 때문입니다. 초안 블록이 8토큰에서 16토큰으로 커지면 검증해야 할 토큰이 늘고, 초안 모델이 커지면 초안 단계가 길어집니다. 또 카드의 처리량은 "총 출력 토큰을 동시 재생 전체 시간으로 나눈 값"이라서, 가속되지 않는 시간(프리필, 스케줄링 등)도 분모에 들어갑니다. 수락 길이가 두 배가 되어도 처리량이 두 배가 되지 않는 이유입니다.

그러면 카드의 수치로 얼마나 벌어지는지 직접 계산해 보겠습니다.

DSpine 파일 안에는 무엇이 들어 있나요?

모델 카드는 구조를 한 줄로 설명합니다. 각 층이 예측한 이전 위치의 특징을 옆 위치로 넘겨서, 깊이 방향으로 인과 의존을 전달한다는 내용입니다. 파일 쪽에서는 config.json과 safetensors 헤더로 확인되는 것만 적겠습니다. 헤더는 파일 맨 앞 8바이트가 JSON 길이이므로, 가중치 본체를 받지 않고 몇 KB만 읽으면 됩니다.

import json, struct, urllib.request

def head(repo):
    url = f"https://huggingface.co/{repo}/resolve/main/model.safetensors"
    get = lambda a, b: urllib.request.urlopen(
        urllib.request.Request(url, headers={"Range": f"bytes={a}-{b}"})).read()
    size = struct.unpack("<Q", get(0, 7))[0]          # 앞 8바이트 = JSON 헤더 길이
    return json.loads(get(8, 7 + size))               # 가중치 본체는 받지 않는다

h = head("tencent/Qwen3.8-27B-DSpine-b16")
h.pop("__metadata__", None)
prod = lambda s: __import__("math").prod(s)
bf16 = sum(prod(v["shape"]) for v in h.values() if v["dtype"] == "BF16")
print(f"BF16 파라미터 {bf16:,}개, {bf16 * 2 / 1e9:.2f} GB")
print("embed/lm_head 텐서:", [k for k in h if "embed" in k or "lm_head" in k])

실행하면 다음과 같이 나옵니다.

BF16 파라미터 2,025,912,064개, 4.05 GB
embed/lm_head 텐서: []

헤더에서 읽은 구성은 이렇습니다. 합은 20억 2,591만 개이고, 정수형 버전 표시 스칼라 4개는 뺐습니다.

덩어리 파라미터 비중
MLP (5층) 13억 3,693만 66.0%
어텐션 q/k/v/o (5층) 2억 6,214만 12.9%
selected_prefix_bridge.codebook 2억 5,428만 12.6%
fc (5개 층 특징을 합치는 투영) 1억 3,107만 6.5%
나머지 (브리지의 다른 가중치, 정규화) 4,148만 2.0%

몇 가지를 읽을 수 있습니다. 먼저 초안 모델에는 임베딩과 출력층 텐서가 없습니다. 어휘 크기가 248,320이므로 따로 가지면 12억 7천만 개씩일 텐데, 파일에는 없습니다. 대상 모델의 것을 빌려 쓰는 구조로 보이지만, 이것은 헤더에서 추정한 것이고 코드를 읽어 확인한 것은 아닙니다. 다음으로 fc의 모양이 [5120, 25600]인데, 25,600은 5,120의 정확히 5배이고 config.json의 target_layer_ids가 다섯 층(1, 16, 31, 46, 61)입니다. 대상 모델의 다섯 층에서 뽑은 은닉 상태를 이어 붙여 5,120차원으로 줄이는 투영으로 읽는 것이 자연스럽습니다.

codebook은 모양이 [248320, 1024]입니다. 어휘 토큰마다 1,024차원 벡터를 가진 표로 보이고, 초안 파라미터의 12.6%를 차지합니다. 이름과 모양 말고는 확인한 것이 없으므로 역할은 논문(arXiv 2609.36173)과 저장소 코드를 보셔야 합니다.

대상 모델 쪽은 Qwen/Qwen3.8-27B의 config.json에서 읽었습니다. 64층 중 16층이 전체 어텐션이고 나머지 48층이 선형 어텐션이며, 은닉 크기 5,120과 MLP 중간 크기 17,408은 초안과 똑같습니다. HF 메타데이터의 총 파라미터는 277억 8,143만 개입니다. 이 저장소는 비전 설정이 함께 들어 있는 멀티모달 구조라서 텍스트 부분만의 값은 이보다 작습니다. 비교는 다음과 같습니다.

모델 파라미터 대상 대비
Qwen3.8-27B (대상) 277억 8,143만 100%
DSpine-b16 (초안) 20억 2,591만 7.3%
DFlash2 (초안, z-lab) 19억 2,440만 6.9%

DSpine은 DFlash2보다 약 1억 150만 개(5.3%) 큽니다. 초안 블록은 16토큰으로 DFlash2의 8토큰보다 길고, 카드는 동적 검증과 ReplaySSM을 켰다고 적었습니다. 크기와 블록 길이와 추론 설정이 동시에 다르므로, 어느 요소가 이득을 만들었는지는 카드의 표로는 가를 수 없습니다.

카드 수치 열 칸을 계산하면 무엇이 보이나요?

카드의 에이전트 표는 수락 길이와 처리량을 각각 DFlash2와 DSpine으로 줍니다. 처리량 표에는 자기회귀(AR) 대비 배수도 괄호로 적혀 있습니다. 여기서 한 가지를 더 계산했습니다. 속도 배수 S가 수락 길이 L을 주기 비용 c로 나눈 값이라고 보면 c = L / S입니다. c는 "초안-검증 한 주기가 자기회귀 1토큰 디코딩의 몇 배 시간이 걸리나"를 나타내는 눈금입니다. 이것은 저희가 카드 수치에서 유도한 값이지 측정값이 아닙니다.

L, S = 5.63, 805.53 / 210.03     # WorkBuddy Office (low): DSpine 수락 길이, 처리량/AR
print(round(L / S, 2))           # 1.47: 한 주기가 AR 1토큰의 약 1.47배 시간

열 칸 전체의 결과입니다. 수락 길이와 처리량은 카드 값이고, 증가율과 c는 계산입니다.

과제 (추론 강도) 수락 길이 DFlash2에서 DSpine 수락 길이 증가 처리량 증가 암시 주기 비용 c
WorkBuddy Code (low) 4.19에서 5.08 +21.2% +16.3% 1.80에서 1.88
WorkBuddy Code (xhigh) 4.06에서 4.92 +21.2% +11.5% 1.42에서 1.55
WorkBuddy Web (low) 3.95에서 4.91 +24.3% +20.9% 1.53에서 1.57
WorkBuddy Web (xhigh) 3.95에서 5.01 +26.8% +14.5% 1.36에서 1.50
WorkBuddy Office (low) 4.24에서 5.63 +32.8% +21.2% 1.34에서 1.47
WorkBuddy Office (xhigh) 4.20에서 5.49 +30.7% +15.3% 1.36에서 1.55
SWE-bench Pro (low) 4.19에서 4.99 +19.1% +8.5% 1.54에서 1.69
SWE-bench Pro (xhigh) 4.00에서 4.77 +19.2% +11.2% 1.39에서 1.50
τ²-bench (low) 4.70에서 5.53 +17.7% +8.2% 1.59에서 1.73
τ²-bench (xhigh) 4.29에서 4.95 +15.4% +12.2% 1.67에서 1.72

초안-검증 한 주기의 암시 비용

세 가지가 보입니다.

  1. 열 칸 모두에서 DSpine이 앞섭니다. 처리량 증가율이 가장 낮은 칸도 +8.2%입니다. 카드가 말하는 "DFlash2보다 빠르다"는 이 표 안에서는 일관됩니다.
  2. 그러나 수락 길이 이득이 처리량으로 전부 옮겨 가지는 않았습니다. 평균 22.8% 대 14.0%이고, 암시 주기 비용은 DSpine 쪽이 2.8%에서 13.3%(평균 7.8%) 높습니다. 블록 16토큰 검증, 5.3% 큰 초안 모델, 동적 검증 비용이 여기에 들어 있을 것으로 짐작하지만, 카드에는 이를 분리한 실험이 없습니다. 게다가 앞서 말한 가속되지 않는 시간이 분모에 들어가서, 비용이 전혀 늘지 않았더라도 처리량 증가율은 수락 길이 증가율보다 작아집니다. 두 효과를 이 표로는 나눌 수 없습니다.
  3. DFlash2의 c 자체가 과제마다 1.34에서 1.80으로 흩어집니다. 주기 비용이 모델과 하드웨어로만 정해진다면 이렇게 퍼지지 않을 것입니다. 과제별 프리필 비중과 도구 호출 재생 시간이 처리량에 섞여 있다는 뜻으로 읽힙니다. c는 판정이 아니라 눈금으로만 쓰시길 권합니다.

한 가지를 더 짚어 둡니다. 카드에 따르면 WorkBuddy 세 부분집합은 CodeBuddy 샌드박스에서 기록한 궤적의 도구 호출 앞부분을 순서대로 재생하며 얻은 값이고, 부분집합당 대화는 20개입니다. 실제 에이전트가 도구 결과를 받으며 진행하는 환경과는 다를 수 있고, 표본이 크지 않으므로 소수점 둘째 자리의 차이를 해석하는 것은 무리입니다.

온도를 올리면 이득이 얼마나 줄어드나요?

일반 벤치마크 표는 탐욕(T=0)과 샘플링(T=1, top_p 0.95, top_k 20)을 나란히 줍니다. DFlash2 대비 DSpine의 수락 길이 증가율을 계산하면 다섯 과제 모두에서 T=1이 작습니다.

과제 T=0 증가 T=1 증가
GSM8K +26.5% +15.8%
MATH-500 +18.2% +7.4%
HumanEval +17.2% +8.5%
MBPP +21.8% +12.9%
MT-Bench +9.0% +3.6%
평균 +18.6% +9.6%

온도에 따른 수락 길이 증가율

샘플링을 하면 큰 모델이 고르는 토큰이 초안과 어긋날 확률이 올라가므로 수락 길이가 줄어드는 것은 자연스럽습니다. 눈여겨볼 점은 줄어드는 폭이 DFlash2보다 DSpine 쪽에서 더 크다는 것입니다. 병렬로 16토큰을 제안하는 만큼 뒤쪽 위치의 예측이 샘플링 잡음에 더 민감한 것으로 보이는데, 이것은 숫자에서 읽은 추측이고 원인을 확인한 것은 아닙니다. 서비스가 낮은 온도로 도는지 높은 온도로 도는지에 따라 기대 이득이 크게 달라질 수 있다는 점은 분명합니다.

초안 모델이 메모리를 얼마나 더 먹나요?

가중치는 앞서 계산한 대로 BF16 4.05GB입니다. KV 캐시는 config.json에서 계산할 수 있습니다. 초안은 5층, KV 헤드 8개, 헤드 차원 128이고 슬라이딩 윈도우가 8,192입니다. 대상 모델은 전체 어텐션 16층, KV 헤드 4개, 헤드 차원 256입니다. 선형 어텐션 48층은 길이에 상관없이 일정한 크기의 상태를 가지므로 이 계산에서 뺐습니다.

항목 토큰당 KV (BF16) 컨텍스트 131,072일 때
대상 모델 (전체 어텐션 16층) 65,536B 8.0 GiB
DSpine 초안 (5층) 20,480B 창 8,192로 상한 160 MiB

초안의 토큰당 KV는 대상의 31%이지만, 윈도우가 있어서 컨텍스트가 길어져도 요청당 160 MiB에서 멈춥니다. 카드의 서버 설정(--max-running-requests 8)대로 8개가 동시에 돌면 초안 KV는 최대 1.25 GiB입니다. 이것은 BF16 KV를 가정한 이론값입니다. 실제 SGLang이 확보하는 양은 페이지 단위 할당과 mamba 캐시 설정(--max-mamba-cache-size 64) 때문에 다를 수 있으므로, 올리기 전에 직접 재야 합니다.

내 서버에 올리기 전에 무엇을 재야 하나요?

카드의 서버 명령에는 --enable-linear-replayssm-spec이 들어 있습니다. 일반론으로 설명하면, 선형 어텐션 층의 상태는 토큰마다 덮어써지므로 초안이 틀렸을 때 KV처럼 뒤쪽만 잘라 버릴 수가 없고, 되감는 장치가 필요합니다. 이 옵션이 그 역할이라고 짐작하지만 구현은 확인하지 못했습니다. 중요한 것은 이 모델을 쓰려면 일반 SGLang이 아니라 DSpine 저장소를 설치하고 --speculative-algorithm DSPINE을 써야 한다는 점입니다.

도입 전에 점검할 것을 정리하면 이렇습니다.

  1. 동시 요청 수를 맞춰 AR 대비로 재십시오. 카드의 모든 수치는 동시성 8입니다. 일반적으로 동시 요청이 많아져 GPU가 연산 병목에 가까워지면 투기 디코딩의 이득은 줄어드는 경향이 있습니다. 카드의 3배가 내 서버의 3배라는 보장은 없습니다.
  2. 내 요청 분포로 수락 길이를 기록하십시오. 온도, 도구 호출 비중, 출력 길이에 따라 수락 길이가 달라집니다. 이 글의 표는 카드가 고른 과제에서의 값입니다.
  3. 메모리를 따로 잡으십시오. 초안 가중치 4.05GB에 요청당 KV 160 MiB 이하를 더하고, 선형 어텐션 상태 여유를 따로 확인하십시오.
  4. 출력이 달라지지 않는지 확인하십시오. 투기 디코딩은 설계상 검증을 통과한 토큰만 채택하므로 탐욕 디코딩 결과가 AR과 같아야 합니다. 다만 수치 비결정성으로 일부가 갈릴 수 있으니 고정 입력 몇십 개로 비교해 보십시오.

자주 묻는 질문

수락 길이가 길면 항상 더 빠른가요?
아닙니다. 속도는 수락 길이를 주기 비용으로 나눈 값에 가깝고, 가속되지 않는 시간도 섞입니다. 이 글의 계산에서도 수락 길이는 평균 22.8% 늘었지만 처리량은 14.0%만 늘었습니다.

카드의 최대 3.84배는 어디서 나온 숫자인가요?
WorkBuddy Office(low)에서 자기회귀 210.03 tokens/s 대비 DSpine 805.53 tokens/s로 계산한 값입니다. 동시성 8, BF16, FlashAttention 3, SGLang 0.5.22 조건이고 저자 보고입니다. 같은 표에서 SWE-bench Pro(low)는 2.95배이므로 과제에 따라 폭이 큽니다.

DSpine이 DFlash2보다 낫다고 결론 내려도 되나요?
카드 안의 열 칸에서는 일관되게 앞섭니다. 다만 평가자가 모델을 만든 쪽이고, DSpine은 블록 16과 동적 검증을 쓰고 DFlash2는 블록 8이라 조건이 완전히 같지 않습니다. 독립 재현이 나오기 전에는 "저자 보고 기준으로 앞선다"까지가 적당합니다.

라이선스는 어떤가요?
카드 헤더에 Apache-2.0이라고 적혀 있고 저장소에 LICENSE 파일이 있습니다. 상용 사용 전에는 파일 내용과 대상 모델 Qwen3.8-27B의 라이선스를 각각 확인하십시오.

저희가 직접 돌려 보았나요?
아닙니다. 이 글은 공개 카드, config.json, safetensors 헤더, 대상 모델 설정과 HF 메타데이터를 읽고 계산한 결과입니다. 추론을 돌리지 않았고 처리량과 품질은 측정하지 않았습니다. 출처는 arXiv 2609.36173, DSpine 저장소, 모델 카드입니다.

Further reading

📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.