서빙 비용을 줄이려고 양자화를 적용했더니 perplexity는 거의 그대로인데 실제 응답 품질이 눈에 띄게 나빠지는 경험을 해본 사람이 있을 것이다. 특히 코딩이나 수학 추론처럼 정밀함이 필요한 작업에서 갑자기 엉뚱한 답이 나오기 시작할 때. 이 글은 그 상황이 왜 발생하는지 — 손실이 어느 레이어에서, 어떤 연산에서 나오는지 — 를 원리 수준으로 설명하고, W4A16·W8A8·FP8·GPTQ·AWQ를 실측 수치로 비교한다.
가중치(W)만 줄이는 것과 연산(W+A)까지 줄이는 것
LLM 추론에는 두 가지 병목이 있다. GPU 메모리 용량과 연산 처리량(compute throughput). 양자화가 어느 병목을 공략하느냐에 따라 기법이 갈리고, 이 구분을 무시하면 판단이 틀린다.
W4A16은 가중치(W)만 4비트로 압축한다. 활성값(A)은 16비트를 유지하고, 실제 행렬 곱셈은 가중치를 FP16으로 dequantize한 뒤 수행한다. Llama-3 8B 기준 BF16이 약 16 GB의 VRAM을 점유하는 것과 달리, W4A16은 약 6 GB로 내려온다. 메모리 절감은 분명하다. 그런데 compute 자체가 빨라지지는 않는다. GEMM은 그대로 FP16이기 때문이다. batch=1~4처럼 메모리 대역폭이 병목인 상황에서는 이득이 명확하지만, batch=32 이상처럼 연산이 포화되는 상황에서는 dequantize overhead가 오히려 부담이 된다.
W8A8은 가중치와 활성값 모두 8비트로 처리하고, 행렬 곱셈 자체가 INT8 GEMM으로 실행된다. 하드웨어가 INT8 Tensor Core를 지원하면 BF16 대비 연산 처리량이 실제로 올라간다. 메모리는 BF16 절반인 약 8 GB다. 단, "INT8 GEMM이 실제로 빠른지"는 하드웨어와 행렬 크기에 달려 있다 — 이 부분은 뒤에서 다시 다룬다.
FP8은 W8A8의 부동소수점 버전이다. NVIDIA가 E4M3(4비트 지수, 3비트 가수)과 E5M2(5비트 지수, 2비트 가수) 포맷을 제안했고, H100(Hopper)과 Ada Lovelace(RTX 4090 계열)부터 native FP8 Tensor Core를 지원한다. 정수형 INT8과 달리 outlier 값을 넓은 dynamic range에서 그대로 표현하므로, 정확도 손실이 INT8보다 훨씬 작다.
이 세 가지를 같은 트레이드오프 선 위에 놓고 비교하면 판단이 어긋난다. W4A16은 메모리 병목 해소 도구고, W8A8/FP8은 연산 처리량 향상 도구다.
손실이 균등하지 않다: 레이어별 민감도
양자화 오차가 모든 레이어에 고르게 퍼지면 perplexity로 충분히 측정된다. 실제로는 몇몇 지점에 집중된다.
가장 취약한 곳은 outlier 활성값이 집중된 채널이다. Dettmers et al. (2022)는 6B 파라미터 이상의 LLM에서 특정 hidden dimension에 magnitude가 극단적으로 큰 활성값(emergent outliers)이 나타난다는 걸 관찰했다. 이 채널을 INT8로 그냥 clamp하면 해당 채널의 정보가 통째로 사라진다. 128개 채널 중 5~6개만 이렇게 망가져도 downstream task에서는 크게 떨어진다. perplexity는 조금 오르는데 GSM8K나 HumanEval 같은 추론·코딩 벤치마크에서 훨씬 큰 폭으로 손실이 나오는 이유가 여기 있다. perplexity가 실제 손실을 과소평가하는 정확히 그 경우다.
Attention의 Q/K projection도 취약하다. positional information과 token 간 유사도를 계산하는 핵심 레이어여서, 여기서 오차가 생기면 긴 컨텍스트에서 attention 패턴이 흐트러진다. 짧은 생성 태스크에서는 드러나지 않다가 long-form reasoning이나 multi-turn 대화에서 갑자기 품질이 떨어지는 경우, Q/K projection의 양자화 오차를 먼저 확인해볼 만하다.
첫 번째와 마지막 레이어도 중간 레이어보다 민감하다. 값의 분포가 달라서 동일한 양자화 설정에서도 오차가 상대적으로 크다.
LLM.int8()은 이 문제를 mixed-precision 분해로 우회한다. 논문이 정의한 threshold를 넘는 outlier 채널은 FP16 행렬 곱셈으로 처리하고, 나머지 99.9% 이상의 값은 INT8 GEMM으로 돌린다. 정확도는 보존되지만, FP16 연산 경로가 혼재하므로 latency overhead가 생긴다. 특히 소형 모델(7~8B)에서 이 overhead가 상대적으로 눈에 띈다.
AWQ는 다른 방식으로 같은 문제를 다룬다. 활성화 크기(magnitude)를 보고 중요한 채널을 식별한 뒤, 그 채널의 스케일을 수학적 등가 변환으로 오프라인에서 조정한다. 이 내용은 GPTQ vs AWQ 비교 절에서 더 자세히 다룬다.
기법별 수치 비교: Llama-3 8B 기준
Llama-3 8B를 기준으로 각 포맷의 주요 지표를 정리했다. perplexity는 WikiText-2 기준이다.
| 포맷 | GPU 메모리 | Perplexity (WikiText-2) | 비고 |
|---|---|---|---|
| BF16 | ~16 GB | 6.14 | 기준 |
| W8A8 INT8 (SmoothQuant) | ~8 GB | 6.28 | INT8 GEMM 가속 필요 |
| W4A16 (GPTQ / AWQ) | ~6 GB | 6.4~6.9 (설정·calibration 의존) | dequantize 후 FP16 GEMM |
| FP8 (W8A8-FP) | ~8 GB | ~6.15 내외 | H100 / Ada Lovelace 전용 |
FP8가 BF16 수준의 perplexity를 유지하는 건 부동소수점의 dynamic range 덕분이다. 정수 grid에 clamp하지 않고 지수부를 활용해 outlier 값을 그대로 표현한다. Red Hat이 Llama 3.1 시리즈 8B/70B/405B를 대상으로 진행한 대규모 실험에서도 FP8 포맷은 OpenLLM Leaderboard 평균 기준 원본 점수의 99% 이상을 회복했다.
W4A16(GPTQ/AWQ)의 perplexity 범위가 넓은 건 group size와 calibration 데이터에 따라 품질이 달라지기 때문이다. group=128이 일반적인 설정이고, 이 경우 대부분 6.5 안팎을 찍는다.
throughput 쪽에서는, Mistral 7B를 FP8로 H100에서 서빙했을 때 FP16 대비 output tokens/s 기준 약 33% 향상, TTFT 8.5% 감소라는 측정치가 있다. VRAM도 16 GB에서 7 GB로 줄었다. 이 수준의 정확도 보존과 속도 향상이면, H100 장비가 있을 때 FP8은 사실상 기본 선택지다.
GPTQ vs AWQ: 같은 W4인데 품질이 갈리는 이유
GPTQ는 Hessian 행렬을 근사해 양자화 오차를 보정한다. 각 가중치를 4비트로 양자화할 때 오차를 나머지 가중치에 전파해, 레이어 단위로 전체 오차가 최소가 되도록 조율하는 방식이다. 175B 파라미터 모델도 A100에서 약 4시간 안에 양자화할 수 있을 만큼 효율적이고, 당시 W4 기준 SOTA였다.
이 Hessian 계산이 calibration 데이터의 활성화 분포에 묶인다는 게 문제다. c4나 wikitext 같은 일반 텍스트로 calibration하면 일반 추론에서는 잘 동작한다. 그런데 특화 도메인(코드, 수학, 의료 등)으로 서빙하면 calibration 분포와 실서빙 분포 간 불일치가 오차 보정의 방향을 틀리게 만든다. 수학 텍스트로 calibration하면 GSM8K 성능이 오르는 반면, 같은 모델이 HumanEval에서는 기본 calibration 대비 떨어지는 현상이 보고된다. 오차를 줄이려고 최적화한 게 다른 도메인 능력을 해치는 역효과다.
AWQ는 Hessian 없이 활성화 크기(magnitude)를 보고 중요한 채널을 식별한다. 그 채널의 스케일을 수학적 등가 변환으로 오프라인에서 조정해, 양자화 후에도 중요한 채널의 실효 정밀도가 유지되도록 만든다. 역전파가 없으니 calibration 도메인에 과적합될 구조적 위험이 낮다. 실제 벤치마크에서 AWQ가 GPTQ 대비 전반적으로 1~2% 높은 점수를 보이고, vLLM·SGLang의 INT4 행렬 곱셈 커널과의 궁합도 AWQ 쪽이 낫다.
calibration 데이터를 실서빙 도메인에 정밀하게 맞추면 GPTQ가 특정 태스크에서 AWQ를 앞서기도 한다. 다만 일반적인 사용 패턴 — calibration 데이터를 c4로 쓰고 다양한 도메인에 서빙하는 상황 — 에서는 AWQ가 더 안전한 선택이다.
하드웨어 지원이 실제 속도를 결정한다
같은 W8A8 설정도 하드웨어에 따라 빠를 수도, 느릴 수도 있다.
H100(Hopper)은 FP8 Tensor Core와 INT8 GEMM을 모두 네이티브로 지원한다. FP8 W8A8은 이론적으로 BF16 대비 2배의 FLOPS를 쓸 수 있고, 실측에서도 33% 이상의 throughput 향상이 나온다.
A100은 다르다. INT8 GEMM(cuBLAS)은 지원하지만 FP8 Tensor Core는 없다. FP8 모델을 A100에서 돌리면 vLLM이 내부적으로 BF16으로 업캐스팅해서 연산하므로, FP8의 속도 이점이 전혀 없고 캐스팅 overhead로 오히려 느려질 수 있다. W8A8 INT8을 A100에서 돌릴 때도 주의가 필요하다. cuBLAS INT8 GEMM이 특정 행렬 크기와 배치 구성에 최적화되지 않으면 FP16 GEMM보다 느린 경우가 생긴다. A100에서 W4A16(AWQ)이 W8A8보다 throughput이 나은 케이스가 관찰되는 건 이 때문이다 — dequantize overhead보다 메모리 대역폭 절감 효과가 더 크다.
RTX 4090(Ada Lovelace)은 FP8 Tensor Core가 있어 기술적으로 FP8을 지원한다. 다만 VRAM이 24 GB라서, Llama-3 70B는 FP8(~35 GB)이어도 단일 GPU에는 올라가지 않는다. 8B 모델은 FP8(~7 GB)으로 올라가므로 4090에서 8B 서빙이라면 FP8이 유효하다. RTX 3090(Ampere)은 FP8을 지원하지 않아 W4A16이 현실적 최선이다.
어떤 양자화를 고르는가
GPU 세대와 배치 크기를 기준으로 한 선택 가이드다.
| GPU | batch 1~4 | batch 8~32 | 정확도 우선 |
|---|---|---|---|
| H100 | FP8 | FP8 | FP8 또는 BF16 |
| A100 | W4A16 AWQ | W8A8 INT8 (성능 검증 필수) | BF16 |
| RTX 4090 | FP8 (8B) 또는 W4A16 AWQ | FP8 (8B) 또는 W4A16 AWQ | FP8 (8B 기준) |
| RTX 3090 | W4A16 AWQ | W4A16 AWQ | BF16 |
W4A16을 compute-bound 서빙에 쓰면 BF16보다 느려질 수 있다. dequantize 단계가 GEMM 앞에 추가되는데, GEMM 자체는 FP16과 동일하기 때문이다. "무조건 INT4"라는 규칙은 메모리 병목 상황에서만 맞다.
컨텍스트가 길수록(16K 이상) KV cache 때문에 메모리 병목이 오래 유지되므로 W4A16의 이점 구간이 늘어난다. 짧은 컨텍스트 대량 배치 서빙에서는 W8A8 또는 FP8이 맞다.
FP8을 쓸 수 없는 환경에서 W4A16을 선택해야 한다면, AWQ를 기본으로 하고 calibration 데이터는 c4나 pileval 같은 도메인 중립 코퍼스를 쓰는 게 안전하다. 실서빙 도메인이 코드나 수학으로 특화되어 있다면 그 도메인 샘플로 calibration 데이터를 별도 구성하는 게 낫고, GPTQ와 AWQ 중 선택해야 한다면 calibration 도메인 미스매치에 더 강한 AWQ가 기본이다.