LLM Quantization¶
개요¶
양자화(Quantization)는 모델의 가중치와 활성화를 더 낮은 비트 정밀도로 표현하여 메모리 사용량과 추론 속도를 개선하는 기법이다. FP32나 FP16 대신 INT8, INT4 등을 사용하여 모델 크기를 2-8배 줄일 수 있다.
핵심 개념¶
양자화 기본 원리¶
여기서: - x: 원본 FP32/FP16 값 - x_q: 양자화된 INT 값 - scale: 스케일링 팩터 - zero_point: 영점 오프셋
양자화 유형¶
| 유형 | 설명 | 예시 |
|---|---|---|
| Weight-only | 가중치만 양자화 | GPTQ, AWQ, GGUF |
| Dynamic | 추론 시 활성화 동적 양자화 | PyTorch Dynamic Quant |
| Static | 캘리브레이션 후 고정 양자화 | TensorRT |
| QAT | 학습 중 양자화 | LLM-QAT |
그룹 양자화 (Group Quantization)¶
Per-tensor: 전체 텐서에 단일 scale/zero_point
Per-channel: 채널별 scale/zero_point
Per-group: 그룹(예: 128개)별 scale/zero_point
Precision vs Efficiency tradeoff:
Per-tensor < Per-channel < Per-group (in terms of accuracy)
Per-tensor > Per-channel > Per-group (in terms of efficiency)
아키텍처 다이어그램¶
Weight-only Quantization 흐름¶
Original Model (FP16)
|
v
+------------------+
| Calibration Data |
| (for AWQ/GPTQ) |
+--------+---------+
|
v
+------------------+
| Quantization |
| Algorithm |
| (GPTQ/AWQ/etc) |
+--------+---------+
|
v
+------------------+
| Quantized Model |
| (INT4/INT8) |
+--------+---------+
|
v
+------------------+
| Inference |
| (Dequant on fly) |
+------------------+
GPTQ 알고리즘 흐름¶
Weight Matrix W
|
v
+---------------------+
| Compute Hessian H |
| H = X^T X |
| (from calibration) |
+----------+----------+
|
v
+---------------------+
| For each column i: |
| |
| 1. Quantize w_i |
| q_i = round(w_i) |
| |
| 2. Compute error |
| e = w_i - q_i |
| |
| 3. Update remaining |
| W[:,i+1:] -= |
| e * H[i,i+1:]/ |
| H[i,i] |
+---------------------+
|
v
Quantized Weight Q
AWQ (Activation-aware Weight Quantization)¶
Calibration Data
|
v
+---------------+
| Run Forward |
| Collect Acts |
+-------+-------+
|
v
+---------------+
| Find Salient |
| Channels |
| (high act mag)|
+-------+-------+
|
v
+---------------+
| Scale Salient |
| Weights Up |
| (protect them)|
+-------+-------+
|
v
+---------------+
| Quantize |
| All Weights |
+-------+-------+
|
v
+---------------+
| Scale Back |
| During Infer |
+---------------+
GGUF 파일 구조¶
+----------------------------------+
| GGUF Header |
+----------------------------------+
| Magic Number: "GGUF" |
| Version: 3 |
| Tensor Count |
| Metadata KV Count |
+----------------------------------+
| Metadata |
+----------------------------------+
| general.architecture: "llama" |
| general.name: "Llama-3-8B" |
| llama.context_length: 8192 |
| llama.embedding_length: 4096 |
| ... |
+----------------------------------+
| Tensor Info |
+----------------------------------+
| token_embd.weight: Q4_K_M |
| blk.0.attn_q.weight: Q4_K_M |
| blk.0.attn_k.weight: Q4_K_M |
| ... |
+----------------------------------+
| Tensor Data |
+----------------------------------+
| [Quantized weight bytes] |
| [...] |
+----------------------------------+
K-Quants 구조 (GGUF)¶
Q4_K_M Block (32 weights per block)
+------------------------------------------+
| Scales (6 bits x 8 = 48 bits = 6 bytes) |
+------------------------------------------+
| Mins (6 bits x 8 = 48 bits = 6 bytes) |
+------------------------------------------+
| Weights (4 bits x 32 = 128 bits=16 bytes)|
+------------------------------------------+
Total: 28 bytes for 32 weights = 7 bits per weight
Dequantization:
w[i] = (quantized[i] * scale[group] + min[group])
주요 양자화 기법 비교¶
GPTQ vs AWQ vs GGUF¶
+----------+----------------+----------------+----------------+
| 특성 | GPTQ | AWQ | GGUF |
+----------+----------------+----------------+----------------+
| 방식 | OBQ 기반 | Activation | K-quant |
| | 2차 정보 활용 | aware scaling | 블록 양자화 |
+----------+----------------+----------------+----------------+
| 정밀도 | 높음 | 매우 높음 | 좋음 |
+----------+----------------+----------------+----------------+
| 속도 | 중간 | 빠름 | 매우 빠름 |
| | (양자화 시간) | | (CPU 최적화) |
+----------+----------------+----------------+----------------+
| 하드웨어 | GPU 필요 | GPU 필요 | CPU/GPU 모두 |
+----------+----------------+----------------+----------------+
| 사용처 | GPU 추론 | GPU 추론 | CPU/Edge |
| | (vLLM, TGI) | (vLLM 권장) | (llama.cpp) |
+----------+----------------+----------------+----------------+
비트별 품질/크기 비교¶
Model Quality vs Size Tradeoff
|Quality
|
| * FP16 (100%)
|
| * INT8 (99.5%)
|
| * Q8_0 (99%)
|
| * Q6_K (98.5%)
|
| * Q5_K_M (97%)
|
| * Q4_K_M (95%)
|
| * Q4_0 (93%)
|
| * Q3_K_M (90%)
|
| * Q2_K (85%)
|
+---------------------------------> Size Reduction
1x 2x 3x 4x 5x 6x
대표 양자화 모델¶
| 원본 모델 | 양자화 | 크기 | VRAM 필요 |
|---|---|---|---|
| Llama-3-70B | FP16 | 140GB | ~150GB |
| Llama-3-70B | Q8_0 | 70GB | ~75GB |
| Llama-3-70B | Q4_K_M | 40GB | ~45GB |
| Llama-3-8B | FP16 | 16GB | ~18GB |
| Llama-3-8B | Q4_K_M | 4.7GB | ~6GB |
| Llama-3-8B | Q3_K_M | 3.9GB | ~5GB |
장단점¶
GPTQ¶
장점: - 높은 정확도 유지 - GPU 추론에 최적화 - vLLM, TGI 등 서빙 프레임워크 지원
단점: - 양자화에 GPU 및 캘리브레이션 데이터 필요 - 양자화 시간이 오래 걸림 - CPU 추론 지원 제한
AWQ¶
장점: - GPTQ보다 높은 정확도 (특히 instruction-tuned 모델) - 빠른 양자화 속도 - vLLM 권장 포맷
단점: - GPU 필요 - GPTQ보다 생태계가 작음 (하지만 빠르게 성장 중)
GGUF¶
장점: - CPU 추론 최적화 (llama.cpp) - 다양한 양자화 레벨 (Q2~Q8) - 플랫폼 독립적 (Windows, Mac, Linux) - 부분 GPU 오프로딩 지원
단점: - 순수 GPU 추론은 GPTQ/AWQ보다 느릴 수 있음 - 서빙 프레임워크 지원 제한 (주로 llama.cpp)
코드 예시¶
GPTQ 양자화 (AutoGPTQ)¶
from transformers import AutoModelForCausalLM, AutoTokenizer
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
# Load model
model_name = "meta-llama/Meta-Llama-3-8B"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.float16,
device_map="auto"
)
# Prepare calibration data
calibration_data = [
tokenizer(text, return_tensors="pt")
for text in [
"The quick brown fox jumps over the lazy dog.",
"Machine learning is a subset of artificial intelligence.",
# ... more calibration texts
]
]
# Quantization config
quantize_config = BaseQuantizeConfig(
bits=4, # 4-bit quantization
group_size=128, # Group size for quantization
desc_act=True, # Descending activation order
damp_percent=0.01, # Dampening factor
)
# Quantize
quantized_model = AutoGPTQForCausalLM.from_pretrained(
model_name,
quantize_config=quantize_config
)
quantized_model.quantize(calibration_data)
# Save
quantized_model.save_quantized("llama3-8b-gptq-4bit")
AWQ 양자화 (AutoAWQ)¶
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer
# Load model
model_path = "meta-llama/Meta-Llama-3-8B"
quant_path = "llama3-8b-awq-4bit"
model = AutoAWQForCausalLM.from_pretrained(
model_path,
device_map="auto",
safetensors=True
)
tokenizer = AutoTokenizer.from_pretrained(model_path)
# Quantization config
quant_config = {
"zero_point": True,
"q_group_size": 128,
"w_bit": 4,
"version": "GEMM"
}
# Quantize
model.quantize(
tokenizer,
quant_config=quant_config,
calib_data="pileval", # Built-in calibration dataset
)
# Save
model.save_quantized(quant_path)
tokenizer.save_pretrained(quant_path)
GGUF 변환 및 양자화 (llama.cpp)¶
# 1. Convert HuggingFace model to GGUF
python convert_hf_to_gguf.py \
./meta-llama-3-8b \
--outfile llama3-8b-f16.gguf \
--outtype f16
# 2. Quantize to different formats
./llama-quantize llama3-8b-f16.gguf llama3-8b-q4_k_m.gguf Q4_K_M
./llama-quantize llama3-8b-f16.gguf llama3-8b-q5_k_m.gguf Q5_K_M
./llama-quantize llama3-8b-f16.gguf llama3-8b-q8_0.gguf Q8_0
# 3. Run inference
./llama-cli -m llama3-8b-q4_k_m.gguf -p "Hello, world!" -n 100
vLLM으로 양자화 모델 서빙¶
from vllm import LLM, SamplingParams
# AWQ model (recommended for vLLM)
llm = LLM(
model="TheBloke/Llama-3-8B-AWQ",
quantization="awq",
dtype="half",
gpu_memory_utilization=0.90
)
# GPTQ model
llm = LLM(
model="TheBloke/Llama-3-8B-GPTQ",
quantization="gptq",
dtype="half"
)
# Generate
sampling_params = SamplingParams(
temperature=0.7,
max_tokens=256
)
outputs = llm.generate(["Hello, how are you?"], sampling_params)
GGUF K-Quant 상세¶
| 타입 | 비트/가중치 | 설명 | 권장 사용처 |
|---|---|---|---|
| Q2_K | 2.56 | 최소 크기, 낮은 품질 | 테스트용 |
| Q3_K_S | 3.41 | 작은 K-quant | 메모리 극히 제한 |
| Q3_K_M | 3.91 | 중간 K-quant | 메모리 제한 |
| Q4_0 | 4.50 | 레거시 4비트 | 호환성 필요 시 |
| Q4_K_S | 4.58 | 작은 4비트 K-quant | 균형 |
| Q4_K_M | 4.85 | 중간 4비트 K-quant | 권장 기본값 |
| Q5_K_S | 5.52 | 작은 5비트 K-quant | 높은 품질 |
| Q5_K_M | 5.69 | 중간 5비트 K-quant | 품질 우선 |
| Q6_K | 6.56 | 6비트 K-quant | 최고 품질 |
| Q8_0 | 8.50 | 8비트 | 품질 최우선 |
참고 논문 및 자료¶
- Frantar, E., et al. (2022). "GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers."
-
arXiv: https://arxiv.org/abs/2210.17323
-
Lin, J., et al. (2023). "AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration."
-
arXiv: https://arxiv.org/abs/2306.00978
-
Dettmers, T., et al. (2022). "LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale."
-
arXiv: https://arxiv.org/abs/2208.07339
-
Dettmers, T., et al. (2023). "QLoRA: Efficient Finetuning of Quantized LLMs."
-
arXiv: https://arxiv.org/abs/2305.14314
-
GGML/GGUF Documentation
- https://github.com/ggerganov/ggml
-
https://github.com/ggerganov/llama.cpp
-
AutoGPTQ
-
https://github.com/AutoGPTQ/AutoGPTQ
-
AutoAWQ
- https://github.com/casper-hansen/AutoAWQ