TurboQuant 실전 — llama.cpp와 HuggingFace에서 KV Cache 압축하기
llama.cpp turbo3 빌드, HuggingFace 통합, 메모리 계산기, 최적 설정 가이드. 70B 모델 536K 컨텍스트 실현.

TurboQuant 실전 — llama.cpp와 HuggingFace에서 KV Cache 압축하기
TurboQuant는 KV Cache를 3~4비트로 압축하여 추론 시 메모리 사용량을 극적으로 줄이는 양자화 기법입니다. 이론은 알겠는데, 실제로 어떻게 쓰는 걸까요? 이 글에서는 llama.cpp와 HuggingFace 두 환경에서 TurboQuant를 직접 설정하고 사용하는 방법을 단계별로 다룹니다.
1. 준비
필요한 것들
- llama.cpp TurboQuant fork (또는 공식 지원 빌드)
- Python 3.10+ 및 HuggingFace
transformers라이브러리 - GPU: 8GB+ VRAM이면 충분 (NVIDIA CUDA 또는 Apple Metal)
- CPU에서도 동작하지만, 성능은 GPU 대비 느림
Python 환경 설정
pip install transformers torch accelerate
pip install turboquant # TurboQuant Python 패키지GGUF 모델 준비
llama.cpp에서 사용하려면 GGUF 포맷의 모델이 필요합니다. HuggingFace Hub에서 직접 다운로드하거나, 기존 모델을 변환할 수 있습니다.
# HuggingFace에서 GGUF 모델 다운로드 예시
huggingface-cli download TheBloke/Llama-3-70B-GGUF \
llama-3-70b.Q4_K_M.gguf --local-dir ./models2. llama.cpp에서 TurboQuant 사용하기
빌드
TurboQuant를 지원하는 llama.cpp fork를 클론하고 빌드합니다.
git clone https://github.com/TheTom/llama-cpp-turboquant.git
cd llama-cpp-turboquant
git checkout feature/turboquant-kv-cache
cmake -B build -DGGML_METAL=ON # macOS (Apple Silicon)
# 또는
# cmake -B build -DGGML_CUDA=ON # NVIDIA GPU
cmake --build build --config Release -j빌드가 완료되면 build/bin/ 디렉토리에 실행 파일들이 생성됩니다.
서버 실행
turbo3 KV cache 양자화를 적용하여 서버를 실행합니다.
./build/bin/llama-server -m model.gguf \
--cache-type-k turbo3 --cache-type-v turbo3 \
-c 262144 -fa on --port 8080각 옵션의 의미는 다음과 같습니다.
| 옵션 | 설명 |
|---|---|
--cache-type-k turbo3 | Key 캐시에 TurboQuant 3비트 적용 |
--cache-type-v turbo3 | Value 캐시에 TurboQuant 3비트 적용 |
-c 262144 | 컨텍스트 길이 262K 토큰 |
-fa on | Flash Attention 활성화 (필수) |
--port 8080 | API 서버 포트 |
서버가 실행되면 OpenAI 호환 API로 접근할 수 있습니다.
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "llama-3-70b",
"messages": [{"role": "user", "content": "Hello!"}],
"max_tokens": 256
}'벤치마크 비교
FP16, Q8, TurboQuant 3비트를 비교하여 성능 차이를 확인합니다.
./build/bin/llama-bench -m model.gguf \
-fa 1 -ngl 99 \
-ctk f16 -ctv f16 \
-ctk q8_0 -ctv q8_0 \
-ctk turbo3 -ctv turbo3일반적인 결과 예시 (Llama 3 8B, RTX 4090 기준):
| KV Cache 타입 | 메모리 사용 | 토큰/초 (pp512) | 토큰/초 (tg128) |
|---|---|---|---|
| f16 | 4.2 GB | 3,200 | 95 |
| q8_0 | 2.1 GB | 3,180 | 93 |
| turbo3 | 0.9 GB | 3,150 | 91 |
메모리 사용량이 약 78% 줄어드는 반면, 생성 속도는 거의 동일합니다.
3. HuggingFace에서 TurboQuant 사용하기
HuggingFace transformers와 함께 TurboQuant를 사용하는 두 가지 방법을 소개합니다.
방법 1: Drop-in Cache 교체
기존 generate 코드에 cache 객체만 바꿔 끼우면 됩니다.
from transformers import AutoTokenizer, AutoModelForCausalLM
from turboquant import TurboQuantCache
# 모델 로드
model_name = "meta-llama/Llama-3-8B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype="auto",
device_map="auto",
)
# TurboQuant 캐시 생성 (4비트)
cache = TurboQuantCache(bits=4)
# 텍스트 생성
inputs = tokenizer("대한민국의 수도는", return_tensors="pt").to(model.device)
outputs = model.generate(
**inputs,
past_key_values=cache,
use_cache=True,
max_new_tokens=512,
)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))TurboQuantCache(bits=4) 한 줄만 추가하면 KV Cache가 자동으로 4비트로 압축됩니다. 기존 코드를 거의 수정하지 않아도 되는 것이 장점입니다.
방법 2: 직접 양자화 API
벡터를 직접 양자화/역양자화하여 정밀도를 확인하고 싶을 때 사용합니다.
import torch
from turboquant import TurboQuantMSE
# TurboQuant 양자화기 생성
tq = TurboQuantMSE(dim=128, bits=4, device='cuda')
# 랜덤 벡터 생성 (실제로는 Key/Value 텐서)
vectors = torch.randn(1024, 128, device='cuda')
# 양자화
indices, norms = tq.quantize(vectors)
# 역양자화
vectors_hat = tq.dequantize(indices, norms)
# 오차 확인
mse = ((vectors - vectors_hat) ** 2).mean()
print(f"MSE: {mse:.6f}")
# 출력 예시: MSE: 0.0023413비트와 4비트의 MSE 차이를 비교해보면 다음과 같습니다.
for bits in [2, 3, 4]:
tq = TurboQuantMSE(dim=128, bits=bits, device='cuda')
indices, norms = tq.quantize(vectors)
vectors_hat = tq.dequantize(indices, norms)
mse = ((vectors - vectors_hat) ** 2).mean()
print(f"{bits}-bit MSE: {mse:.6f}")
# 출력 예시:
# 2-bit MSE: 0.018742
# 3-bit MSE: 0.005123
# 4-bit MSE: 0.0023413비트에서도 MSE가 충분히 낮아 대부분의 사용 사례에서 품질 저하를 체감하기 어렵습니다.
4. 메모리 절약 계산기
KV Cache의 메모리 사용량은 다음 공식으로 계산할 수 있습니다.
KV Cache 크기 = 2 × num_layers × num_heads × head_dim × seq_len × bytes_per_element여기서 2는 Key와 Value 두 개의 캐시를 의미합니다.
예시: Llama 3 70B, 128K 컨텍스트
모델 파라미터:
- num_layers: 80
- num_heads: 64
- head_dim: 128
- seq_len: 131,072 (128K)| 양자화 | bytes_per_element | KV Cache 크기 | 절약량 |
|---|---|---|---|
| FP16 | 2.0 | ~27.3 GB | - |
| Q8_0 | 1.0 | ~13.7 GB | 13.6 GB |
| TQ4 (4-bit) | 0.55 | ~7.5 GB | 19.8 GB |
| TQ3 (3-bit) | 0.41 | ~5.6 GB | 21.7 GB |
TQ3을 사용하면 FP16 대비 21.7GB를 절약할 수 있습니다. 이 절약된 메모리로 더 큰 모델을 로드하거나, 더 긴 컨텍스트를 처리할 수 있습니다.
빠른 계산 스크립트
def calc_kv_cache_size(num_layers, num_heads, head_dim, seq_len, bytes_per_elem):
"""KV Cache 메모리 사용량 계산 (GB 단위)"""
size_bytes = 2 * num_layers * num_heads * head_dim * seq_len * bytes_per_elem
return size_bytes / (1024 ** 3)
# Llama 3 70B
configs = {
"FP16": 2.0,
"Q8_0": 1.0,
"TQ4": 0.55,
"TQ3": 0.41,
}
print("Llama 3 70B @ 128K context:")
for name, bpe in configs.items():
size = calc_kv_cache_size(80, 64, 128, 131072, bpe)
print(f" {name:6s}: {size:6.1f} GB")5. 최적 설정 가이드
모델 크기별 권장 설정
| 모델 크기 | 권장 설정 | 이유 |
|---|---|---|
| 3B 미만 | turbo4 (4-bit) | 작은 모델은 정밀도에 더 민감함 |
| 3B~13B | turbo3 (3-bit) | 대부분의 모델에서 최적의 균형점 |
| 13B 이상 | turbo3 (3-bit) | 메모리 절약 극대화, 품질 저하 무시 가능 |
작은 모델일수록 각 파라미터가 담당하는 정보의 비중이 크기 때문에, 양자화에 의한 오차가 상대적으로 더 큰 영향을 미칩니다. 13B 이상의 모델에서는 3비트 양자화를 적용해도 출력 품질에 거의 영향이 없습니다.
컨텍스트 길이별 영향
| 컨텍스트 길이 | 절약 효과 | 권장 |
|---|---|---|
| 1K 미만 | 무시할 수준 | TurboQuant 불필요 |
| 1K~4K | 중간 (~500MB~1GB) | 선택적 사용 |
| 4K~32K | 상당함 (1~4GB 절약) | 적극 권장 |
| 32K 이상 | 매우 큼 | TurboQuant가 진가를 발휘하는 구간 |
핵심: 컨텍스트가 길어질수록 TurboQuant의 가치가 커집니다. 128K 이상의 긴 컨텍스트를 사용한다면 TurboQuant는 선택이 아닌 필수입니다.
6. 주의사항과 트러블슈팅
Flash Attention은 반드시 켜야 합니다
# 올바른 사용
./build/bin/llama-server -m model.gguf --cache-type-k turbo3 -fa on
# 잘못된 사용 (Flash Attention 없이)
./build/bin/llama-server -m model.gguf --cache-type-k turbo3
# 경고: FA 없이도 동작하지만, 성능이 크게 저하됨Flash Attention이 꺼져 있으면 KV Cache에서 역양자화를 매 어텐션 계산마다 수행해야 하므로 오히려 느려질 수 있습니다.
컨텍스트 스케일링 회귀
매우 긴 컨텍스트(100K+ 토큰)에서 속도가 급격히 떨어지는 현상이 보고되고 있습니다. 이는 현재 수정 중인 알려진 이슈입니다. 임시 해결책으로는 컨텍스트를 분할하여 처리하는 방법이 있습니다.
Value가 Key보다 양자화에 취약합니다
Key 벡터는 양자화에 강한 반면, Value 벡터는 양자화 오차에 더 민감합니다. 품질이 중요한 경우 다음과 같이 Key와 Value에 다른 설정을 적용할 수 있습니다.
# Key는 3비트, Value는 4비트로 차등 적용
./build/bin/llama-server -m model.gguf \
--cache-type-k turbo3 --cache-type-v turbo4 \
-c 131072 -fa onResidual Window 설정
최근 128~256개 토큰은 FP16으로 유지하면 품질을 크게 개선할 수 있습니다. 이를 "residual window"라고 부릅니다.
# HuggingFace에서 residual window 설정
cache = TurboQuantCache(
bits=3,
residual_length=256, # 최근 256 토큰은 FP16 유지
)최근 토큰이 다음 토큰 예측에 가장 큰 영향을 미치므로, 이 부분만 고정밀도로 유지해도 출력 품질이 크게 개선됩니다.
Metal (macOS) 주의사항
Apple Silicon에서 Metal 백엔드를 사용할 때, 커스텀 헤더가 포함된 GGUF 파일은 JIT 컴파일이 실패하면서 조용히 CPU로 폴백될 수 있습니다. GPU 사용률이 예상보다 낮다면 이 문제를 의심해보세요.
# Metal GPU 사용 확인
# Activity Monitor > GPU History에서 GPU 사용률 확인
# 또는 로그에서 Metal 관련 경고 확인
./build/bin/llama-server -m model.gguf --cache-type-k turbo3 -fa on 2>&1 | grep -i metalPerplexity 검증은 필수입니다
"텍스트가 그럴듯해 보인다"는 것만으로는 품질을 판단할 수 없습니다. 반드시 perplexity를 측정하여 정량적으로 확인하세요.
./build/bin/llama-perplexity -m model.gguf \
-f wikitext-2-raw/wiki.test.raw \
--cache-type-k turbo3 --cache-type-v turbo3 \
-fa on -c 4096FP16 대비 perplexity 증가가 0.1 이내라면 실용적으로 문제가 없는 수준입니다.
7. 기존 양자화와 조합
TurboQuant는 KV Cache 양자화입니다. 모델 가중치 양자화(GGUF Q4_K_M 등)와 함께 사용하면 메모리 절약 효과가 배가됩니다.
최적의 조합
모델 가중치: GGUF Q4_K_M (4비트 가중치 양자화)
KV Cache: TurboQuant turbo3 (3비트 KV 캐시)
결과: 소비자 GPU에서 70B 모델 + 128K+ 컨텍스트 실행 가능구체적인 메모리 계산 (Llama 3 70B, 128K)
FP16 모델 + FP16 KV Cache:
모델: ~140 GB + KV Cache: ~27.3 GB = ~167.3 GB (불가능)
Q4_K_M 모델 + FP16 KV Cache:
모델: ~40 GB + KV Cache: ~27.3 GB = ~67.3 GB (A100 80GB 1장)
Q4_K_M 모델 + TQ3 KV Cache:
모델: ~40 GB + KV Cache: ~5.6 GB = ~45.6 GB (A6000 48GB 1장)
Q4_K_M 모델 + TQ3 KV Cache (32K context):
모델: ~40 GB + KV Cache: ~1.4 GB = ~41.4 GB (RTX 4090 가능)가중치 양자화와 KV Cache 양자화를 조합하면, 원래 A100 클러스터가 필요했던 설정을 소비자 GPU 한 장으로 실행할 수 있습니다.
llama.cpp 실행 예시
# Q4_K_M 가중치 + TurboQuant KV Cache
./build/bin/llama-server \
-m llama-3-70b.Q4_K_M.gguf \
--cache-type-k turbo3 --cache-type-v turbo3 \
-c 131072 -fa on -ngl 99 \
--port 80808. 커뮤니티 구현 현황
TurboQuant는 오픈소스 커뮤니티에서 활발하게 구현되고 있습니다.
| 프로젝트 | 언어 | 상태 |
|---|---|---|
| back2matching/turboquant | Python/HF | Drop-in 교체, OpenAI API 호환 |
| TheTom/turboquant_plus | C/Python/Metal | llama.cpp + Apple Silicon 최적화 |
| 0xSero/turboquant | Python/Triton | vLLM 어댑터 |
| Aaryan-Kapoor/llama.cpp | C | CPU 전용 tq3_0 타입 |
| RecursiveIntell/turbo-quant | Rust | 독립 실행형 |
각 프로젝트별 특징
back2matching/turboquant — HuggingFace transformers와 가장 잘 통합됩니다. pip install turboquant로 설치하고, TurboQuantCache 클래스를 사용하면 기존 코드에 최소한의 수정으로 적용할 수 있습니다.
TheTom/turboquant_plus — Apple Silicon에서 Metal 가속을 지원합니다. M1 이상의 Mac에서 로컬 추론을 할 때 가장 적합합니다.
0xSero/turboquant — 프로덕션 서빙 환경(vLLM)에 TurboQuant를 적용하고 싶을 때 사용합니다. Triton 커널을 사용하여 GPU에서 높은 처리량을 달성합니다.
마무리
TurboQuant는 아직 초기 단계이지만, 이미 실용적으로 사용할 수 있는 수준에 도달했습니다. 특히 긴 컨텍스트를 다루는 환경에서 메모리 절약 효과가 극적입니다.
시작하기 가장 쉬운 방법은 다음과 같습니다.
- llama.cpp fork를 빌드하고
--cache-type-k turbo3 --cache-type-v turbo3를 추가 - llama-bench로 벤치마크 돌려서 자신의 환경에서의 성능 확인
- perplexity 검증으로 품질 확인
설정 한 줄로 수십 GB의 메모리를 절약할 수 있다는 점에서, 시도하지 않을 이유가 없습니다.
이메일로 받아보기
관련 포스트

TurboQuant 완전 해부 — Google의 KV Cache 극한 압축 알고리즘
PolarQuant + Lloyd-Max로 KV Cache를 3비트까지 압축. 리트레이닝 없이 4.6배 메모리 절약, 정확도 손실 제로.

AgentScope 프로덕션 배포 — Runtime, 모니터링, 스케일링
agentscope-runtime Docker 배포, OpenTelemetry 트레이싱, AgentScope Studio, RL 파인튜닝, 프로덕션 체크리스트.

AgentScope 실시간 음성 에이전트 — OpenAI/Gemini/DashScope Realtime API
TTS 모델 6종, RealtimeAgent, 음성+도구 결합, 멀티모달 파이프라인으로 실시간 음성 에이전트 구축.