콘텐츠로 이동

TurboQuant KV 캐시 압축

TurboQuant는 긴 컨텍스트 추론을 위한 KV 캐시 압축 모드입니다. mlxcel은 attention 캐시의 일부를 더 작은 양자화 형식으로 저장하여 메모리 사용량을 줄입니다. 모델 가중치나 프롬프트는 바꾸지 않습니다.

실제로는 모델 자체는 메모리에 올라가지만 긴 대화나 여러 동시 요청을 기억하기 위한 메모리가 부족할 때 쓰는 기능이라고 보면 됩니다. TurboQuant는 이 "기억해 두는 컨텍스트"를 더 작게 저장합니다.

컨텍스트 길이, 배치 크기, 동시 요청 수 때문에 KV 캐시가 커질 때 TurboQuant를 사용하십시오. 메모리가 충분하거나, 기준선과 비교 중이거나, 아래 지원 구성 표에 없는 모델 계열이라면 기본 fp16 캐시를 유지하는 편이 낫습니다.

구현은 TurboQuant 논문(Zandieh et al., ICLR 2026, arXiv:2504.19874)과 독립 TurboQuant+ 프로젝트에서 검증한 PolarQuant 전용 변형을 따릅니다.

TurboQuant KV 캐시 개요

목차

KV 캐시가 중요한 이유

자동회귀 생성에서 모델은 매 토큰마다 이전 토큰 전체를 처음부터 다시 계산하지 않습니다. 대신 각 트랜스포머 레이어는 이미 처리한 모든 토큰에 대해 두 텐서를 저장합니다.

  • K, key: 다음 토큰이 어디에 주목할지 attention score를 계산할 때 사용합니다.
  • V, value: attention score에 따라 섞여 다음 hidden state를 만드는 데 사용합니다.

이 저장된 상태가 KV 캐시입니다. KV 캐시는 디코드를 실용적으로 만들지만 컨텍스트 길이, 레이어 수, KV head 수, 각 head 벡터의 크기, 활성 sequence 수에 비례해 커집니다. 여기서 활성 sequence는 동시에 디코드 중인 요청이나 배치 항목 하나를 뜻합니다. 짧은 컨텍스트에서는 모델 가중치에 비해 작을 수 있지만 긴 컨텍스트나 높은 동시성에서는 주요 메모리 비용이 됩니다.

KV 캐시는 현재 요청을 위한 모델의 작업 노트라고 생각하면 쉽습니다. 프롬프트가 길거나, 컨텍스트 윈도우가 크거나, 동시에 처리하는 사용자가 많으면 이 노트도 커집니다. TurboQuant는 이 노트를 압축해 더 긴 세션을 메모리에 유지할 수 있게 합니다.

TurboQuant가 바꾸는 것

TurboQuant는 KV 캐시의 저장 방식을 바꿉니다. 모델 가중치나 프롬프트는 그대로 두고 캐시 텐서를 저장할 때 다음 절차를 적용합니다.

  1. 캐시 벡터를 압축하기 쉬운 모양으로 바꿉니다.
  2. 각 값을 더 적은 비트로 저장합니다.
  3. attention 계산에서 읽어야 할 때 다시 펼칩니다.

첫 단계에는 Walsh-Hadamard transform을 사용하고 작은 저장 형식에는 PolarQuant codebook을 사용합니다. 사용자가 이 세부 요소를 직접 조정할 필요는 없습니다. 보통은 캐시 모드와 boundary 설정만 고르면 됩니다.

mlxcel의 기본 TurboQuant 권장 모드는 fp16+turbo4입니다. 이 모드는 K는 FP16으로 유지하고 V만 4비트 TurboQuant 저장 형식으로 압축합니다.

이 기본값은 의도적으로 비대칭입니다. K는 모델이 어디를 볼지 결정할 때 사용됩니다. K가 왜곡되면 모델이 잘못된 토큰을 볼 수 있습니다. V는 attention이 볼 위치를 정한 뒤 섞이는 내용에 가깝기 때문에 보통 더 안전하게 압축할 수 있습니다. 그래서 dense Q4KM 모델에서는 fp16+turbo4를 시작점으로 권장합니다.

