TurboQuant llama.cpp CUDA 포크, A100에서 실측 — turbo4는 q4_0급, turbo3는 긴 컨텍스트에서 무너진다
Qwen3-8B Q4_K_M, A100 한 장, KV 타입 6종: perplexity·프리필·깊이별 디코드·VRAM 실측. turbo4는 q4_0과 품질 동급에 깊은 컨텍스트에선 q8_0보다 2.5배 빠르고, turbo3는 32K에서 PPL이 세 배로 뜁니다.

TurboQuant llama.cpp CUDA 포크, A100에서 실측 -- turbo4는 q4_0급, turbo3는 긴 컨텍스트에서 무너진다
llama.cpp용 TurboQuant 수치로 돌아다니는 것들은 Apple Silicon(Metal)과 소비자용 RTX에서 나왔습니다. 저희 질문은 달랐습니다. 데이터센터 GPU에서, 사람들이 실제로 서빙하는 모델로, 사람들이 건너뛰는 측정 -- *긴 컨텍스트에서의* perplexity, *캐시가 가득 찬 상태의* 디코드 속도, VRAM -- 을 하면 CUDA 포크는 어떻게 되는가.
설정: Qwen3-8B Q4_K_M, A100 80GB 한 장, spiritbuun CUDA 포크를 -DGGML_CUDA=ON sm80으로 빌드, flash attention 켬, KV 캐시 타입 6종(f16, q8_0, q4_0, turbo4, turbo3, turbo2) + 커뮤니티가 권하는 비대칭 K/V 조합 둘. 아래 숫자는 전부 이 머신에서 나왔고 JSON 로그를 첨부합니다.
결과 넷:
turbo4는 진짜 q4_0 대체재입니다 -- perplexity 동일(f16 대비 +0.65%), 27% 더 작고, 이 커널에서 64K 컨텍스트 디코드가q8_0/q4_0보다 2.5배 빠릅니다.turbo3는 4K에서는 괜찮고 16K면 망가집니다. perplexity가 4K +5.5% → 8K +24% → 16K +210%로 뜁니다. 컨텍스트 길이를 확인하지 않고 배포하지 마세요.- 이 포크의 양자화 KV 어텐션 경로는 A100에서
q8_0/q4_0에 느립니다 -- 64K 깊이에서 f16 속도의 29%로 디코드합니다. TurboQuant 커널이 더 낫고, f16이 가장 빠릅니다. - 비대칭 조합
K q8_0 / V turbo3는 거의 무손실(+0.18%)이지만 q8_0의 느린 디코드를 물려받습니다.
이 글은 TurboQuant 시리즈 Part 5입니다. 왜 이게 본류가 아니라 포크인지는 Part 3, 알고리즘을 직접 구현해 *왜* 이런 숫자가 나오는지 설명한 글은 Part 6입니다.
1. 무엇을 쟀나, 왜 이 넷인가
TurboQuant 벤치마크 대부분은 llama-bench 프리필 처리량과 -c 512나 -c 4096의 perplexity를 보고합니다. KV 압축이 공짜로 보이게 만드는 숫자들입니다. KV 압축이 바꾸는 바로 그것 -- 디코드 스텝마다 큰 양자화 캐시를 읽는 일 -- 을 건드리지 않기 때문입니다.
그래서 이렇게 쟀습니다.
- perplexity: wikitext-2, 컨텍스트 4,096(40청크), 그리고 8K / 16K / 32K에서 다시 -- 각 토큰이 어텐션하는 양자화 컨텍스트 양에 따라 품질이 어떻게 변하는지.
- 프리필 처리량: 8K·32K 프롬프트(
llama-bench -p). - 깊이별 디코드 처리량: 캐시에 8K·32K·64K 토큰이 이미 든 상태에서의 생성 tok/s(
llama-bench -d). KV 대역폭을 반영하는 유일한 속도 지표입니다. - 최대 VRAM: 32K 컨텍스트, 단일 청크 perplexity 실행 중
nvidia-smi로 샘플링.
모델: Qwen3-8B(36 레이어, KV 헤드 8, 헤드 차원 128 → 토큰당 f16 KV 144 KiB). 가중치 Q4_K_M(4.68 GiB).
2. 4K perplexity: turbo4 = q4_0, turbo3는 5% 비용
| KV 타입 | 값당 비트(근사) | PPL @4K | f16 대비 |
|---|---|---|---|
| f16 | 16 | 8.319 ± 0.084 | -- |
| q8_0 | 8.5 | 8.318 | +0.00% |
| q4_0 | 4.5 | 8.374 | +0.66% |
| turbo4 | 4.25 | 8.373 | +0.65% |
| turbo3 | 3.25 | 8.776 | +5.5% |
| turbo2 | 2.25 | 15.23 | +83% |
| K q8_0 / V turbo3 | 5.9 | 8.333 | +0.18% |
| K turbo4 / V turbo3 | 3.75 | 8.407 | +1.06% |
4K 컨텍스트에서는 이야기가 깔끔합니다. turbo4는 더 적은 비트로 q4_0에 정확히 얹힙니다(8.373 vs 8.374). turbo3는 5.5% -- Qwen3.5-35B Metal에서 보고된 "+1%"보다 눈에 띄게 크고, 작은 모델이 더 민감하다는 패턴과 일치합니다. turbo2는 쓸 수 없습니다. 그리고 키를 q8_0에 두고 값만 turbo3로 내리면 f16과 노이즈 범위 안입니다 -- 커뮤니티가 발견한 K/V 비대칭은 실재하고 큽니다.
3. 컨텍스트 길이별 perplexity: turbo3가 무너진다
저희 권고를 바꾼 측정입니다. 같은 모델, 같은 파일, 각 토큰이 더 많은 양자화 캐시에 어텐션하도록 컨텍스트 창을 넓힌 perplexity:
| KV 타입 | ctx 8K | ctx 16K | ctx 32K |
|---|---|---|---|
f16 | 7.90 | 7.60 | 9.09 |
turbo4 | 8.04 (+1.8%) | 7.71 (+1.5%) | 9.18 (+1.0%) |
turbo3 | 9.76 (+23.6%) | 23.56 (+210%) | 26.67 (+193%) |
K q8_0 / V turbo3 | 7.91 (+0.1%) | 7.62 (+0.4%) | 9.10 (+0.1%) |
K turbo4 / V turbo3 | 8.12 (+2.8%) | 7.73 (+1.8%) | 9.20 (+1.2%) |
각 셀은 wikitext-2 3청크 평균 perplexity(f16 대비 변화율)입니다. 컨텍스트가 길수록 청크 수가 적어 절대값의 신뢰구간이 넓지만, 타입 간 비교는 같은 텍스트 위에서 이뤄집니다.
turbo4는 완만하게 나빠집니다. turbo3는 아닙니다. 32K에서 perplexity가 f16의 대략 세 배입니다. turbo3가 키마다 넣는 오차가 무엇이든, 쿼리가 순위를 매겨야 하는 키 수에 비례해 누적되고, 3.25비트에서는 softmax가 올바른 키를 더는 찾지 못합니다. 커뮤니티의 "context-scaling regression" 보고는 Metal에서의 장문 *속도* 문제였습니다. 이것은 CUDA에서의 *품질* 퇴행이고, 훨씬 심합니다.
비대칭 K q8_0 / V turbo3 조합은 컨텍스트 길이에 걸쳐 평평합니다 -- 피해가 키 쪽에 있다는 또 하나의 신호입니다. 3비트 값을 원하면 키는 8비트로 두세요.
실무 규칙: 이 포크에서 turbo3는 4K 이하 컨텍스트용 설정입니다 -- 8K에서 이미 +24%입니다. 그보다 길면 turbo4나 비대칭 조합.
4. 속도: 프리필은 싸고, 깊이별 디코드에서 타입이 갈린다
프리필(tok/s, 높을수록 좋음):
| KV 타입 | pp 8K | pp 32K | tg 128 (빈 컨텍스트) |
|---|---|---|---|
| f16 | 4,511 | 3,342 | 152.5 |
| q8_0 | 4,385 | 3,205 | 135.9 |
| q4_0 | 4,379 | 3,194 | 135.3 |
| turbo4 | 4,071 (−10%) | 2,788 (−17%) | 130.2 |
| turbo3 | 3,969 (−12%) | 2,953 (−12%) | 92.4 (−39%) |
| turbo2 | 4,061 | 3,011 | 116.1 |
A100에서 turbo 타입의 프리필 비용은 10~17%입니다. 저장 경로의 Walsh-Hadamard 회전과 코드북 조회가 이 커널에서는 공짜가 아닙니다 -- "q8_0보다 2% 빠르다"는 Metal 결과와 다릅니다. turbo3는 빈 컨텍스트 디코드부터 f16보다 39% 느린데, 토큰당 역양자화 비용을 암시합니다.
이제 중요한 숫자 -- 캐시가 가득 찬 디코드:
| KV 타입 | 디코드 @8K | @32K | @64K | @64K f16 대비 |
|---|---|---|---|---|
| f16 | 134.7 | 103.9 | 79.6 | 100% |
| turbo4 | 111.1 | 79.5 | 57.8 | 73% |
| turbo3 | 80.4 | 58.4 | 42.6 | 54% |
| q8_0 | 83.9 | 39.5 | 22.8 | 29% |
| q4_0 | 82.3 | 38.0 | 21.7 | 27% |
| K q8_0 / V turbo3 | 72.9 | 37.5 | 22.9 | 29% |
놀라운 점 둘. 첫째, 이 포크의 CUDA 빌드에서 q8_0과 q4_0는 깊은 컨텍스트에서 디코드가 형편없습니다 -- 64K에서 f16의 30% 미만입니다. 양자화 KV의 flash-attention 경로가 텐서코어를 쓰지 않는 "vec" 커널이라 장문에서 그 비용이 지배합니다. 둘째, TurboQuant 커널이 양자화 옵션 중 가장 빠릅니다: 64K에서 turbo4는 q8_0보다 2.5배, q4_0보다 2.7배 빠릅니다. 포크의 어텐션 내 fused 역양자화 경로는 분명히 깊이를 염두에 두고 짜였습니다.
그래도 f16이 가장 빠릅니다. 80GB 카드에 8B 모델이면 128K를 한참 넘기 전까지는 메모리 때문에 캐시를 압축할 *필요*가 없고, 그 전까지는 f16이 품질도 속도도 최고입니다. 큰 GPU에서 KV 압축은 속도가 아니라 용량의 결정입니다.
5. 32K 컨텍스트의 VRAM
| KV 타입 | 최대 VRAM @32K | f16 대비 | 추정 KV 캐시 |
|---|---|---|---|
| f16 | 9.86 GB | -- | ~4.8 GB |
| q8_0 | 7.70 GB | −2.2 GB | ~2.6 GB |
| q4_0 | 6.55 GB | −3.3 GB | ~1.4 GB |
| turbo4 | 6.57 GB | −3.3 GB | ~1.3 GB |
| turbo3 | 6.40 GB | −3.5 GB | ~1.0 GB |
| turbo2 | 6.11 GB | −3.7 GB | ~0.7 GB |
| K q8_0 / V turbo3 | 7.12 GB | −2.7 GB | ~1.8 GB |
최대 VRAM에는 Q4_K_M 가중치 4.7GB와 컴퓨트 버퍼 ~0.4GB가 포함되고, 차이는 KV 캐시입니다. 32K 토큰의 f16 KV는 해석적으로 4.83GB(36 레이어 × 8 헤드 × 128 × 2 × 2바이트 × 32,768)이고, 측정된 차이는 명목 bpv를 잘 따라갑니다. turbo4와 q4_0는 크기가 같습니다. 둘 사이의 선택은 속도와 품질인데, 둘 다 turbo4 편입니다.
이게 중요해지는 곳: 70B Q4_K_M 모델은 80GB A100에 ~34GB를 남기고, 70B(80 레이어, KV 헤드 8)의 128K f16 KV는 ~40GB입니다. turbo4가 "안 들어감"을 "배치 여유 있게 들어감"으로 바꾸는 경우입니다.
6. 권고 (A100, 이 포크)
| 상황 | 선택 | 이유 |
|---|---|---|
| 캐시가 VRAM에 들어감 | f16 | 가장 빠르고 무손실. 얻을 게 없음 |
| ~3.5배 작은 캐시, 컨텍스트 무관 | `turbo4` | q4_0 품질, 깊은 컨텍스트에서 q8_0/q4_0보다 2.5배 빠른 디코드 |
| 거의 무손실 + 약간의 절약 | -ctk q8_0 -ctv turbo3 | +0.18% PPL, 컨텍스트에 걸쳐 평평 -- 단 q8_0의 느린 깊이 디코드 |
| 짧은 컨텍스트(≤4K), 최대 압축 | turbo3 | 4K에서 +5.5% PPL, 4.9배 압축 |
| 8K 이상 컨텍스트 | `turbo3` 금지 | 8K에서 +24%, 16K에서 세 배 |
| 어떤 경우든 | turbo2 금지 | 4K에서 +83%, 32K에서 약 60배 |
그리고 메타 권고 하나: 실제로 서빙하는 컨텍스트 길이에서 llama-perplexity를 반드시 돌리세요. 4K perplexity는 turbo3가 괜찮다고 했습니다. 아닙니다.
7. 재지 않은 것
- 태스크 정확도(needle-in-a-haystack, GSM8K) -- Part 4가 vLLM에서 합니다.
- 배치 > 1.
llama-bench디코드는 단일 스트림이라 배치 서빙에서는 대역폭 그림이 바뀝니다. - 다른 GPU.
q8_0/q4_0의 깊이 페널티는 sm80에서 이 포크의 CUDA flash-attention 경로에 특유한 것이고, 본류 llama.cpp나 Hopper는 다를 수 있습니다. - 다른 모델. 전부 Qwen3-8B입니다. Llama-3.1-8B나 70B에서는 turbo3의 임계가 움직일 수 있습니다.
재현: 포크 빌드(cmake -B build -DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=80) 후 첨부 번들의 bench-llamacpp-tq.sh, bench-llamacpp-depth.sh, ctxscale.sh, kvmem-probe.sh. A100 한 장 기준 총 약 2.5시간.
참고 자료
- spiritbuun/llama-cpp-turboquant-cuda -- 여기서 벤치마크한 포크
- llama.cpp Discussion #20969 -- Metal/RTX 커뮤니티 결과
- Part 3: TurboQuant 현황 점검 · Part 6: TurboQuant 밑바닥부터
- Zandieh et al., TurboQuant, ICLR 2026
이메일로 받아보기
관련 포스트

