KV 캐시 양자화(KV cache quantization): FP8/INT8 K 및 V가 실제로 제공하는 이점과 한계점
요약
LLM 서빙 시 긴 컨텍스트 처리를 위한 KV 캐시 양자화의 원리와 이점, 한계를 분석합니다. FP8/INT8 양자화를 통해 메모리 점유율을 낮추어 인프라 비용을 절감하는 방법과 그에 따른 정확도 트레이드오프를 다룹니다.
핵심 포인트
- KV 캐시는 컨텍스트 길이에 따라 증가하는 동적 메모리 핵심 요소임
- FP8/INT8 양자화로 BF16 대비 메모리 사용량을 약 50% 절감 가능
- 정확도 손실은 미미하지만 서빙 복잡성 및 기능 호환성 고려 필요
- 인프라 비용 절감과 모델 출력 품질 사이의 엔지니어링 트레이드오프 발생
KV 캐시 양자화(KV cache quantization): FP8/INT8 K 및 V가 실제로 제공하는 이점과 한계점
당신은 방금 8개의 H100에서 70B Llama 파인튜닝 모델을 배포했고, 서빙 박스는 200개의 동시 8k 컨텍스트를 즐겁게 처리하고 있습니다. 그런데 제품 팀에서 "32k도 가능할까요?"라고 말하는 순간, 갑자기 계산이 맞지 않게 됩니다. BF16을 사용할 경우, 32k 컨텍스트를 가진 70B Llama-3의 KV 캐시만 해도 대략 2 × 80 layers × 8 KV heads × 32768 tokens × 128 head_dim × 2 bytes ≈ 요청당 10.7 GB입니다. 이런 요청이 200개라면 H100은 CPU로 페이징(paging)을 하게 됩니다. 모델 자체는 들어가지만, _어텐션 상태(attention state)_가 들어가지 않는 것입니다. 이것이 바로 KV 캐시 양자화(KV cache quantization)가 만들어진 이유이며, 지난주에 다룬 투기적 디코딩(speculative decoding)에 대한 글의 자연스러운 후속 주제입니다. 왜냐하면 이 두 기능은 벤더의 벤치마크에서는 항상 나타나지 않는 방식으로 상호작용하기 때문입니다.
이것이 어떻게 작동하는지, 포맷은 무엇인지, 그리고 어디에 주의해야 할 함정(footguns)이 숨어 있는지 알아보겠습니다.
이것이 실무에서 중요한 이유
KV 캐시는 서빙되는 LLM에서 가장 큰 동적(dynamic) 메모리 조각입니다. 모델 가중치(weights)는 로드 시점에 고정됩니다. 활성화 값(activations)은 각 순전파(forward pass) 이후에 해제됩니다. KV 캐시는 batch_size × seq_len에 따라 증가하며 요청이 끝날 때까지 할당된 상태로 유지됩니다. 긴 컨텍스트(long-context) 워크로드에서는 KV 캐시가 지배적입니다.
KV 캐시 양자화는 모델 가중치의 변경 없이, 캐시 점유 공간을 2배 또는 4배 줄이는 대신 약간의 _표현 정밀도(representational precision)_를 희생합니다. FP8 및 INT8은 BF16 점유 공간의 약 50%를 제공합니다. INT4(KIVI, KVQuant, ZipCache 스타일)는 25%를 제공합니다. 문제는 이러한 압축이 출력 품질, 서빙 복잡성, 그리고 — 대부분의 블로그 포스트가 생략하는 부분인 — 이미 활성화해 둔 다른 서빙 기능들과의 호환성 측면에서 어떤 대가를 치르게 하는가 하는 점입니다.
경제적 관점은 명확합니다. 32k 컨텍스트에서 70B 모델의 KV 캐시 예산을 두 배로 늘린다는 것은, 약 21GB의 HBM이 더 필요하거나(32k 컨텍스트에서 동시 사용자 약 10명당 H100 1대 추가 필요), 혹은 서버당 동시 사용자 수가 절반으로 줄어든다는 것을 의미합니다. 표준 롱 컨텍스트 (long-context) 벤치마크로 측정한 FP8 KV 캐시의 품질 비용은 검색 중심 (retrieval-heavy) 작업에서 일반적으로 0.5%포인트 미만입니다. 이는 0.5%포인트 미만의 정확도 손실로 50%의 인프라 비용을 절감하는 것입니다. 트레이드오프 (trade-off)는 유리하지만, 엔지니어링 비용이 공짜는 아닙니다.
KV 캐시 양자화 (KV cache quantization)란 실제로 무엇인가
표준 BF16 어텐션 (attention)은 K와 V 텐서를 전체 정밀도 (full precision)로 저장합니다. 모든 어텐션 단계에서 모델은 과거의 모든 K와 V를 읽어들입니다. 양자화 (quantization)는 이러한 저장된 텐서들을 더 낮은 정밀도 형식으로 압축하며, 행렬 곱셈 (matmul) 직전에 어텐션 커널 (attention kernel)에 통합된 역양자화 (dequantization) 단계를 거칩니다.
파이프라인은 다음과 같습니다:
flowchart LR
A[New token<br/>embedding] --> B[Project to Kt Vt<br/>BF16, in registers]
B --> C[Quantize Kt Vt<br/>per-token / per-head]
...
주의 깊게 봐야 할 세 가지 사항이 있습니다: 캐시에 추가되는 활성화 값 (activations)은 저장 (storage) 시점에만 양자화되며, 스케일 (scale) 계산을 위해 전체 BF16 값을 사용할 수 있습니다. 어텐션 행렬 곱셈 (matmul)은 여전히 BF16 또는 FP16에서 수행됩니다. 즉, 절약되는 것은 연산량 (FLOPs)이 아니라 메모리 대역폭 (memory bandwidth)입니다. 그리고 토큰별 (per-token) 또는 헤드별 (per-head) 스케일 (8k 컨텍스트 기준 몇 KB)은 BF16 형식으로 함께 저장되며, 이것이 나머지 수학적 연산이 작동하게 만드는 핵심입니다.
실제로 접하게 될 형식들
2026년 프로덕션 서빙 스택 (production serving stacks)을 지배하는 다섯 가지 형식이 있습니다. 목록은 대략 도입된 순서대로 나열되었습니다.
| 형식 | 비트 (Bits) | 입도 (Granularity) | 하드웨어 지원 | 사용처 |
|---|---|---|---|---|
| BF16 (baseline) | 16 | — | Ampere+에서 네이티브 지원 | 모든 곳 |
| ... | ||||
| 표에 대한 몇 가지 참고 사항: |
- FP8 E4M3 vs E5M2. E4M3는 정밀도(precision)가 더 높고 범위(range)가 좁으며, E5M2는 범위가 더 넓고 정밀도가 낮습니다. KV 캐시(KV cache)의 경우, K와 V 활성화 함수(activations)의 동적 범위(dynamic range)가 소프트맥스(softmax)에 의해 제한되기 때문에 E4M3가 주를 이룹니다. E5M2는 원래 그래디언트(gradients)를 위해 지정되었습니다.
- INT8 per-token asymmetric. 실질적인 주력 포맷입니다. 각 토큰의 K와 V는 각각 고유한
(scale, zero_point)쌍을 가집니다. 채널별(per-channel, head_dim 슬라이스당 하나의 scale) 방식은 하드웨어에서 더 빠르지만 정확도가 약간 낮습니다. 텐서별(per-tensor, 전체 캐시에 하나의 scale) 방식은 비용이 가장 저렴하지만 손실이 가장 큽니다. - Mixed-precision 4-bit (KVQuant, KIVI, ZipCache). K는 이상치(outliers)가 존재하는 채널별(per-channel)로 양자화하고, V는 토큰별(per-token)로 양자화하여, 단순한 INT4 방식보다 훨씬 적은 정확도 손실로 4비트 저장 용량을 확보합니다. vLLM은 v0.22.1 기준으로 4비트 KV를 제공하지 않으며, llama.cpp는 CPU 및 일부 Apple Silicon 경로에서 이를 지원합니다.
- NVFP4 (E2M1 + block scales). vLLM v0.22.0에 도입된 (DeepSeek V4의 NVFP4 fused MoE) 가중치(weights)용 별도 포맷입니다. KV 캐시 포맷이 아니며, 스케일링 방식과 코드 경로가 다릅니다.
vLLM 배포 시 사용 방법
CLI 플래그는 --kv-cache-dtype입니다. vLLM v0.22.1에서 허용되는 값은 auto, fp8 (E4M3), fp8_e5m2, int8, 그리고 bf16 (기본값; 모델이 FP8-native로 감지되지 않는 한 auto는 bf16으로 결정됨)입니다. OpenAI 호환 서버를 실행할 경우:
vllm serve meta-llama/Meta-Llama-3-70B-Instruct \
--tensor-parallel-size 8 \
--kv-cache-dtype fp8 \
...
프로그래밍 방식으로 사용할 경우:
from vllm import LLM
llm = LLM(
...
H100에서는 FP8 경로가 Transformer Engine의 fused attention을 통해 실행되며, B100/B200에서는 FlashAttention-3 FP8 커널을 통해 실행됩니다. Hopper 이전 세대 하드웨어(A100, RTX 4090)에서 FP8 플래그는 아무 동작도 하지 않거나(no-op) 느린 경로를 사용합니다. 이는 네이티브 FP8 텐서 코어(tensor core)가 없기 때문입니다. 반면, INT8은 Triton을 통해 어디에서나 실행됩니다.
한 가지 실무적인 세부 사항: H100에서 --kv-cache-dtype fp8을 사용하면 KV 캐시 (KV cache) 메모리가 약 50% 감소하지만, 모델의 가중치(weight) 점유 공간은 줄어들지 않습니다. BF16 형식의 70B 모델은 여전히 140 GB입니다. 절감 효과는 실재하지만, 워크로드의 캐시 대 가중치 비율(cache-to-weight ratio)에 의해 제한됩니다. 즉, 긴 컨텍스트(long-context) 및 높은 동시성(high-concurrency) 워크로드가 가장 큰 이점을 얻습니다.
추측적 디코딩 (Speculative decoding)과의 상호작용 방식
이것은 조용히 발등을 찍는 실수(footgun)가 될 수 있습니다. 지난주 추측적 디코딩(speculative decoding)에 관한 포스트에서는 수락 확률 r = min(1, M_p(x) / M_q(x))와 사이클당 평균 수락 토큰 수인 μ를 이용한 속도 향상 공식을 설명했습니다. KV 캐시 양자화(KV cache quantization)는 그 밑바탕에 깔린 암묵적인 가정, 즉 제안 위치(proposal position)에서의 타겟 모델의 로짓(logit)이 초안 모델(draft model)과 동일한 수치 정밀도로 계산된다는 가정을 깨뜨립니다.
작동 메커니즘은 다음과 같습니다:
- 초안 모델은 자체 KV 캐시(초안 캐시, 일반적으로 BF16)를 사용하여 토큰
x_t를 제안합니다. - 타겟 모델은 모든 제안을 평가하기 위해 K+1 위치에 대해 한 번의 순전파(forward pass)를 수행합니다. 타겟 모델은 양자화된 (quantized) KV 캐시를 읽고, 실시간으로 역양자화(dequantize)를 수행하며, BF16에서 어텐션(attention)을 실행합니다.
M_p(x_t)대M_q(x_t)의 수락 확인은 여전히 수행되지만, 이제M_p는 FP8 또는 INT8로 반올림된 K 및 V 값을 사용합니다.- 수락 확률은 수학적으로 여전히 잘 정의되어 있지만, 타겟 모델의 _분포 (distribution)_가 BF16 기준점(baseline)에 비해 약간 이동했습니다. 이 이동이 경험적 (empirical)
μ를 변화시킵니다.
그 크기는 포맷과 컨텍스트 길이에 따라 달라집니다. 커뮤니티 벤치마크와 양자화된 캐시를 사용한 추측적 디코딩(spec-decoding)에 관한 발표된 연구들에 따르면, 사이클당 평균 수락 토큰 수는 FP8 E4M3의 경우 일반적으로 0.3–0.8, INT8 per-token의 경우 0.5–1.5 정도 감소합니다. 속도 향상 곡선이 μ = 4 부근에서 급격히 변하는 구간(knee)이 있다는 점을 기억하지 못한다면 이 수치는 작게 들릴 수 있습니다. 하지만 4.5에서 3.5로 떨어지는 것은 당신이 얻었다고 생각했던 속도 향상의 20–30%를 순식간에 날려버릴 수 있습니다.
vLLM v0.18.0 릴리스 노트에서는 특정 사례에 대해 이를 지적했습니다: B200에서 FP8 KV 캐시 (KV cache)를 사용하여 Qwen3.5를 서빙할 때 정확도가 저하되는 현상 (#37618). 이 교훈은 일반화될 수 있습니다: 서빙 최적화(serving optimizations)를 쌓아 올릴 때
- Hopper 이전 세대 GPU를 사용 중이며 Triton-fused INT8 커널 경로가 없는 경우. 해당 플래그는 아무런 동작을 하지 않거나(no-op) 느린 시뮬레이션으로 작동할 것입니다. 클러스터 간의 일관성을 위해 이를 활성화하지 마십시오.
- 워크로드의 컨텍스트(context)가 짧은 경우. 중간 요청 토큰 수가 2k 미만이라면 KV 캐시(KV cache)는 병목 지점이 아닙니다. 활성화 값(activations), 가중치(weights), 그리고 프리필(prefill) 연산이 병목입니다. 캐시를 양자화(quantizing)해도 큰 차이를 만들 수 없습니다.
- 수용 한계에 아슬아슬하게 걸쳐 있는 draft-target 쌍과 함께 투기적 디코딩(speculative decoding)을 쌓아 올리는 경우. BF16에서 측정된
μ값이 3.0 미만이라면, FP8로 인해 발생하는 0.3~1.0의 추가적인 수용률(acceptance-rate) 저하가 수용률을 1.0 미만으로 떨어뜨려 알고리즘을 결과적으로 손해를 보는 구조로 만들 수 있습니다. 먼저 측정하고, 그 다음에 활성화하십시오. - 재검증이 불가능한 엄격한 정확도 SLO(Service Level Objective)를 준수해야 하는 경우. 의료, 법률, 금융과 같은 도메인에서 0.1% 미만의 성능 저하(regression)만을 허용해야 한다면, FP8 KV 캐시는 단순히 켜고 끌 수 있는 스위치가 아닙니다. 단순한 벤치마크 확인이 아닌, 배포 시마다 수행되는 정확도 검증(accuracy validation)이 필요합니다.
- 모델에 헤드별로 심한 이상치(outliers)가 존재하는 경우. 일부 아키텍처(특정 MoE 라우터, 강력한 이상치 채널을 가진 MLA 등)는 헤드당 몇 개의 K/V 값에 매우 큰 크기(magnitude)를 할당합니다. 이 경우 텐서별(per-tensor) 또는 헤드별(per-head) 양자화는 심각하게 무너집니다. 토큰별 스케일(Per-token scales) 적용이 필수적입니다.
요약 (TL;DR)
- **KV 캐시 양자화 (KV cache quantization)**는 요청별 K 및 V 텐서를 FP8 또는 INT8로 압축하며, 역양자화 (dequantization) 과정은 어텐션 커널 (attention kernel)에 융합 (fused)됩니다. 연산은 BF16으로 유지되지만, _저장 공간 (storage)_과 _메모리 대역폭 (memory bandwidth)_이 줄어듭니다.
- 캐시 크기는
2 × layers × kv_heads × seq_len × head_dim × bytes로 확장됩니다. 32k BF16 환경의 70B Llama-3의 경우, 요청당 약 10.7 GB가 필요합니다. FP8은 이를 절반으로 줄이고, INT8도 절반으로 줄이며, 4비트 방식은 4분의 1로 줄입니다. - vLLM v0.22.1에서는
--kv-cache-dtype fp8또는int8을 설정하십시오. FP8은 H100/H200/B100/B200/MI300X에서만 지원되며, INT8은 Triton을 통해 어디서나 실행 가능합니다. - **품질 비용 (quality cost)**은 일반적으로 긴 문맥 검색 (long-context retrieval) 벤치마크에서 0.5점 미만이지만, 손실이 특정 부분에 집중되어 있어 짧은 문맥 평가 (short-context evals)에서는 잘 드러나지 않습니다.
- 추측적 디코딩 (speculative-decoding)과의 상호작용은 조심해야 할 숨겨진 위험 요소입니다. FP8/INT8 캐시는 타겟 모델의 로짓 분포 (logit distribution)를 변화시키며, 이로 인해 사이클당 평균 수락 토큰 수 (mean accepted tokens per cycle)가 0.3~1.5만큼 감소할 수 있습니다. 이를 활성화한 후에는
num_speculative_tokens를 다시 조정하십시오. - Triton 경로가 없는 Hopper 이전 세대의 GPU, 짧은 문맥 워크로드, 이미 수락률이 낮은 초안/타겟 (draft/target) 쌍을 사용하는 경우, 또는 특정 배포 환경에 대해 재검증되지 않은 엄격한 정확도 SLO(서비스 수준 목표) 하에서는 활성화하지 마십시오.
다음 포스트: 대규모 프리픽스 캐싱 (prefix caching at scale) — 프리필 (prefill) 비용을 80% 절감하는 방법과, 실제 운영 환경에서 이를 조용히 5% 절감으로 전락시키는 방출 정책 (eviction policies)에 대하여.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기