Weight-Only Quantization: GPTQ and AWQ
마지막 수정:
Weight-only quantization은 model weight를 낮은 bit로 저장하지만 activation은 높은 precision으로 둔다.
W4A16:
weights -> 4-bit
activations -> FP16/BF16
accumulation / output -> usually higher precision
이 방식의 핵심 이득은 weight memory와 memory bandwidth다. Activation까지 낮은 precision으로 바꾸는 W8A8이나 FP8과 달리, matmul compute 전체가 낮은 precision으로 바뀐다고 보면 안 된다.
RTN
round to nearest
- Mechanism
- weights are rounded directly
- Calibration
- none
GPTQ
Hessian error correction
- Mechanism
- rounding errors are redistributed
- Calibration
- activation Hessian
AWQ
activation-aware scaling
- Mechanism
- salient channels are protected first
- Calibration
- activation magnitude
RTN은 너무 단순하다
가장 단순한 방법은 round-to-nearest, 즉 RTN이다.
weight
-> scale로 나눔
-> 가장 가까운 integer로 반올림
-> 다시 dequantize
INT8에서는 이 단순한 방법도 꽤 잘 버틸 수 있다. 하지만 INT4에는 code가 16개뿐이다. 한 column이나 group 안에서 중요한 weight가 잘못 반올림되면 layer output이 크게 흔들릴 수 있다.
여기서 중요한 관점은 weight 자체의 MSE가 아니라 layer output의 reconstruction error다.
나쁜 질문:
W와 Q(W)가 얼마나 가까운가?
좋은 질문:
WX와 Q(W)X가 얼마나 가까운가?
같은 weight error라도 input activation이 큰 방향에서 생기면 output error가 훨씬 커진다.
GPTQ는 error를 보정한다
GPTQ는 INT4로 weight를 quantize하되, 단순히 반올림하고 끝내지 않는다.
Calibration activation X를 모아 layer output이 어떤 방향에 민감한지 본다.
H = X X^T
여기서 H는 Hessian에 해당하는 sensitivity map이다. 어떤 input dimension이 layer output에 크게 영향을 주는지 알려준다.
GPTQ의 흐름은 이렇다.
1. calibration activation 수집
2. Hessian 계산
3. weight column을 순서대로 quantize
4. 생긴 rounding error를 남은 column에 보정해서 전파
5. group-wise INT4 weight로 저장
핵심은 “이미 생긴 rounding error를 무시하지 않는다”는 점이다. 어떤 column을 quantize하며 생긴 오차를 Hessian 정보에 따라 다음 column들에 분산시킨다.
그래서 GPTQ는 좁은 domain에서 calibration data가 deployment와 잘 맞을 때 강하다. 특히 4-bit 이하처럼 grid가 거칠수록 error compensation의 가치가 커진다.
AWQ는 중요한 channel을 먼저 보호한다
AWQ는 다른 질문을 던진다.
error가 생긴 뒤 보정할 것인가?
아니면 중요한 channel에서 error가 덜 생기게 만들 것인가?
AWQ의 핵심 관찰은 이것이다.
weight magnitude가 큰 channel이 중요한 것이 아니다.
activation magnitude가 큰 channel이 중요하다.
Linear layer는 y = Wx다. 어떤 weight column이 작아도, 그 column과 곱해지는 activation이 크면 output contribution은 클 수 있다.
그래서 AWQ는 calibration data에서 activation magnitude를 보고 중요한 channel을 찾는다. 그런 다음 quantization 전에 그 weight channel을 scale up한다.
salient channel
-> weight column scale up
-> quantization grid에서 더 잘 살아남음
-> inverse scaling은 LayerNorm 등에 fold
수학적으로는 layer output을 바꾸지 않는 equivalent transformation이다.
W x = (W diag(s)) (diag(s)^-1 x)
실제 inference에서는 inverse scaling을 앞단 LayerNorm gain에 흡수할 수 있다. 그래서 AWQ는 quantization 후 runtime overhead 없이 표준 INT4 weight model처럼 실행될 수 있다.
GPTQ와 AWQ는 같은 저장 형식, 다른 선택 방식이다
둘 다 보통 다음 형태로 배포된다.
INT4 weights
group size 128
FP16/BF16 activations
하지만 quantized value를 고르는 방식이 다르다.
GPTQ:
Hessian으로 quantization error를 보정한다.
AWQ:
activation이 큰 channel을 quantize 전에 보호한다.
GPTQ는 layer별 reconstruction problem을 더 직접적으로 최적화한다. 대신 Hessian 계산과 column-wise compensation이 필요하고, calibration data에 더 붙을 수 있다.
AWQ는 더 단순한 activation-aware scaling을 쓴다. Calibration distribution이 넓거나 chatbot처럼 입력이 예측하기 어려운 경우에는 AWQ가 실무 기본값으로 자주 선택된다.
Weight-only가 항상 빠른 것은 아니다
Weight-only quantization은 memory-bound 상황에서 매우 강하다.
low concurrency
single request latency
memory bandwidth bottleneck
model load / KV budget pressure
이때 W4A16은 weight traffic을 크게 줄여 TTFT나 throughput을 개선할 수 있다.
하지만 concurrency가 커져 compute가 더 중요해지면 약점이 드러날 수 있다.
weight는 INT4로 저장
-> kernel 안에서 dequantize
-> activation은 FP16/BF16
-> compute 자체는 high precision 경로
그래서 high-batch/high-concurrency에서는 activation까지 낮은 precision으로 쓰는 FP8 W8A8 같은 방법이 더 좋은 경우가 있다.
정리하면 weight-only는 “무조건 빠르게 만드는 기술”이 아니라, weight memory traffic을 줄이는 기술이다.
언제 무엇을 먼저 볼까?
실무적인 순서는 보통 이렇다.
빠르게 작동하는 모델이 필요하다
-> 이미 공개된 AWQ/GPTQ checkpoint를 먼저 사용
도메인 데이터가 명확하고 품질을 최대한 보존하고 싶다
-> GPTQ 직접 quantization 고려
chatbot / multi-domain / multimodal처럼 입력이 넓다
-> AWQ 또는 runtime 지원이 좋은 weight-only format 우선
high concurrency에서 compute throughput이 병목이다
-> W8A8 / FP8 activation quantization까지 비교
확인
- Weight-only quantization이 줄이는 것은 compute인가, memory traffic인가?
- GPTQ가 weight MSE가 아니라 layer output error를 보는 이유는 무엇인가?
- AWQ에서 weight magnitude보다 activation magnitude가 중요한 이유는 무엇인가?