Boundary-V 보호는 처음과 마지막 몇 개 트랜스포머 레이어의 V를 FP16으로 유지합니다. 이 레이어들은 압축에 더 민감한 경우가 많으므로, 일부 메모리 절감을 포기하고 출력 품질을 더 안정적으로 유지하는 정책입니다.

처음 선택할 모드

상황 시작 모드
가장 낮은 운영 위험으로 KV 메모리를 줄이고 싶을 때 fp16+turbo4
Llama, Qwen, Mistral 같은 dense Q4KM 모델을 사용할 때 fp16+turbo4
K와 V를 모두 압축해야 하고 모델 계열이 allowlist에 있을 때 turbo4
delegated hot/cold 캐시 경로를 실험할 때 turbo4-delegated
V 측 압축률을 더 높이고 직접 품질을 확인할 수 있을 때 fp16+turbo3

첫 배포에서는 기본 boundary 설정과 함께 fp16+turbo4를 우선 사용하십시오. 더 공격적인 모드는 실제 서비스 프롬프트 분포에서 출력 품질을 확인한 뒤 선택하는 것이 좋습니다.

캐시 모드

--kv-cache-mode 값 K 측 V 측 KV 메모리 (FP16 대비) 품질 비용 권장 용도
fp16 (기본) FP16 FP16 1.00배 없음 기준선 동작
int8 INT8 per-token absmax INT8 per-token absmax 약 0.50배 작은 양자화 오차 단순 INT8 캐시 저장을 쓰는 긴 컨텍스트
fp16+turbo4 (별칭 turbo4-asym) FP16 4비트 PolarQuant + WHT boundary 레이어 적용 전 약 0.74배 지원 모델에서 낮음 권장 TurboQuant 기본값
turbo4 (별칭 turbo4-sym) 4비트 PolarQuant + WHT 4비트 PolarQuant + WHT boundary 레이어 적용 전 약 0.27배 모델 의존 대칭 allowlist에 있는 모델 계열
fp16+turbo3 FP16 3비트 PolarQuant + WHT boundary 레이어 적용 전 약 0.72배 Turbo4 V보다 높음 더 공격적인 V 측 압축
turbo3 FP16 3비트 PolarQuant + WHT fp16+turbo3와 같음 fp16+turbo3와 같음 비대칭 Turbo3 별칭
turbo4-delegated FP16 hot/cold K FP16 hot tail + Turbo4 cold body 긴 컨텍스트에서 약 0.74배 fp16+turbo4와 유사 delegated 캐시 디코드 실험

단순 메모리 공식은 (K_bits + V_bits) / (2 * 16)에 작은 블록별 norm sidecar 비용을 더한 값입니다. Boundary-V 보호는 일부 V 레이어를 FP16으로 유지하므로, Turbo 모드의 실제 메모리 사용량은 표의 값보다 큽니다.

표의 WHT는 Walsh-Hadamard transform을 뜻합니다. 캐시 벡터를 작은 codebook으로 저장하기 쉽게 만드는 회전 단계입니다.

CLI 플래그

mlxcel generate, mlxcel serve, mlxcel-server는 같은 TurboQuant 플래그를 공유합니다.

플래그 환경 변수 기본값 설명
--kv-cache-mode <MODE> - fp16 통합 KV 캐시 모드. 위 표의 모드 값을 받습니다.
--cache-type-k <TYPE> LLAMA_ARG_CACHE_TYPE_K fp16 K 측 llama-server 호환 split 플래그.
--cache-type-v <TYPE> LLAMA_ARG_CACHE_TYPE_V fp16 V 측 llama-server 호환 split 플래그.
--turbo-boundary-v <COUNT> MLXCEL_KV_BOUNDARY_V_LAYERS 2 Turbo 모드에서 V 캐시를 FP16으로 유지할 앞/뒤 트랜스포머 레이어 수.

split 플래그와 --kv-cache-mode가 함께 주어지면 split 플래그가 우선하고 mlxcel은 경고를 기록합니다. split 플래그 중 하나만 주어지면 나머지 측은 fp16으로 처리됩니다.

지원되는 K/V split 조합