하이브리드 Mamba-Transformer 실측 — Qwen3.5-9B의 캐시는 Qwen3-8B의 4.4분의 1, 그리고 저희 속도 수치를 믿으면 안 되는 이유
A100 한 장에서 Qwen3.5-9B(24 linear + 8 attention)와 Qwen3-8B의 캐시를 2K~64K 컨텍스트로 실측. 64K에서 4.4배 작고 4.6배로 수렴 — 산수로 정확히 분해됩니다. HF eager 속도 수치가 왜 아키텍처를 말해주지 않는지도 설명합니다.

TurboQuant를 실제 KV 텐서 위에서 밑바닥부터 — 3비트의 진짜 비용, 그리고 포크가 논문 레이아웃을 이기는 이유
PolarQuant를 PyTorch 60줄로 구현해 Llama-3.2-1B·Qwen3-8B의 실제 KV에 적용. 3비트는 +10%, k8v4는 +0.2%, QJL은 저비트에서만 유효, 블록-32 레이아웃이 포크 우위의 절반을 설명합니다.

TurboQuant 현황 점검, 2026년 8월 — vLLM·llama.cpp·Ollama에 실제로 들어간 것
vLLM은 v0.20에 탑재하고 냉정한 벤치마크를 냈고, llama.cpp 본류는 6월에 거부했고, Ollama 구현은 죽었습니다. 저희 이전 글의 "llama.cpp 머지" 주장도 정정합니다 — 링크와 함께.