70B 파라미터 모델을 FP16으로 그냥 올리면 GPU 메모리가 140GB 필요해요. H100 두 개가 있어야 겨우 올라가요.
양자화(Quantization)는 이 문제를 해결해요.
FP16 (기본): 70B 모델 = 140GB VRAM → H100 2개 필요
INT8: 70B 모델 = 70GB VRAM → H100 1개로 가능
INT4 (4비트): 70B 모델 = 35GB VRAM → A100 1개로 가능
근데 양자화 방식이 너무 많아요. FP8, AWQ, GPTQ, GGUF, BitsAndBytes, MXFP4... 뭐가 뭔지 헷갈려요.
이번 글에서 각 방식이 어떻게 다르고 언제 써야 하는지 완전 정리해 드릴게요.
양자화란 무엇인가
LLM의 가중치는 수천억 개의 숫자예요. 기본적으로 FP32(32비트) 또는 FP16(16비트) 부동소수점으로 저장돼요.
FP32 가중치 예시:
0.01823740, -1.76328451, 0.00293847, ...
→ 각 숫자가 32비트 (4바이트) 차지
INT4 양자화 후:
7, 2, 8, ... (0~15 범위)
→ 각 숫자가 4비트 (0.5바이트) 차지
→ 메모리 8배 절감
당연히 정밀도를 잃으니 품질이 약간 떨어져요. 양자화 방식마다 얼마나 잃느냐, 어떤 하드웨어에서 빠르냐가 달라요.
두 가지 접근법: PTQ vs QAT
모든 양자화는 크게 두 가지로 나뉘어요.
PTQ (Post-Training Quantization, 사후 양자화):
- 훈련 완료 후 양자화
- 빠르고 쉬움
- 대부분의 방식 (GGUF, GPTQ, AWQ, FP8)
QAT (Quantization-Aware Training, 훈련 인식 양자화):
- 훈련 중 양자화 시뮬레이션
- 품질 손실 최소화
- 비용 높음 (재훈련 필요)
- BitNet 등
실제로 거의 모든 경우 PTQ를 써요. 이미 훈련된 오픈소스 모델을 그대로 양자화하니까요.
FP8 — 신세대 GPU를 위한 양자화
개념
16비트 부동소수점(FP16/BF16)을 8비트 부동소수점(FP8)으로 줄여요. 정수가 아닌 부동소수점 방식이라 품질 손실이 매우 적어요.
FP16: [1비트 부호] [5비트 지수] [10비트 가수] = 16비트
FP8: [1비트 부호] [4비트 지수] [3비트 가수] = 8비트 (e4m3)
또는
[1비트 부호] [5비트 지수] [2비트 가수] = 8비트 (e5m2)
e4m3은 정밀도(가수 비트) 우선, e5m2는 범위(지수 비트) 우선이에요.
특징
✅ 품질 손실 최소 (FP16 대비 ~0.5% 하락)
✅ 메모리 50% 절감
✅ H100/A100에서 하드웨어 가속 지원
✅ SGLang, vLLM, TensorRT-LLM 기본 지원
❌ H100, A100, Ada Lovelace 이상 GPU 필요
❌ 구형 GPU (RTX 3090 이하)에서 속도 이점 없음
언제 쓰나
서버급 GPU(H100, A100)에서 프로덕션 서빙할 때의 1순위 선택이에요.
사용법
# SGLang에서 FP8
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.3-70B-Instruct \
--quantization fp8 \
--dtype float16
# vLLM에서 FP8
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3.3-70B-Instruct \
--quantization fp8
# 이미 FP8으로 저장된 모델은 그냥 로드
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-70B-Instruct-FP8
# 별도 --quantization 필요 없음
# HuggingFace에서 직접 FP8 양자화
from transformers import AutoModelForCausalLM
import torch
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B-Instruct",
torch_dtype=torch.float8_e4m3fn, # FP8 로드
device_map="auto"
)
FP8 KV 캐시 (추가 메모리 절감)
# KV 캐시도 FP8으로 저장 (기본 FP16 대비 KV 메모리 50% 절감)
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-70B-Instruct \
--kv-cache-dtype fp8_e4m3
AWQ — GPU 서빙의 현재 최강자
개념
MIT에서 개발한 방식이에요. 핵심 인사이트가 있어요.
"전체 가중치의 1% 미만이 모델 출력의 대부분을 결정한다."
일반 양자화:
모든 가중치를 균일하게 4비트로 줄임
→ 중요한 가중치도 품질 손실
AWQ (Activation-Aware Weight Quantization):
1. 캘리브레이션 데이터로 실제 추론 시 활성화 패턴 분석
2. 중요한 가중치("salient weights") 식별
3. 중요 가중치는 보호 (높은 비트 유지 또는 스케일링)
4. 나머지는 4비트로 압축
→ 품질 손실 최소화
특징
✅ INT4 중 최고 품질 (FP16 대비 95% 유지)
✅ Marlin 커널과 함께 기본 FP16보다 빠름 (741 tok/s vs 461 tok/s)
✅ vLLM, SGLang, TGI 지원
✅ NVIDIA, Intel GPU 지원
❌ CPU 서빙 불가 (GGUF보다 호환성 낮음)
❌ 캘리브레이션 데이터 필요
❌ 양자화 과정이 GPTQ보다 느림
Marlin 커널이 핵심
AWQ만으로는 오히려 FP16보다 느릴 수 있어요. Marlin 커널을 같이 써야 빨라요.
AWQ 단독: 67 tok/s ← FP16(461)보다 느림!
AWQ + Marlin: 741 tok/s ← FP16보다 1.6배 빠름
vLLM과 SGLang은 자동으로 Marlin 커널을 사용해요.
사용법
# AutoAWQ로 직접 양자화
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer
model_path = "meta-llama/Llama-3.1-8B-Instruct"
quant_path = "llama-3.1-8b-awq-4bit"
# 캘리브레이션 데이터 준비
quant_config = {
"zero_point": True,
"q_group_size": 128,
"w_bit": 4, # 4비트
"version": "GEMM"
}
model = AutoAWQForCausalLM.from_pretrained(model_path)
tokenizer = AutoTokenizer.from_pretrained(model_path)
# 양자화 실행 (캘리브레이션 포함)
model.quantize(tokenizer, quant_config=quant_config)
model.save_quantized(quant_path)
tokenizer.save_pretrained(quant_path)
# 저장된 AWQ 모델 로드
from awq import AutoAWQForCausalLM
model = AutoAWQForCausalLM.from_quantized(
quant_path,
fuse_layers=True # Marlin 커널 자동 활성화
)
# SGLang에서 AWQ 서빙
python -m sglang.launch_server \
--model-path TheBloke/Llama-2-70B-AWQ \
--quantization awq \
--dtype half # AWQ는 float16 권장
# vLLM에서 AWQ 서빙
python -m vllm.entrypoints.openai.api_server \
--model TheBloke/Llama-2-70B-AWQ \
--quantization awq
GPTQ — 검증된 GPU 양자화의 고전
개념
LLM을 4비트로 압축한 최초의 실용적 방법이에요. **헤시안 행렬(Hessian matrix)**을 이용해 각 레이어의 중요도를 분석하고 양자화 오류를 최소화해요.
GPTQ 동작 방식:
1. 레이어별로 순서대로 양자화
2. 각 가중치를 양자화할 때 헤시안 정보 활용
3. 이미 양자화된 가중치의 오류를 남은 가중치로 보상
4. 레이어 전체 오류를 최소화
→ 수학적으로 최적화된 양자화 오류 분포
특징
✅ 4비트 INT4 중 수학적으로 검증된 방식
✅ 사전 양자화 모델 풍부 (TheBloke 등 커뮤니티)
✅ ExLlamaV2 커널로 빠른 추론 (712 tok/s)
✅ vLLM, SGLang, Transformers 지원
❌ AWQ보다 품질 약간 낮음 (90% vs 95%)
❌ 캘리브레이션 오래 걸림
❌ 커널 없으면 FP16보다 느림 (276 tok/s)
사용법
# GPTQModel로 직접 양자화 (AutoGPTQ 후속)
from gptqmodel import GPTQModel, QuantizeConfig
model_id = "meta-llama/Llama-3.1-8B-Instruct"
# 양자화 설정
quant_config = QuantizeConfig(
bits=4, # 4비트
group_size=128, # 그룹 크기 (클수록 품질 좋음)
desc_act=False # True면 품질 높지만 속도 느림
)
# 캘리브레이션 데이터
calibration_data = [
"파이썬으로 피보나치 수열을 구현하는 방법은?",
"머신러닝과 딥러닝의 차이는?",
# ... 최소 128개 권장
]
# 모델 로드 및 양자화
model = GPTQModel.from_pretrained(model_id, quant_config)
model.quantize(calibration_data)
model.save_quantized("llama-3.1-8b-gptq-4bit")
# 저장된 GPTQ 모델 로드
from transformers import AutoModelForCausalLM
import torch
model = AutoModelForCausalLM.from_pretrained(
"TheBloke/Llama-2-70B-GPTQ",
device_map="auto",
torch_dtype=torch.float16
)
# SGLang에서 GPTQ 서빙
python -m sglang.launch_server \
--model-path TheBloke/Llama-2-70B-GPTQ \
--quantization gptq
# Marlin 커널 활성화 (속도 2.6배 향상)
python -m sglang.launch_server \
--model-path TheBloke/Llama-2-70B-GPTQ \
--quantization gptq_marlin
GGUF — CPU/로컬 환경의 표준
개념
llama.cpp 팀이 만든 파일 포맷이에요. 중요한 점은 GGUF는 양자화 알고리즘이 아니라 파일 포맷이에요.
GGUF = 파일 포맷 (컨테이너)
내부에 다양한 양자화 방식 담음:
- Q4_0, Q4_K_M, Q5_K_M (선형 양자화)
- IQ2_XXS, IQ3_S (importance matrix 기반)
K-Quant 표기법 이해
Q4_K_M:
Q = Quantization (양자화)
4 = 4비트
K = K-Quant (혼합 정밀도, 레이어별 다른 비트 수)
M = Medium (S=Small, L=Large, XL=Extra Large)
실제 동작:
중요한 어텐션 레이어 → 더 높은 비트 수 사용
덜 중요한 피드포워드 레이어 → 낮은 비트 수 사용
→ 품질과 크기의 균형점 찾기
GGUF 레벨별 특성
레벨 비트 크기 (7B) 품질 권장 용도
| Q2_K | 2비트 | ~3GB | 낮음 | RAM 2GB 이하 극한 환경 |
| Q3_K_M | 3비트 | ~4GB | 보통 | RAM 4GB 환경 |
| Q4_K_M | 4비트 | ~5GB | 양호 (92%) | 범용 권장 |
| Q5_K_M | 5비트 | ~6GB | 좋음 (95%) | 품질 중시 로컬 |
| Q6_K | 6비트 | ~7GB | 매우 좋음 | RAM 넉넉한 환경 |
| Q8_0 | 8비트 | ~9GB | FP16 근접 | 최고 품질 로컬 |
특징
✅ CPU에서도 실행 가능 (llama.cpp, Ollama)
✅ Apple Silicon(M1/M2/M3) 완벽 지원
✅ 윈도우/맥/리눅스 크로스 플랫폼
✅ GPU 레이어 부분 오프로드 가능 (CPU+GPU 혼합)
✅ 사전 양자화 모델 가장 풍부
❌ GPU 전용 양자화(AWQ, GPTQ)보다 GPU 처리량 낮음
❌ vLLM/SGLang에서 GGUF는 TTFT 높음 (958ms vs AWQ 183ms)
사용법
# llama.cpp로 GGUF 양자화
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make
# FP16 → GGUF 변환
python convert_hf_to_gguf.py \
meta-llama/Llama-3.1-8B-Instruct \
--outtype f16
# GGUF → 양자화
./llama-quantize \
llama-3.1-8b-f16.gguf \
llama-3.1-8b-q4_k_m.gguf \
Q4_K_M
# Ollama로 GGUF 서빙
ollama run llama3.1
# llama.cpp 서버로 직접 서빙
./llama-server \
-m llama-3.1-8b-q4_k_m.gguf \
--host 0.0.0.0 \
--port 8080 \
-ngl 99 # GPU로 오프로드할 레이어 수 (99 = 전체)
# Python에서 GGUF 로드 (llama-cpp-python)
from llama_cpp import Llama
llm = Llama(
model_path="./llama-3.1-8b-q4_k_m.gguf",
n_gpu_layers=-1, # 모든 레이어 GPU로
n_ctx=4096, # 컨텍스트 길이
verbose=False
)
response = llm.create_chat_completion(
messages=[{"role": "user", "content": "안녕하세요"}]
)
print(response["choices"][0]["message"]["content"])
BitsAndBytes — 파인튜닝의 유일한 선택
개념
HuggingFace와 함께 개발된 양자화 라이브러리예요. **QLoRA(파인튜닝)**에 필수예요.
INT8 (LLM.int8()):
- 8비트 양자화
- 아웃라이어 처리 특화
- 품질 손실 거의 없음
NF4 (4비트 Normal Float):
- QLoRA에 사용
- 정규분포에 최적화된 4비트
- 파인튜닝 시 원래 FP16 성능 근접
특징
✅ QLoRA 파인튜닝 유일한 지원
✅ 코드 한 줄로 적용 가능
✅ HuggingFace 완벽 통합
❌ 추론 속도 느림 (168 tok/s)
❌ 프로덕션 서빙보다 연구/파인튜닝용
사용법
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
import torch
# 4비트 NF4 로드
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4", # NF4 양자화
bnb_4bit_compute_dtype=torch.bfloat16, # 연산은 BF16
bnb_4bit_use_double_quant=True # Double quantization (추가 메모리 절감)
)
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B-Instruct",
quantization_config=bnb_config,
device_map="auto"
)
# QLoRA 파인튜닝
from peft import prepare_model_for_kbit_training, LoraConfig, get_peft_model
model = prepare_model_for_kbit_training(model)
lora_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
MXFP4 / FP4 — 차세대 양자화 (Blackwell 전용)
NVIDIA Blackwell (B200, GB200) GPU에서만 사용 가능한 최신 방식이에요.
# SGLang에서 MXFP4 (GB200 전용)
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-70B-Instruct \
--quantization mxfp4
# TensorRT-LLM에서 FP4
python -m tensorrt_llm.build \
--model-path meta-llama/Llama-3.1-70B-Instruct \
--dtype float4
FP8 대비 메모리를 추가로 50% 절감하지만 아직 Blackwell GPU에서만 지원돼요.
실측 벤치마크 (vLLM, H100, Qwen2.5-32B 기준)
방식 처리량 (tok/s) 품질 유지율 메모리 절감
| FP16 기준 | 461 | 100% | 0% |
| FP8 | ~800 | ~99.5% | 50% |
| AWQ + Marlin | 741 | 95% | 75% |
| GPTQ + Marlin | 712 | 90% | 75% |
| BitsAndBytes | 168 | 97% | 75% |
| GGUF Q4_K_M | 93 (vLLM) | 92% | 75% |
GGUF는 vLLM/SGLang보다 llama.cpp/Ollama에서 훨씬 빠름. 위 수치는 GPU 서버 기준.
어떤 걸 써야 하나 — 상황별 선택 가이드
H100/A100 프로덕션 서버
→ FP8 (최고 품질, 속도, 메모리 균형)
→ 또는 AWQ + Marlin (더 많은 동시 요청 처리)
RTX 4090/3090 등 컨슈머 GPU 서버
→ AWQ (최고 품질 + 속도)
→ 또는 GPTQ + Marlin (처리량 비슷, 더 많은 사전 양자화 모델)
로컬 PC/맥 (Ollama, LM Studio)
→ GGUF Q4_K_M (범용 최고 선택)
→ Apple Silicon: GGUF Q4_K_M 또는 MLX
파인튜닝 (QLoRA)
→ BitsAndBytes NF4 (유일한 선택)
극한 메모리 절약 (GPU 없음)
→ GGUF Q2_K 또는 Q3_K_M
방식별 비교 한눈에 보기
FP8 AWQ GPTQ GGUF BitsAndBytes
| 비트 수 | 8비트 | 4비트 | 4비트 | 2~8비트 | 4/8비트 |
| 품질 | ★★★★★ | ★★★★☆ | ★★★★☆ | ★★★★☆ | ★★★★★ |
| GPU 속도 | 최고 | 매우 빠름 | 빠름 | 느림 | 보통 |
| CPU 지원 | ❌ | ❌ | ❌ | ✅ | ❌ |
| 파인튜닝 | ❌ | ❌ | ❌ | ❌ | ✅ |
| 필요 GPU | H100/A100 | 모든 CUDA | 모든 CUDA | CPU OK | 모든 CUDA |
| 추천 사용처 | 프로덕션 서버 | GPU 서빙 | GPU 서빙 | 로컬/엣지 | QLoRA |
직접 양자화 vs 사전 양자화 모델 사용
대부분의 경우 직접 양자화할 필요 없어요. HuggingFace에 이미 양자화된 모델이 많아요.
# 사전 양자화 모델 검색
# GGUF: TheBloke/*, bartowski/*
# AWQ: TheBloke/*-AWQ, 모델명-AWQ
# GPTQ: TheBloke/*-GPTQ, 모델명-GPTQ
# FP8: 모델명-FP8 (공식 제공 증가 중)
# 예시
TheBloke/Llama-2-70B-GPTQ
TheBloke/Llama-2-70B-AWQ
TheBloke/Llama-2-70B-GGUF
meta-llama/Llama-3.1-70B-Instruct-FP8 # 공식 FP8
직접 양자화해야 할 때
- 파인튜닝한 커스텀 모델
- 사전 양자화 모델이 없는 최신 모델
- 특정 캘리브레이션 데이터로 품질 최적화할 때
마무리
양자화 선택을 한 줄로 정리하면 이래요.
서버 (H100/A100) → FP8
서버 (RTX 4090) → AWQ
로컬/Mac → GGUF Q4_K_M
파인튜닝 → BitsAndBytes
양자화에서 가장 중요한 건 알고리즘보다 커널이에요. AWQ가 아무리 좋아도 Marlin 커널 없이는 FP16보다 느려요. vLLM, SGLang 같은 최적화된 서빙 엔진을 쓰면 자동으로 최적 커널이 선택돼요. 😄
'LLM' 카테고리의 다른 글
| LLM 지식 증류(Knowledge Distillation) 완전 정리 — 큰 모델의 지식을 작은 모델에 이식하는 법 (0) | 2026.04.09 |
|---|---|
| LoRA / QLoRA 완전 가이드 — LLM 파인튜닝을 저렴하게 하는 법 (0) | 2026.04.09 |
| SGLang PD 분리 배포 완전 가이드 — Prefill/Decode 분리로 처리량 5배 올리기 (0) | 2026.04.09 |
| SGLang launch_server 파라미터 완전 정리 (0) | 2026.04.09 |
| SGLang 서빙에 대한 모든 것 — 설치부터 프로덕션까지 완전 가이드 (0) | 2026.04.09 |