--cache-type-k --cache-type-v 실제 모드
fp16 fp16 Fp16
int8 int8 Int8
fp16 turbo4 Turbo4Asym
fp16 turbo4-asym Turbo4Asym
turbo4 turbo4 Turbo4
fp16 turbo4-delegated Turbo4Delegated
fp16 turbo3 Turbo3Asym
fp16 turbo3-asym Turbo3Asym

다른 조합은 시작 시점에 거부되며 오류 메시지에 지원되는 쌍이 표시됩니다. 대칭 Turbo3(turbo3 / turbo3)는 노출하지 않습니다.

split 플래그는 llama.cpp에서 비양자화 FP16 저장을 가리키는 f16 표기도 fp16으로 받습니다. 그 밖의 GGML 캐시 타입(q8_0, q4_0, q4_1, iq4_nl, q5_0, q5_1, f32, bf16)은 mlxcel 모드와 수치적으로 같지 않으므로 이유를 설명하는 오류와 함께 거부됩니다. 여기서 int8은 토큰별 absmax 방식이고 Turbo 모드는 Walsh-Hadamard 회전을 쓰는 PolarQuant입니다. fp16+turbo4-delegated는 turbo4-delegated의 별칭으로 받습니다.

예시

오프라인 생성

# 권장 TurboQuant 기본값: FP16 K, Turbo4 V.
mlxcel generate -m models/<model> --kv-cache-mode fp16+turbo4 -p "Hello" -n 200

# 대칭 Turbo4. allowlist에 있는 모델 계열에만 사용하십시오.
mlxcel generate -m models/<model> --kv-cache-mode turbo4 -p "Hello" -n 200

# delegated 캐시 경로.
mlxcel generate -m models/<model> --kv-cache-mode turbo4-delegated -p "Hello" -n 200

서버

# 통합 모드 플래그.
mlxcel-server -m models/<model> --kv-cache-mode fp16+turbo4

# llama-server 호환 split 플래그.
mlxcel-server -m models/<model> --cache-type-k fp16 --cache-type-v turbo4

# 같은 설정을 환경 변수로 지정.
LLAMA_ARG_CACHE_TYPE_K=fp16 LLAMA_ARG_CACHE_TYPE_V=turbo4 mlxcel-server -m models/<model>

튜닝

Boundary-V 레이어 보호

Turbo 모드가 활성화되면 앞/뒤 --turbo-boundary-v개의 트랜스포머 레이어는 FP16 V 캐시를 유지합니다. 기본값은 2이며 TurboQuant+ 검증 작업에서 사용한 LA-V7 정책과 같은 방향입니다.

mlxcel generate --kv-cache-mode fp16+turbo4 --turbo-boundary-v 2 \
    -m models/<model> -p "Hello" -n 50

# 같은 설정을 환경 변수로 지정.
MLXCEL_KV_BOUNDARY_V_LAYERS=4 mlxcel generate --kv-cache-mode fp16+turbo4 ...

특수 값:

  • 0: boundary 보호를 비활성화합니다.
  • 2: 기본값이며 일반적인 28~64 레이어 모델에 적합합니다.
  • n_layers / 2보다 큰 값은 잘립니다. 예를 들어 4레이어 모델에 --turbo-boundary-v 8을 지정하면 4개 레이어 모두 FP16으로 유지되고 오류는 발생하지 않습니다.

Sparse-V dequant 임계값

attention 가중치가 임계값보다 낮은 위치에서는 출력 기여가 작기 때문에 V dequantization을 건너뛸 수 있습니다.

MLXCEL_SPARSE_V_THRESHOLD=1e-5 mlxcel generate --kv-cache-mode fp16+turbo4 ...

기본 임계값은 1e-6입니다. macOS에서는 임계값이 0이 아닐 때 fused Metal 커널이 사용됩니다. graph reference 경로와 비교하려면 MLXCEL_SPARSE_V_KERNEL=0을 설정하십시오.

Delegated 캐시 변형

delegated 캐시는 최근 토큰을 FP16으로 유지하고 오래된 V 토큰은 Turbo4 형태로 저장합니다. 즉, 최근 부분은 읽기 쉬운 형태로 두고 오래된 부분은 작게 저장하는 구조입니다. 아래 변수들은 실험과 성능 비교를 위한 고급 설정입니다.

