디코드 스텝의 하한은 가중치를 메모리에서 읽는 시간이 정한다. 그렇다면 가중치를 작게 만들면 그만큼 빨라진다. 양자화(quantization)는 가중치를 BF16의 16비트보다 적은 비트로 표현하는 방법이다. 서빙에서 양자화는 모델을 작은 GPU에 올리는 수단이기도 하지만, 같은 GPU에서 디코드를 빠르게 하고 KV 캐시 공간을 넓히는 수단이기도 하다.
바이트가 줄면 생기는 일
Llama 3.1 8B의 가중치는 BF16으로 약 16GB다. 같은 모델을 8비트로 표현하면 약 8GB, 4비트면 약 4GB에 스케일 값이 조금 더해진다. H100 SXM의 대역폭 3.35TB/s로 디코드 스텝 하한을 다시 계산하면 이렇다.
| 가중치 형식 | 가중치 크기 | 디코드 스텝 하한 (배치 1) | KV 캐시에 더 쓸 수 있는 메모리 |
|---|---|---|---|
| BF16 | 약 16GB | 약 4.8ms | 기준 |
| 8비트 (FP8, INT8) | 약 8GB | 약 2.4ms | 약 8GB |
| 4비트 (INT4) | 약 4GB + 스케일 | 약 1.2ms + α | 약 12GB |
배치가 작을 때는 스텝 시간이 거의 가중치 크기에 비례해 준다. 줄어든 가중치 자리는 KV 캐시가 쓰므로 8GB면 토큰당 128KiB 기준으로 약 6만 토큰을 더 담는다. 동시 처리 요청 수가 늘어 처리량도 함께 오른다.
배치가 커지면 이 이득이 줄어든다. 배치가 클수록 스텝마다 읽는 바이트 가운데 KV 캐시 비중이 커지고, 연산 강도가 능선에 가까워지면 스텝 시간을 연산이 정하기 시작한다. 이때부터는 가중치를 얼마나 작게 저장했느냐보다 행렬 곱을 몇 비트 연산기로 하느냐가 중요해진다.
가중치만 줄이는 방식과 활성화까지 줄이는 방식
양자화 방식은 행렬 곱의 두 입력 가운데 무엇을 줄이느냐로 나뉜다.
| 방식 | 표기 예 | 메모리에 저장 | 행렬 곱 | 주로 얻는 것 |
|---|---|---|---|---|
| 가중치만 | W4A16, W8A16 | 저비트 가중치 | 커널 안에서 가중치를 BF16으로 풀어 BF16 연산 | 가중치를 읽는 바이트 감소. 작은 배치의 디코드가 빨라진다 |
| 가중치와 활성화 | W8A8 (INT8, FP8) | 저비트 가중치 | 활성화도 8비트로 바꿔 8비트 텐서 코어로 연산 | 바이트 감소에 더해 연산 성능 상한이 오른다. 프리필과 큰 배치도 빨라진다 |
H100 SXM의 사양에서 FP8 텐서 코어 성능은 3,958 TFLOPS(희소성 가정)로 BF16의 두 배다. 밀집 행렬 기준으로 약 1,979 TFLOPS다. 가중치만 양자화하면 연산은 여전히 BF16으로 하므로 이 상한을 쓰지 못한다. 연산 성능에 묶인 프리필에서는 가중치만 줄이는 방식의 이득이 작고, 커널 안에서 가중치를 푸는 비용 때문에 오히려 느려질 수도 있다.
그래서 고르는 기준은 부하의 모양이다. 배치가 작고 디코드가 대부분인 부하에서는 4비트 가중치 양자화가 지연을 가장 많이 줄인다. 배치가 크고 프롬프트가 긴 부하에서는 FP8처럼 연산까지 8비트로 하는 방식이 처리량을 더 올린다.
숫자 형식
| 형식 | 구성 | 특징 |
|---|---|---|
| INT8 | 정수 8비트 + 스케일 | 값 범위가 균일하게 나뉜다. 큰 이상값이 있으면 스케일이 커져 작은 값들의 정밀도가 떨어진다 |
| FP8 E4M3 | 지수 4비트, 가수 3비트 | 최대 448. 정밀도가 높아 추론의 가중치·활성화에 주로 쓴다 |
| FP8 E5M2 | 지수 5비트, 가수 2비트 | 최대 57,344. 범위가 넓고 정밀도가 낮다 |
| INT4 | 정수 4비트 + 그룹별 스케일 | 가중치만 양자화할 때 쓴다. 가중치 64~128개 단위의 그룹마다 스케일을 둬 정밀도를 지킨다 |
FP8의 두 형식은 FP8 Formats for Deep Learning이 정의했다. 부동소수점이라 값의 크기에 따라 간격이 달라지므로 분포의 꼬리가 긴 신경망 값을 INT8보다 적은 손실로 담는다.
어느 형식이든 실제 값은 저비트 값에 스케일을 곱해 복원한다. 스케일을 텐서 전체에 하나 두면 가장 단순하지만 정밀도가 낮고 출력 채널마다 또는 작은 그룹마다 두면 정밀도가 오르는 대신 스케일을 저장하고 곱하는 비용이 는다.
오차를 줄이는 방법
가중치를 반올림만 해서 줄여도 8비트는 대개 큰 손실이 없지만 4비트에서는 품질이 눈에 띄게 떨어진다. 학습을 다시 하지 않고 적은 보정 데이터로 오차를 줄이는 사후 양자화(post-training quantization) 방법들이 그래서 나왔다.
- GPTQ (ICLR 2023): 층마다 가중치를 한 열씩 양자화하면서, 생긴 오차를 아직 양자화하지 않은 열들이 보정하도록 갱신한다. 보정 데이터로 구한 2차 정보(헤시안)를 써서 출력 오차가 최소가 되게 한다
- AWQ (MLSys 2024): 활성화가 큰 채널에 곱해지는 가중치가 출력에 더 큰 영향을 준다는 관찰에서 출발한다. 논문은 중요한 가중치 1%만 보호해도 양자화 오차가 크게 준다고 보고하고, 그 채널을 혼합 정밀도로 남기는 대신 채널별 스케일을 키워 함께 양자화한다
- LLM.int8() (NeurIPS 2022): 큰 모델의 활성화에는 일부 차원에 아주 큰 이상값이 나타난다. 이상값 차원만 16비트로 따로 계산하고 나머지를 8비트로 계산한다
- SmoothQuant (ICML 2023): 활성화의 이상값 때문에 W8A8이 어렵다는 문제를, 활성화의 채널별 크기를 가중치 쪽으로 옮겨 둘 다 8비트에 담기 쉽게 만드는 수학적으로 동등한 변환으로 푼다
공개 모델은 이런 방법으로 미리 양자화한 체크포인트가 함께 배포되는 경우가 많다. 직접 양자화하든 받아 쓰든 어떤 방법과 설정(비트 수, 그룹 크기, 보정 데이터)으로 만든 것인지 기록해 둔다.
품질 확인
양자화 모델의 품질은 일반 벤치마크 점수 몇 개로 확인하고 끝내지 않는다. 평균 점수가 비슷해도 특정 작업에서만 크게 떨어지는 경우가 있기 때문이다.
- 서비스의 실제 작업으로 평가한다. 운영 요청에서 뽑은 평가 집합으로 원본과 양자화 모델의 출력을 비교한다
- 긴 문맥과 형식 준수를 따로 본다. 긴 문서에서 정보를 찾는 작업, JSON처럼 형식을 지켜야 하는 출력, 수치 계산은 양자화 오차에 민감한 편이다
- 언어별로 본다. 보정 데이터가 영어 위주였다면 한국어처럼 보정에 덜 들어간 언어에서 손실이 더 클 수 있다
- 성능과 함께 기록한다. 같은 부하 테스트로 굿풋을 재고, 품질 손실과 얻은 굿풋을 나란히 놓고 고른다
4비트 양자화한 큰 모델이 BF16 작은 모델보다 같은 메모리에서 품질이 더 좋은 경우도 많다. 양자화는 같은 모델을 빠르게 만드는 수단인 동시에, 주어진 GPU에 올릴 수 있는 모델의 선택지를 넓히는 수단이다.