Skip to content

추측 복호화와 멀티 GPU를 상징하는 이미지

radiance 문서에서 성능 이야기가 가장 빽빽하게 몰린 두 절이 추측 복호화(§4.6)와 멀티 카드(§4.7)다. 모든 메커니즘의 공통 원칙은 출력 분포를 바꾸지 않는다는 것이다. 손실이 있는 곳은 초안 채택이나 와이어 압축처럼 명시적으로 선언한 곳뿐이다.

drafter는 컨테이너에서 온다 ​

컨테이너에 초안 헤더가 들어 있으면 기본으로 켜지고, 깊이는 플러그인이 선언한 작동점을 쓴다.

sh
radiance --model m.rad                              # auto: drafter의 작동점
radiance --model m.rad --num-speculative-tokens 0   # 끄기
radiance --model m.rad --num-speculative-tokens 3   # 깊이 지정

drafter는 컨테이너에서 온다 — 변환 시 rad-convert --draft-model DIR로 병합하거나, 타깃 체크포인트 안에 MTP 헤더가 있으면 그걸 쓴다. 실행 시 radiance --draft-model은 "그건 없다"는 오류로 거부된다. DSpark, DFlash, DFlash2, LiLiCorr 같은 외부 drafter가 있고, 모델 표에 어떤 컨테이너에 어떤 drafter이 들었는지 적혀 있다. 초안 복호화는 tokens/s가 아니라 스텝 시간으로 재라는 것이 문서의 조언이다. DFlash2처럼 자기 캐시에 슬라이딩 창이 있는 drafter는 프리픽스 캐시와 다른 방식으로 상호작용한다(창 스냅샷, draft floor 시작 라인) — 접중률이 이상할 때 시작 로그를 먼저 본다.

모델 없는 초안: prompt lookup ​

drafter가 아예 없을 때도 엔진은 초안을 만든다 — 모델 없이, 프롬프트와 출력을 훑어 이 시퀀스의 마지막 n토큰이 가장 최근에 나타난 위치를 찾아 그 뒤를 제안한다(--spec-ngram-max/min, 기본 4~2). 초안 패스가 없고 재발이 없으면 제안도 없다. 답이 문맥을 복사할 때 — 코드 편집, 리라이트, diff, JSON, 인용 — 특히 이득이 크다.

제안은 공짜가 아니다(MoE에서 row마다 expert를 읽는다). 그래서 룩업이 유일한 drafter일 때, 제안이 기대 이득보다 비싸면 검증을 미룬다: 실측한 row-수 대비 스텝 시간과 시퀀스 자신의 채택 기록으로 기각/채택을 예측한다. 산문의 제안은 조용히 묻히고 복사 구간의 제안은 검증된다. --spec-ngram 5로 창을 준다. 이 제안은 결정적 제안용 초안 샘플링 규칙을 쓰므로 어떤 온도에서도 분포 정확하고 greedy 텍스트는 초안 없이와 같다.

적응형 창과 draft tree ​

코드와 JSON은 창 깊이까지 채택되고 산문은 두세 위치에서 꺾인다. --draft-window adaptive는 --num-speculative-tokens를 상한으로, 시퀀스마다 초안 위치별 채택률을평탄하게 집계해 스텝마다 깊이를 고른다(초당 기대 토큰 ÷ 실측 스텝 시간이 최대가 되는 깊이).

DFlash2처럼 블록 drafter가 제안하는 모델에서는(gemma4 31B 등 실측 이득이 확인된 곳) 제안을 트리로 검증한다. 트리는 토큰을 하나도 바꾸지 않고 한 스텝에 착지하는 초안 개수만 늘린다. --num-speculative-tokens는 트리의 노드 수를 센다. 문법 제약(response_format, tools)이 있어도 각 row는 자기 조상에 대해 마스킹되며 트리로 초안된다.

부하가 쌓이면 짧은 블록으로 ​