환경 변수 효과
MLXCEL_TURBO4_DELEGATED_DEQUANT_SDPA=0 기본 dequant-first SDPA 경로 대신 구형 커스텀 packed-V Metal 경로를 사용합니다.
MLXCEL_TURBO4_DELEGATED_FUSED=1 dequant-first SDPA가 꺼진 상태에서 cold-only fused composition 커널을 사용합니다.
MLXCEL_TURBO4_DELEGATED_FP16_FAST_PATH=1 packed sidecar와 별도로 FP16 V working set을 유지합니다. 속도 비교에는 유용하지만 압축 메모리 목표는 충족하지 않습니다.
MLXCEL_TURBO4_DELEGATED_FP16_SIDECARS=lazy FP16 fast path가 활성화된 상태에서 sidecar fold를 캐시 보존 시점까지 늦춥니다.

지원 구성

모델 계열 권장 모드 대칭 turbo4
Llama 3.x, Qwen 2.5, Qwen 3, Mistral dense Q4KM 모델 fp16+turbo4 기본 allowlist에는 없음
Qwen3.5 및 Qwen3-Next 계열 fp16+turbo4, 대칭 모드가 필요하면 turbo4 allowlist에 있음
Qwen 2-VL, Qwen 2.5-VL, Aya-Vision VLM 지원되는 text/VLM 사례에서는 fp16+turbo4 대칭 turbo4 미검증
Gemma 3 및 Gemma 4 로컬에서 직접 테스트하지 않았다면 fp16 사용 미검증

현재 대칭 turbo4 allowlist 항목은 qwen3_5, qwen3_5_moe, qwen3_next입니다. Q8 모델과 70B 이상 Q4KM 모델은 향후 allowlist 후보가 될 수 있지만 런타임이 가중치 등급을 식별하고 해당 계열이 별도 테스트를 통과하기 전에는 일반적으로 활성화된 것으로 문서화하지 않습니다.

allowlist 밖의 dense Q4KM 모델에서 대칭 turbo4를 사용하면 K 측 양자화가 attention score에 영향을 주어 PPL이 크게 악화될 수 있습니다. 이런 모델에는 fp16+turbo4를 사용하십시오.

알려진 제한 사항

헤드 차원 제약

TurboQuant는 64, 128, 256 같은 2의 거듭제곱 헤드 차원이 필요합니다. 80, 96, 192 같은 헤드 차원은 패딩 없이 TurboQuant를 사용할 수 없으며 캐시 초기화 시점에 거부됩니다.

대칭 Turbo3

대칭 turbo3는 노출하지 않습니다. --kv-cache-mode turbo3와 --cache-type-v turbo3는 비대칭 fp16+turbo3 모드로 해석됩니다.

Paged KV 스케줄러

--kv-cache-mode <turbo4-variant> --decode-storage-backend paged는 서버 디스패치 경로에 연결되어 있습니다. Apple Silicon에서 디코드 처리량과 동시 prefix 일관성에 대한 종단 간 검증은 아직 진행 중입니다.

M5 Max delegated 디코드 속도

M5 Max에서 기본 압축 turbo4-delegated 경로는 0.97배 FP16 디코드 속도 목표를 항상 만족하지는 않습니다. MLXCEL_TURBO4_DELEGATED_FP16_FAST_PATH=1 변형은 속도 실험에 사용할 수 있지만 FP16 V working set 전체를 유지하므로 메모리 특성이 달라집니다.

M3 이전 하드웨어

turbo3는 M1/M2 GPU 마이크로아키텍처에서 대역폭 병목을 만들 수 있습니다. M1/M2의 디코드 중심 작업에서는 fp16+turbo4를 우선 사용하십시오.

VLM 커버리지

현재 측정은 Qwen 2.5-VL 3B 대리 모델로 Qwen2-VL 2B를 사용하고 Aya-Vision 8B를 4K 이하 컨텍스트에서 검증합니다. 다른 VLM 계열과 8K 초과 멀티 이미지 프롬프트는 별도 검증이 필요합니다.