Blog
llm-inferencequantizationkv-cacheoptimizationvllmai
LLM 추론 최적화 가이드 - 양자화, KV Cache, 추측적 디코딩
LLM 추론 최적화의 핵심 기법인 양자화(GPTQ, AWQ, GGUF), KV Cache 최적화, 추측적 디코딩, 배치 처리, 텐서 병렬, FlashAttention을 체계적으로 정리합니다.
Data Dynamics2026年4月16日12 min read
This post is not yet translated. The original Korean version is shown below.
LLM 추론 최적화는 제한된 GPU 자원에서 최대한의 처리량과 최소한의 지연시간을 달성하는 핵심 기술입니다. 이 글에서는 양자화, KV Cache, 추측적 디코딩 등 주요 최적화 기법을 체계적으로 다룹니다.
1. LLM 추론의 이해
추론 과정
LLM 추론은 **Prefill(입력 처리)**과 Decode(토큰 생성) 두 단계로 나뉩니다.
[LLM 추론 단계]
입력: "Spark 성능을 최적화하는 방법은?"
↓
[Prefill 단계] — 입력 토큰을 한 번에 병렬 처리
- KV Cache 생성
- 계산 집약적 (GPU 컴퓨트 바운드)
- TTFT (Time to First Token) 결정
↓
[Decode 단계] — 토큰을 하나씩 순차 생성
- KV Cache 읽기 + 업데이트
- 메모리 집약적 (메모리 바운드)
- TPS (Tokens Per Second) 결정
↓
출력: "Spark 성능을 최적화하려면 다음 방법을..."
핵심 성능 지표
| 지표 | 설명 | 영향 요소 |
|---|---|---|
| TTFT | 첫 번째 토큰 생성 시간 | Prefill 속도, 모델 크기 |
| TPS | 초당 생성 토큰 수 | Decode 속도, 메모리 대역폭 |
| Throughput | 전체 처리량 (tok/s) | 배칭, GPU 활용률 |
| Latency (P95) | 95번째 백분위 응답 시간 | 큐잉, 스케줄링 |
GPU 메모리 구성
[7B 모델의 GPU 메모리 사용 (FP16)]
총 GPU 메모리: 24 GB (RTX 4090)
모델 가중치: ██████████████ 14 GB (58%)
KV Cache: ████████ 8 GB (33%)
활성화/임시: ██ 2 GB (9%)
─────────────────────────
합계: 24 GB
→ KV Cache가 동시 요청 수를 결정하는 병목
2. 양자화 (Quantization)
양자화란
모델 가중치의 정밀도를 줄여 메모리 사용량과 연산량을 절감하는 기법입니다.
FP32 (32비트): 0.12345678901234567890 → 4바이트/파라미터
FP16 (16비트): 0.1235 → 2바이트/파라미터 (2x 절감)
INT8 (8비트): 31 → 1바이트/파라미터 (4x 절감)
INT4 (4비트): 7 → 0.5바이트/파라미터 (8x 절감)
주요 양자화 방식 비교
| 방식 | 비트 | 품질 손실 | 속도 | 추론 환경 | 대표 도구 |
|---|---|---|---|---|---|
| FP16/BF16 | 16 | 없음 | 기준 | GPU | 기본 |
| GPTQ | 4 | 매우 적음 | 빠름 | GPU (CUDA) | AutoGPTQ |
| AWQ | 4 | 매우 적음 | 매우 빠름 | GPU (CUDA) | AutoAWQ |
| GGUF | 2~8 | 방식에 따라 | 보통 | CPU/GPU | llama.cpp |
| BitsAndBytes | 4/8 | 적음 | 보통 | GPU | HuggingFace |
| FP8 | 8 | 거의 없음 | 빠름 | H100+ | vLLM, TRT-LLM |
| AQLM | 2 | 중간 | 빠름 | GPU | - |
GGUF 양자화 (llama.cpp / Ollama)
# GGUF 양자화 수준별 비교 (LLaMA 3.1 8B)
# Q2_K: 2.7 GB — 품질 저하 있음, 최소 메모리
# Q4_K_M: 4.1 GB — 좋은 균형점 (가장 추천)
# Q5_K_M: 4.8 GB — 우수한 품질
# Q6_K: 5.5 GB — 높은 품질
# Q8_0: 7.2 GB — 거의 원본 수준
# FP16: 14.0 GB — 원본
# Ollama에서 양자화 모델 사용
ollama run llama3.1:8b-q4_K_MAWQ 양자화 (GPU 서빙용)
# AWQ 양자화 모델을 vLLM으로 서빙
python -m vllm.entrypoints.openai.api_server \
--model TheBloke/Llama-3.1-8B-Instruct-AWQ \
--quantization awq \
--max-model-len 4096양자화 선택 가이드
[GPU 서빙인가?]
├─ Yes
│ ├─ H100/A100 → FP8 (최소 손실, 최고 속도)
│ ├─ A100/A10 → AWQ 4비트 (높은 품질, 빠른 속도)
│ └─ RTX 4090 → GPTQ 또는 AWQ 4비트
└─ No (CPU 또는 혼합)
└─ GGUF Q4_K_M (Ollama/llama.cpp)
3. KV Cache 최적화
KV Cache란
Transformer의 Self-Attention 계산 시, 이전 토큰의 Key/Value를 캐싱하여 중복 계산을 방지합니다.
[KV Cache 없이]
토큰 1 생성: K,V 계산 (토큰 0)
토큰 2 생성: K,V 계산 (토큰 0, 1) ← 토큰 0 재계산!
토큰 3 생성: K,V 계산 (토큰 0, 1, 2) ← 토큰 0, 1 재계산!
→ O(n²) 연산
[KV Cache 사용]
토큰 1 생성: K,V 계산 (토큰 0) → 캐시 저장
토큰 2 생성: 캐시(토큰 0) + K,V 계산 (토큰 1) → 캐시 업데이트
토큰 3 생성: 캐시(토큰 0,1) + K,V 계산 (토큰 2) → 캐시 업데이트
→ O(n) 연산
KV Cache 메모리 계산
KV Cache 크기 = 2 × num_layers × num_heads × head_dim × seq_len × dtype_bytes
LLaMA 3.1 8B 예시:
= 2 × 32 × 32 × 128 × 4096 × 2(FP16)
= 2,147,483,648 bytes ≈ 2 GB (시퀀스 1개당)
→ 동시 10개 요청: ~20 GB의 KV Cache 필요!
PagedAttention (vLLM)
[기존: 연속 메모리 할당]
요청 1: [████████░░░░░░░░░░] ← 최대 길이만큼 예약, 낭비 발생
요청 2: [██████░░░░░░░░░░░░]
요청 3: [메모리 부족]
[PagedAttention: 페이지 단위 할당]
요청 1: [█][█][█][█] ← 필요한 만큼만 블록 할당
요청 2: [█][█][█]
요청 3: [█][█] ← 남은 블록 활용!
→ 메모리 낭비 60~80% 감소
→ 동시 처리 가능 요청 수 2~4배 증가
MQA / GQA (Multi-Query / Grouped-Query Attention)
KV Cache 크기를 줄이는 아키텍처 수준의 최적화:
| 방식 | KV 헤드 수 | Cache 크기 | 적용 모델 |
|---|---|---|---|
| MHA (Multi-Head) | Q=K=V 동일 | 기준 | GPT-3 |
| MQA (Multi-Query) | K=V=1 | 1/32 | PaLM, Falcon |
| GQA (Grouped-Query) | K=V 그룹 | 1/4~1/8 | LLaMA 3, Gemma |
4. 추측적 디코딩 (Speculative Decoding)
원리
작은 Draft 모델로 여러 토큰을 빠르게 생성하고, 큰 Target 모델로 한 번에 검증합니다.
[일반 디코딩]
Target(70B): 토큰 1 → 토큰 2 → 토큰 3 → 토큰 4 → 토큰 5
(5 스텝, 각 스텝 느림)
[추측적 디코딩]
Draft(8B): 토큰 1,2,3,4,5 빠르게 생성 (1 스텝)
Target(70B): 5개 토큰을 한 번에 검증 → 4개 수락, 1개 재생성 (1 스텝)
→ 총 2 스텝으로 4개 토큰 생성 (2.5x 가속)
vLLM에서의 사용
# 추측적 디코딩 활성화
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3.1-70B-Instruct \
--speculative-model meta-llama/Llama-3.1-8B-Instruct \
--num-speculative-tokens 5 \
--speculative-draft-tensor-parallel-size 1성능 효과
| 시나리오 | 일반 | 추측적 디코딩 | 가속비 |
|---|---|---|---|
| 코드 생성 (반복 패턴 많음) | 30 tok/s | 75 tok/s | 2.5x |
| 일반 대화 | 30 tok/s | 55 tok/s | 1.8x |
| 창작 글쓰기 (예측 어려움) | 30 tok/s | 40 tok/s | 1.3x |
참고: 예측 가능성이 높은 태스크(코드, 형식화된 출력)에서 가속 효과가 큽니다.
5. 배치 처리와 스케줄링
Continuous Batching
[Static Batching]
배치 1: [요청A(100tok), 요청B(50tok), 요청C(200tok)]
→ 가장 긴 요청(C) 완료까지 전체 대기
→ A, B 완료 후에도 GPU 유휴
[Continuous Batching]
시점 1: [A, B, C] 동시 처리
시점 2: B 완료 → D 즉시 추가 [A, D, C]
시점 3: A 완료 → E 즉시 추가 [E, D, C]
→ GPU 유휴 시간 최소화
처리량 최적화 설정
# vLLM 최적화 설정
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3.1-8B-Instruct \
--max-num-seqs 256 \ # 최대 동시 시퀀스
--max-num-batched-tokens 8192 \ # 배치당 최대 토큰
--gpu-memory-utilization 0.9 \ # GPU 메모리 활용률
--enable-chunked-prefill \ # 청크 프리필 활성화
--max-model-len 40966. 추가 최적화 기법
FlashAttention
Attention 연산의 메모리 접근 패턴을 최적화하여 속도를 향상시킵니다.
| 버전 | 속도 향상 | 메모리 절감 | 지원 GPU |
|---|---|---|---|
| FlashAttention-1 | 2~4x | O(N) → O(√N) | A100+ |
| FlashAttention-2 | 5~9x (FP16) | 동일 | A100+ |
| FlashAttention-3 | 1.5~2x (추가) | FP8 지원 | H100 |
Prefix Caching
동일한 시스템 프롬프트를 공유하는 요청에서 프리픽스 KV Cache를 재사용합니다.
요청 1: [시스템 프롬프트 (공통)] + [사용자 질문 A]
요청 2: [시스템 프롬프트 (공통)] + [사용자 질문 B]
요청 3: [시스템 프롬프트 (공통)] + [사용자 질문 C]
→ 시스템 프롬프트의 KV Cache를 1번만 계산, 3번 재사용
→ TTFT 50~80% 감소 (시스템 프롬프트가 긴 경우)
# vLLM에서 Prefix Caching 활성화
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3.1-8B-Instruct \
--enable-prefix-caching텐서 병렬 (Tensor Parallelism)
# 4개 GPU로 70B 모델 실행
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3.1-70B-Instruct \
--tensor-parallel-size 4| 병렬 전략 | 분할 대상 | 적합 상황 |
|---|---|---|
| Tensor Parallel | 레이어 내부 (가중치) | 단일 노드 멀티 GPU |
| Pipeline Parallel | 레이어 간 (깊이) | 멀티 노드 |
| Data Parallel | 요청 (복제) | 동일 모델 N개 인스턴스 |
7. 최적화 전략 요약
시나리오별 최적화 가이드
| 목표 | 핵심 기법 | 기대 효과 |
|---|---|---|
| 모델 메모리 절감 | 양자화 (AWQ/GGUF Q4) | 모델 크기 75% 감소 |
| 동시 처리량 증가 | PagedAttention + Continuous Batching | 처리량 2~4배 |
| 첫 토큰 속도 향상 | Prefix Caching + FlashAttention | TTFT 50~80% 감소 |
| 토큰 생성 속도 향상 | 추측적 디코딩 | TPS 1.5~2.5배 |
| 대형 모델 실행 | 텐서 병렬 | 70B+ 모델 서빙 가능 |
| 비용 절감 | 양자화 + 소형 모델 | GPU 비용 60~80% 절감 |
적용 우선순위 (권장)
1. 양자화 적용 (가장 쉽고 효과 큼)
↓
2. vLLM + Continuous Batching (서빙 엔진 전환)
↓
3. FlashAttention 활성화 (대부분 기본 적용)
↓
4. Prefix Caching (시스템 프롬프트 재사용)
↓
5. 추측적 디코딩 (대형 모델 가속)
↓
6. 텐서 병렬 (초대형 모델)
참고: 최적화 기법들은 대부분 조합하여 사용할 수 있습니다. 양자화 + PagedAttention + Continuous Batching + Prefix Caching을 함께 적용하면 최대 효과를 얻을 수 있습니다.
References
- Kwon, W. et al. (2023). "Efficient Memory Management for Large Language Model Serving with PagedAttention." SOSP
- Dao, T. (2024). "FlashAttention-2: Faster Attention with Better Parallelism and Work Partitioning." ICLR
- Leviathan, Y. et al. (2023). "Fast Inference from Transformers via Speculative Decoding." ICML
- Frantar, E. et al. (2023). "GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers." ICLR
- Lin, J. et al. (2024). "AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration." MLSys
- Ainslie, J. et al. (2023). "GQA: Training Generalized Multi-Query Transformer Models." EMNLP
— Data Dynamics 엔지니어링 팀