블록 drafter의 블록은 초안 두는 시퀀스 모두가 대가를 치른다. 한 시퀀스일 때 길수록 이득이지만, 여러 개일 때는 추가 row와 약한 앞자리가 초과분보다 비싸진다. --draft-short-from N은 디코딩 중인 시퀀스가 N개에 닿으면 drafter가 선언한 짧은 블록(DFlash2는 4)으로 전환하고, N-2 아래로 내려가면 원래 블록으로 돌아온다. auto는 트리 drafter를 2부터 전환한다. GUIDE의 Qwen3.8-27B MXFP4 실측 — 8스트림 652.8→696.8, 16스트림 751.9→945.6, 64스트림 1055→1334.6 tok/s. 여덟 개 이상을 동시 디코딩하는 서버라면 8을 주라고 문서는 권한다.

멀티 카드: --tp 기본 ​

sh
radiance --model m.rad --tp 2

tensor parallel은 각 카드가 모든 expert 너비의 slice를 소유하는 방식으로 나뉜다. 세·네 랭크는 용량 구성에 가깝고(같은 카드에서 tp 2 대비 스텝율은 미측정), 여덟 랭크는 GLM-5.3-Flash용으로 별도 문서(TP3.md, TP4.md)가 있다. 3·4 랭크에서는 gated residual 안에 all-reduce가 fused되어 정확히 같은 바이트를 낸다. --tp-attn-split rows는 어텐션이 프리필을 지배하는 모델(GLM-5.3: 8랭크에서 프리필 +18~21%)의 선택지다.

tp-wire: 손실 와이어의 허용 ​

--tp-wire은 all-reduce 페이로드를 고른다.

  • exact (기본) — bf16 정확 합. small message는 one-shot, 큰 것은 two-shot(같은 비트, 덜 전송).
  • wht6 — Walsh-Hadamard 회전 6비트 페이로드. PCIe 위에서 2.4배 작지만 받는 쪽의 합이 더 이상 정확한 합이 아니고하류에서 하류에서 감지도 못 한다. 그래서 명시적 플래그다. --tp-wire-min-kb 128로 임계값 아래 메시지는 정확히 두고 프리필만 압축할 수 있다(단일 시퀀스 디코딩은 정확 유지). Flash-Next 프리필 +5.6~6.3% 실측. 세·네 랭크에서는 two-shot 위의 tiered int8로 동작하고, 여덟 랭크에는 손실 와이어가 없어 --tp 8 --tp-wire wht6는 시작 시 거부된다.

P2P가 없는 카드 구성 ​

all-reduce 커널은 보통 카드 간 직접 쓰기(P2P)를 한다. radiance는 시작 시 드라이버에 카드 짝마다 가능 여부를 물어 답을 로그에 남긴다. IOMMU 설정·PCIe 토폴로지·중간 스위치가 결과를 정한다. P2P가 없는 짝에서는 같은 커널의 _host 변형이 exchange 버퍼를 고정 호스트 메모리에 두고 각 카드가 자기 share를 호스트 RAM에 쓴 뒤 남의 것을 읽는다. 결과는 같은 바이트, 링크를 두 번 건넌다. R9700 둘(PCIe 4.0)에서는 디코딩 1·4스트림에서 run 간 잡음 수준, 23.6K 프리필에서 2~10%였다.

--p2p off는 가능해도 호스트 경로로, on은 요구(없으면 시작 거부), auto(기본)는 드라이버를 따른다. 여덟 카드처럼 링크 속도가 불균등한 보드에서는 two-shot이 링크별 가중치로 shard를 나누고 메시지를 쪼개 duplex를 채운다(sysfs에서 각 카드 PCIe 경로의 가장 느린 hop을 읽어 가중치 계산 — 로그 한 줄에 다 적힌다). 카드가 도중에 링크를 내려도 가중치는 다음 시작 전까지 그대로다.

오픈소스를 한국어로 읽고 배웁니다.