양자화
Llama 3 70B를 BF16으로 저장하면 140 GB다. H100 한 장(80 GB)에 들어가지 않고, 들어간다 해도 토큰 하나를 만들 때마다 그 140 GB를 메모리에서 통째로 읽어야 한다. 숫자 하나에 16비트를 쓰던 것을 8비트, 4비트로 줄이면 모델이 작아지고 디코딩이 빨라진다. 문제는 "얼마나 망가지는가"다. 이 장에서는 비트 하나하나를 직접 뒤집어 부동소수점의 구조를 보고, 실수를 정수 격자에 맞추는 스케일과 영점, 스케일을 얼마나 잘게 나눌지(입도), 이상치가 왜 골칫거리인지, 그리고 GPTQ·SmoothQuant 같은 방법이 오차를 어떻게 줄이는지를 실제 계산으로 따라간다.
- LLM 디코딩이 메모리 대역폭에 묶여 있어서, 가중치 비트 수가 곧 속도를 결정한다는 것을 설명할 수 있다.
- FP32·FP16·BF16·FP8(E4M3/E5M2)·FP4의 부호·지수·가수 구조를 해석하고, 범위와 정밀도의 트레이드오프를 비교할 수 있다.
- 스케일 \(s\)와 영점 \(z\)로 정수 양자화를 수행하고, 반올림 오차와 클리핑 오차의 균형을 이해한다.
- per-tensor·per-channel·per-group 입도의 차이와 스케일 저장 비용(유효 비트)을 계산할 수 있다.
- 활성값 이상치 채널이 왜 INT8 양자화를 어렵게 하는지, SmoothQuant가 이를 어떻게 가중치로 옮기는지 안다.
- GPTQ가 헤시안을 이용해 오차를 남은 열로 보정하는 원리, AWQ·NF4·k-quant·MX 포맷의 핵심 아이디어를 설명할 수 있다.
왜 양자화인가: 토큰당 읽는 바이트
신경망의 파라미터는 결국 숫자 배열이다. 학습은 보통 FP32 마스터 가중치와 BF16 연산으로 하고, 공개되는 체크포인트는 BF16(파라미터당 2바이트)인 경우가 많다. 그러면 모델 크기는 단순한 곱셈이다. 70B(700억) 파라미터 × 2바이트 = 140 GB, 8B 모델(Llama 3 8B, 약 8.03B) × 2바이트 ≈ 16 GB다.
크기가 문제인 이유는 두 가지다. 첫째는 용량이다. 140 GB는 80 GB짜리 H100 한 장에 들어가지 않는다. 둘째, 더 중요한 이유는 속도다. 8장에서 본 것처럼 자기회귀 디코딩은 토큰을 하나씩 만든다. 배치가 1이면 토큰 하나를 만들 때 각 가중치는 곱셈·덧셈 한 번(2 FLOP)에만 쓰이고 버려진다. 즉 바이트당 연산이 고작 1 FLOP 정도다. H100은 초당 약 989조 번(BF16 dense) 계산할 수 있지만 메모리에서는 초당 약 3.35 TB밖에 읽지 못한다. 계산기는 대부분의 시간을 가중치가 도착하기를 기다리며 논다. 이런 상태를 메모리 대역폭 바운드(memory-bandwidth bound)라고 한다(11장의 루프라인에서 자세히 다룬다).
70B·BF16을 H100 대역폭으로 읽으면 140 GB ÷ 3.35 TB/s ≈ 42 ms, 즉 이론 상한이 초당 약 24 토큰이다. 같은 모델을 4비트로 줄이면 읽을 바이트가 4분의 1이 되어 상한이 약 4배 오른다. 양자화는 계산을 빠르게 하는 기술이기 이전에 읽어야 할 바이트를 줄이는 기술이다.
| 정밀도 | 비트/파라미터 | Llama 3 8B | Llama 3 70B | 쓰임 |
|---|---|---|---|---|
| FP32 | 32 | 32.1 GB | 282 GB | 학습 마스터 가중치, 옵티마이저 상태 |
| BF16 / FP16 | 16 | 16.1 GB | 141 GB | 학습 연산, 표준 배포 체크포인트 |
| FP8 / INT8 | 8 (+ε) | 8.0 GB | 71 GB | H100급 서빙(FP8), W8A8 |
| INT4 (g128) | ≈4.125 | 4.1 GB | 36 GB | GPTQ·AWQ, 소비자 GPU·로컬 추론 |
| 3비트급 | ≈3.1~3.5 | ≈3.3 GB | ≈29 GB | GGUF Q3_K 등, 품질 손실 눈에 띔 |
| 2비트급 | ≈2.1~2.6 | ≈2.4 GB | ≈21 GB | 연구·극한 압축, 큰 품질 손실 |
표의 값은 가중치만 센 것이다(70.6B 파라미터 기준). 실제 서빙에서는 여기에 KV 캐시와 활성값 작업 공간이 더해진다(11장). 그리고 임베딩·출력층·정규화 파라미터는 보통 더 높은 정밀도로 남겨 두므로, 실제 파일 크기는 표보다 조금 크다.
양자화 대상은 셋이다. 가중치(W)는 한 번 변환해 두면 끝이라 가장 쉽고 이득이 가장 크다(가중치 전용 양자화, 예: W4A16). 활성값(A)까지 낮추면 행렬곱 자체를 INT8/FP8 텐서 코어로 돌려 계산량이 큰 프리필이 빨라진다(W8A8). KV 캐시를 낮추면 긴 컨텍스트와 큰 배치에서 메모리와 대역폭을 아낀다. 표기 "W4A16"은 가중치 4비트, 활성값 16비트라는 뜻이다.
부동소수점의 구조: 범위와 정밀도
컴퓨터가 실수를 저장하는 표준 방법은 부동소수점(floating point)이다. 과학적 표기법 \(6.02 \times 10^{23}\)을 이진수로 옮긴 것이다. 비트열을 세 부분으로 나눈다.
지수 비트 수 \(e\)는 범위(얼마나 크고 작은 수를 담을 수 있나)를, 가수 비트 수 \(m\)은 정밀도(한 옥타브 \([2^k, 2^{k+1})\) 안에 값이 몇 개 있나)를 정한다. 한 옥타브 안에는 항상 \(2^m\)개의 값이 균일 간격으로 있고, 옥타브가 하나 올라갈 때마다 간격이 두 배가 된다. 그래서 부동소수점의 상대 오차는 크기와 무관하게 대략 \(2^{-m-1}\)로 일정하다. 이것이 정수와의 결정적 차이다.
딥러닝이 BF16을 선호하는 이유가 여기 있다. 학습 중의 기울기와 활성값은 \(10^{-6}\)부터 \(10^{4}\)까지 넓게 퍼져 있어 범위가 정밀도보다 중요하다. 신경망은 개별 값의 작은 잡음에 강하지만, 오버플로로 생긴 Inf 하나는 학습 전체를 망친다. FP8은 한 걸음 더 나가서 용도별로 두 형식을 쓴다. 순전파의 가중치·활성값에는 정밀도가 조금 나은 E4M3를, 범위가 넓어야 하는 역전파의 기울기에는 E5M2를 쓴다. OCP(Open Compute Project) FP8 규격의 E4M3는 Inf를 없애고 그 비트 패턴을 일반 값으로 돌려써서 최대값을 240이 아닌 448까지 늘렸다(NaN은 S.1111.111 하나만 남긴다).
비트 편집기: 부동소수점 해부
| 형식 | 지수/가수 | 최대값 | 최소 정규 | 최소 비정규 | 1 근처 간격 |
|---|---|---|---|---|---|
| FP32 | 8 / 23 | 3.40×10³⁸ | 1.18×10⁻³⁸ | 1.4×10⁻⁴⁵ | 2⁻²³ ≈ 1.2×10⁻⁷ |
| FP16 | 5 / 10 | 65504 | 6.1×10⁻⁵ | 6.0×10⁻⁸ | 2⁻¹⁰ ≈ 9.8×10⁻⁴ |
| BF16 | 8 / 7 | 3.39×10³⁸ | 1.18×10⁻³⁸ | 9.2×10⁻⁴¹ | 2⁻⁷ ≈ 7.8×10⁻³ |
| FP8 E4M3 (OCP) | 4 / 3 | 448 | 2⁻⁶ ≈ 0.0156 | 2⁻⁹ ≈ 0.00195 | 0.125 |
| FP8 E5M2 | 5 / 2 | 57344 | 2⁻¹⁴ ≈ 6.1×10⁻⁵ | 2⁻¹⁶ ≈ 1.5×10⁻⁵ | 0.25 |
| FP4 E2M1 | 2 / 1 | 6 | 1 | 0.5 | 0.5 |
FP8의 최대값 448은 작아 보이지만, 실제로는 텐서마다(또는 블록마다) 스케일을 곱해 값을 이 범위 안으로 옮긴 뒤 저장한다. 즉 FP8 양자화도 다음 절의 정수 양자화와 똑같이 "스케일 + 격자"라는 구조를 갖는다. 다른 점은 격자 간격이 균일하지 않고 0 근처가 촘촘하다는 것뿐이다.
정수 양자화: 스케일과 영점
가장 널리 쓰이는 양자화는 실수 \(x\)를 \(b\)비트 정수 \(q\)로 바꾸는 균일 양자화(uniform / affine quantization)다. 실수 축 위에 간격 \(s\)짜리 격자를 깔고, 각 값을 가장 가까운 격자점으로 보낸다.
두 가지 흔한 방식이 있다.
- 대칭(symmetric): \(z = 0\), \(s = \alpha / q_{\max}\). 클리핑 경계 \(\pm\alpha\)를 정하면 끝이다. INT8이면 \(q \in [-127, 127]\)를 쓴다(−128은 대칭을 위해 보통 버린다). 0이 정확히 표현되고 곱셈 커널이 단순하다. 가중치는 대개 0을 중심으로 대칭 분포라 이 방식을 쓴다.
- 비대칭(asymmetric): 범위 \([\beta, \alpha]\)를 \([0, 2^b-1]\)에 맞춘다. \(s = (\alpha-\beta)/(2^b-1)\), \(z = \operatorname{round}(-\beta/s)\). ReLU 뒤 활성값처럼 한쪽으로 치우친 분포에서 격자를 낭비하지 않는다. 대신 \(z\)를 저장하고 계산에 반영해야 한다.
반올림 오차와 클리핑 오차
범위 \([\beta,\alpha]\)를 어떻게 잡을지가 핵심 설계 문제다. 가장 단순한 선택은 데이터의 최소·최대값(absmax)을 쓰는 것이다. 그런데 분포에 이상치가 하나라도 있으면 범위가 넓어지고, 격자 간격 \(s\)가 커져 대부분의 '평범한' 값들이 거친 격자에 놓인다. 반대로 범위를 좁히면(클리핑) 격자가 촘촘해지지만 범위를 벗어난 값은 경계로 잘려 큰 오차를 낸다. 격자 안쪽 값의 반올림 오차는 균일 분포라 가정하면 평균 제곱이 \(s^2/12\)다.
양자화 숫자선: 클리핑 범위를 끌어 보자
실무에서 쓰는 범위 결정법(보정(calibration))은 absmax, 백분위수(예: 99.99%), MSE 최소화, KL 발산 최소화(TensorRT의 엔트로피 보정) 등이 있다. 가중치는 값을 모두 알고 있으니 MSE 최적 클리핑을 직접 찾을 수 있지만, 활성값은 입력마다 달라지므로 보정 데이터 수백 개를 흘려 통계를 모으거나(정적 양자화), 실행 중에 토큰마다 범위를 계산한다(동적 양자화).
입도: 스케일을 얼마나 잘게 나눌까
스케일 \(s\)를 텐서 전체에 하나만 둘 수도, 더 잘게 나눠 여러 개 둘 수도 있다. 이 단위를 입도(granularity)라고 한다. 선형층 \(y = Wx\)의 가중치 \(W \in \mathbb{R}^{d_{out}\times d_{in}}\)을 예로 들자.
- per-tensor: 행렬 전체에 스케일 1개. 저장 비용은 0에 가깝지만, 어느 한 곳의 큰 값이 전체 격자를 거칠게 만든다.
- per-channel(per-row): 출력 채널(행)마다 스케일 1개. 행마다 크기가 다른 경우를 흡수한다. \(y_i = s_i \sum_j q_{ij} x_j\)처럼 스케일을 행렬곱 밖으로 빼낼 수 있어 INT8 커널에 바로 쓴다. INT8 가중치 양자화의 표준이다.
- per-group: 한 행을 입력 방향으로 \(g\)개(보통 128)씩 끊어 그룹마다 스케일. 입력 채널 방향의 이상치까지 국소화한다. 4비트 이하에서는 사실상 필수다. 대신 스케일이 행렬곱 안쪽 합에 걸리므로 커널이 그룹마다 역양자화를 해야 한다.
그룹을 잘게 나눌수록 정확해지지만 공짜는 아니다. 그룹마다 FP16 스케일(16비트)을 저장하면 가중치 하나당 \(16/g\)비트가 추가된다. 비대칭이면 영점도 저장해야 한다.
가중치 행렬 양자화: 입도와 그룹 크기
실제 4비트 LLM 양자화(GPTQ, AWQ, bitsandbytes NF4, GGUF)는 거의 모두 그룹 크기 32~128을 쓴다. Llama 3 70B의 FFN 행렬은 \(28672 \times 8192\)이므로 g = 128이면 행마다 64개, 행렬 하나에 약 180만 개의 스케일이 생긴다. 많아 보여도 가중치(약 2.35억 개)의 0.8% 수준이다.
활성값 이상치와 SmoothQuant
가중치는 비교적 얌전한 분포를 갖는다. 문제는 활성값이다. 2022년 LLM.int8() 논문(Dettmers 외)은 모델이 약 6.7B 파라미터를 넘으면 은닉 상태의 몇 개 특정 채널에서 다른 채널보다 수십~100배 큰 값이 거의 모든 토큰에 걸쳐 나타난다고 보고했다. 차원은 수천 개인데 이상치 채널은 손에 꼽을 정도로 적지만, 이 채널을 0으로 만들면 모델 성능이 무너질 만큼 중요하다.
활성값 \(X \in \mathbb{R}^{T\times C}\)(토큰 × 채널)를 INT8로 양자화하는 효율적인 방법은 per-tensor 또는 per-token(행마다) 스케일이다. 행렬곱 \(XW\)에서 스케일을 밖으로 빼려면 \(X\)는 행(토큰) 방향, \(W\)는 열(출력) 방향으로만 스케일을 나눌 수 있다. 그런데 이상치는 채널(열) 방향으로 몰려 있다. 결국 이상치 채널이 스케일을 결정해 버리고, 나머지 채널은 몇 개의 격자점만 쓰게 된다. LLM.int8()은 이상치 채널을 따로 떼어 FP16으로 계산하는 혼합 정밀도 분해로 이 문제를 풀었지만, 커널이 복잡하고 느렸다.
SmoothQuant(Xiao 외, 2022)는 더 간단한 수학적 트릭을 쓴다. 행렬곱은 채널별 스케일을 한쪽에서 나누고 다른 쪽에서 곱해도 결과가 변하지 않는다.
SmoothQuant: 이동 강도 α
SmoothQuant 논문은 대부분의 모델에서 \(\alpha \approx 0.5\)가, 이상치가 심한 일부 모델(GLM-130B 등)에서는 0.75 정도가 좋다고 보고했다. 이 방법으로 OPT-175B 같은 대형 모델도 W8A8로 정확도를 거의 잃지 않고 돌릴 수 있게 됐다. 이후 연구는 채널별 스케일 대신 직교 회전 행렬 \(R\)(\(XW = (XR)(R^\top W)\))을 곱해 이상치를 모든 채널에 골고루 퍼뜨리는 방향(QuaRot, SpinQuant 등, 2024)으로 발전했고, 이로써 W4A4에 가까운 설정도 시도되고 있다.
PTQ와 QAT, 그리고 GPTQ
양자화를 언제 하느냐에 따라 두 갈래가 있다.
- PTQ(Post-Training Quantization): 학습이 끝난 모델을 소량의 보정 데이터(수백 문장)만으로 양자화한다. 재학습이 없어 70B 모델도 GPU 한 장으로 몇 시간이면 끝난다. LLM 양자화의 주류다.
- QAT(Quantization-Aware Training): 학습(또는 미세조정) 중에 순전파에서 가중치를 가짜로 양자화(fake quant)하고, 역전파에서는 반올림의 기울기를 1로 취급하는 STE(straight-through estimator)로 통과시킨다. 모델이 양자화 잡음에 적응하므로 낮은 비트에서 품질이 좋지만, 학습 비용이 크다. 일부 모델은 QAT로 만든 4비트 체크포인트를 따로 공개하기도 한다.
가장 단순한 PTQ는 각 가중치를 가장 가까운 격자점으로 보내는 RTN(round-to-nearest)이다. RTN은 가중치 하나하나의 오차 \(|w - \hat w|\)를 최소화하지만, 우리가 진짜 신경 쓰는 것은 층의 출력 \(WX\)다. 여러 가중치의 오차가 서로 상쇄되도록 고르면 개별 오차가 조금 커지더라도 출력 오차는 작아질 수 있다.
GPTQ: 한 열씩 양자화하고, 오차를 남은 열에 떠넘긴다
GPTQ(Frantar 외, 2022)는 층별 재구성 문제를 푼다. 보정 입력 \(X \in \mathbb{R}^{d_{in}\times N}\)에 대해 각 행 \(\mathbf w\)(출력 채널 하나)의 출력 오차는 이차식이다.
알고리즘은 OBS(Optimal Brain Surgeon)에서 왔다. 입력 채널(열) \(q\)를 하나 골라 양자화하면 생긴 오차 \(\delta_q = w_q - \hat w_q\)를, 아직 양자화하지 않은 나머지 가중치를 다음처럼 움직여 최적으로 보상한다.
RTN vs GPTQ: 오차 보정의 효과
AWQ(Activation-aware Weight Quantization, Lin 외, 2023)는 "가중치의 중요도는 그 가중치에 곱해지는 활성값의 크기가 정한다"는 관찰에서 출발한다. 활성값이 큰 입력 채널의 가중치 오차는 출력에 크게 증폭되므로, 그런 약 1%의 채널만 보호해도 품질이 크게 좋아진다. 그렇다고 그 채널만 FP16으로 두면 커널이 복잡해지므로, SmoothQuant와 같은 등가 변환을 쓴다. 중요 채널의 가중치에 \(s_j > 1\)을 곱해 키우고(상대 반올림 오차 감소) 활성값을 \(s_j\)로 나눈다. \(s_j = (\overline{|x_j|})^{\alpha}\) 꼴로 두고 보정 데이터에서 출력 오차가 최소가 되는 \(\alpha\)를 격자 탐색한다. 역전파도 헤시안도 필요 없어 빠르고, 보정 데이터에 덜 과적합한다는 장점이 있다. GPTQ와 함께 4비트 가중치 양자화의 양대 표준이다.
그 밖의 형식과 기법
KV 캐시 양자화
8장의 KV 캐시는 컨텍스트 길이와 배치에 비례해 자란다. Llama 3 70B(80층, KV 헤드 8개, 헤드 차원 128)는 BF16에서 토큰당 \(2 \times 80 \times 8 \times 128 \times 2\) 바이트 ≈ 320 KB, 128K 토큰이면 요청 하나에 약 43 GB다. 긴 컨텍스트에서는 가중치보다 KV 캐시가 더 커진다. KV를 FP8이나 INT8(토큰별·헤드별 스케일)로 저장하면 절반이 되고, 서빙 엔진(vLLM, TensorRT-LLM 등)은 FP8 KV 캐시를 옵션으로 지원한다. 키 벡터에는 특정 채널의 이상치가, 값 벡터에는 토큰별 변동이 커서, 키는 채널별·값은 토큰별 스케일을 쓰는 방식(KIVI 등)도 제안됐다.
NF4와 QLoRA
신경망 가중치는 대략 0을 중심으로 한 정규분포다. 균일 격자는 값이 드문 꼬리에도 격자점을 똑같이 배분하므로 낭비가 있다. NF4(NormalFloat4, QLoRA 논문, Dettmers 외 2023)는 표준정규분포의 분위수(quantile)에 격자점 16개를 놓아 각 격자 구간에 같은 확률 질량이 들어가게 한다. 블록(64개)마다 absmax로 정규화한 뒤 이 표에서 가장 가까운 값을 고른다. QLoRA는 기반 모델을 NF4로 얼려 두고(스케일까지 다시 8비트로 양자화하는 이중 양자화 포함), 그 위에 작은 LoRA 어댑터만 BF16으로 학습한다. 덕분에 65B 모델 미세조정이 48 GB GPU 한 장으로 가능해졌다.
GGUF와 k-quant
llama.cpp의 파일 형식 GGUF는 CPU·Apple 실리콘·소비자 GPU에서 LLM을 돌리는 데 널리 쓰인다. 그 안의 k-quant(Q2_K ~ Q6_K)는 2단계 블록 구조를 쓴다. 대략 말하면 256개 가중치로 된 '슈퍼블록'을 16~32개짜리 하위 블록으로 나누고, 하위 블록의 스케일(과 최소값)을 다시 6비트 정도로 양자화한 뒤 슈퍼블록마다 FP16 스케일 하나만 둔다. 스케일 비용을 줄이면서 작은 블록의 이점을 얻는 방법이다. 이름의 숫자는 대략적 비트 수이고, 실제 유효 비트는 Q4_K_M ≈ 4.8, Q5_K_M ≈ 5.7, Q3_K_M ≈ 3.9비트 정도다(_S/_M/_L은 층마다 정밀도를 다르게 섞는 정도). 정확한 블록 구성은 버전에 따라 바뀌므로 여기서는 개념만 기억하자.
FP8 학습과 MX 블록 포맷
H100(Hopper)부터 텐서 코어가 FP8을 지원해 BF16 대비 약 2배 연산 처리량을 낸다. DeepSeek-V3(2024년 12월 보고)는 대부분의 행렬곱을 FP8로 학습했는데, 텐서 하나에 스케일 하나가 아니라 활성값은 1×128 타일, 가중치는 128×128 블록마다 스케일을 둬서 이상치 문제를 피했다. 이 '작은 블록마다 스케일'이라는 아이디어를 하드웨어 표준으로 만든 것이 OCP MX(Microscaling) 포맷이다. 32개 원소가 8비트 지수 스케일(E8M0, 2의 거듭제곱) 하나를 공유하고, 원소는 FP8·FP6·FP4(MXFP8/6/4) 또는 INT8로 저장한다. MXFP4는 원소 4비트 + 8/32 = 4.25비트다. NVIDIA Blackwell(B200, 2024~25)은 MXFP4와 자체 NVFP4(16개마다 FP8 스케일)를 텐서 코어에서 직접 지원한다. 블록 스케일이 하드웨어 안으로 들어오면서 '양자화된 형식으로 그대로 계산하기'가 표준이 되어 가고 있다.
| 방법 | 대상 | 핵심 아이디어 | 대표 설정 |
|---|---|---|---|
| RTN | W | 가장 가까운 격자점 | W8, W4 g128 |
| LLM.int8() | W·A | 이상치 채널만 FP16으로 분리 | W8A8 + FP16 혼합 |
| SmoothQuant | W·A | 채널 스케일로 난이도 이동 | W8A8 |
| GPTQ | W | 헤시안 기반 순차 오차 보정 | W4/W3 g128 |
| AWQ | W | 활성값 기준 중요 채널 스케일 보호 | W4 g128 |
| NF4 / QLoRA | W | 정규분포 분위수 격자 + LoRA 학습 | W4 블록 64 |
| GGUF k-quant | W | 2단계 블록 스케일 | Q4_K_M ≈ 4.8비트 |
| FP8 (E4M3) | W·A·KV | 텐서/블록 스케일 + FP8 텐서 코어 | W8A8 FP8 |
| MXFP4 / NVFP4 | W·A | 하드웨어 블록 스케일(32/16개) | W4A4 (Blackwell) |
프루닝(pruning)은 가중치의 일부를 0으로 만들어 없앤다. 아무 위치나 0으로 만드는 비정형 희소성은 하드웨어 이득을 얻기 어렵고, NVIDIA 텐서 코어는 4개 중 2개가 0인 2:4 희소성을 지원해 이론상 2배 처리량을 낸다(SparseGPT, Wanda 등). 지식 증류(distillation)는 큰 '교사' 모델의 출력 분포를 작은 '학생' 모델이 따라 배우게 한다. Llama 3.2 1B/3B처럼 큰 모델의 로짓을 이용해 작은 모델을 만드는 것이 대표적이다. 세 기법은 서로 배타적이지 않아서, 증류한 작은 모델을 다시 4비트로 양자화해 휴대폰에서 돌리는 식으로 함께 쓴다.
크기와 속도 계산기
지금까지의 내용을 하나의 계산으로 묶어 보자. 배치 1 디코딩의 토큰당 시간 하한은 "가중치 바이트 ÷ 대역폭"이다. 그룹 양자화의 스케일 오버헤드까지 넣으면 다음과 같다.
모델 크기 · 디코딩 속도 계산기
이 계산은 서빙의 출발점일 뿐이다. 동시에 여러 사용자를 처리하면(배치 > 1) 같은 가중치 읽기를 여러 토큰이 나눠 쓰므로 총 처리량이 크게 오르고, 대신 KV 캐시가 메모리를 차지한다. 이 트레이드오프는 11장의 서빙 플레이그라운드에서 이어서 다룬다.
품질에 미치는 영향
양자화가 모델을 얼마나 망가뜨리는지는 모델 크기·구조·방법·평가 과제에 따라 크게 달라서 하나의 숫자로 말하기 어렵다. 다만 지난 몇 년의 보고들에서 반복되는 대략적인 경향은 있다.
- 8비트(INT8 W8A8, FP8): 대부분의 모델에서 퍼플렉시티·벤치마크 차이가 측정 잡음 수준이다. FP8은 현재 데이터센터 서빙의 사실상 기본값이 되어 가고 있다.
- 4비트 가중치(GPTQ/AWQ g128, NF4, Q4_K_M): 퍼플렉시티가 소폭 오른다(대략 수 % 이내인 경우가 많다). 대화 품질 차이는 체감하기 어려운 경우가 많지만, 수학·코드·다국어처럼 정밀한 과제에서는 차이가 더 잘 드러난다는 보고가 있다.
- 3비트 이하: 단순 방법으로는 급격히 나빠진다. 2비트는 벡터 양자화(QuIP#, AQLM 등)처럼 특별한 기법이 있어야 쓸 만해진다.
- 큰 모델이 더 잘 견딘다: 같은 비트에서 파라미터가 많을수록 상대 손실이 작다. 그래서 "작은 모델의 16비트"보다 "큰 모델의 4비트"가 같은 메모리에서 나은 경우가 많다. 다만 많은 토큰으로 오래 학습한 최신 모델일수록 가중치에 정보가 빽빽해 양자화에 더 민감하다는 관찰도 있다(2024).
퍼플렉시티 비교는 같은 평가 데이터·같은 컨텍스트 길이·같은 토크나이저에서만 의미가 있다. 퍼플렉시티 차이가 작아도 특정 과제(긴 추론, 도구 호출 형식 지키기)에서는 차이가 날 수 있으므로, 실제 배포 전에는 그 용도의 평가 세트로 직접 확인해야 한다. 이 장의 수치들은 모두 "대략, 모델·방법에 따라 다름"으로 읽자.
핵심 정리
- 배치 1 디코딩은 메모리 대역폭 바운드다. 토큰당 시간 ≈ 가중치 바이트 ÷ 대역폭이므로 비트를 절반으로 줄이면 속도 상한이 두 배가 된다. 70B·BF16 = 140 GB, H100에서 이론 상한 ~24 tok/s.
- 부동소수점은 지수 비트로 범위를, 가수 비트로 정밀도를 산다. BF16은 FP32의 범위에 7비트 가수, FP8 E4M3는 최대 448(OCP, Inf 없음), E5M2는 범위가 넓어 기울기용이다.
- 정수 양자화 \(q = \operatorname{round}(x/s) + z\). 범위를 넓게 잡으면 반올림 오차가, 좁게 잡으면 클리핑 오차가 커지므로 MSE 최적 클리핑이 존재한다. 비트 1개 ≈ 6 dB SQNR.
- 입도를 텐서 → 채널 → 그룹으로 잘게 나눌수록 이상치가 국소화되어 정확해지고, 스케일 비용이 \(16/g\)비트씩 든다. INT4 g128 ≈ 4.125비트.
- LLM 활성값에는 소수 채널의 큰 이상치가 있다. SmoothQuant는 \(XW = (X\,\mathrm{diag}(s)^{-1})(\mathrm{diag}(s)W)\)로 난이도를 가중치로 옮겨 W8A8을 가능하게 했다.
- GPTQ는 헤시안 \(H = 2XX^\top\)을 써서 한 열의 반올림 오차를 남은 열로 보정하고, AWQ는 활성값이 큰 중요 채널을 스케일로 보호한다. 둘 다 재학습 없는 PTQ다.
- NF4(정규 분위수 격자), GGUF k-quant(2단계 블록 스케일), MX/NVFP4(하드웨어 블록 스케일), FP8 KV 캐시 등 '작은 블록마다 스케일'이 현재 저비트 형식의 공통 원리다.
확인 퀴즈
1. 배치 1로 디코딩할 때 70B 모델을 BF16에서 INT4(g128)로 바꾸면 토큰 생성 속도의 이론 상한은 대략 어떻게 되는가?
2. BF16이 FP16보다 학습에 선호되는 주된 이유는?
3. 어떤 가중치 행의 절대값 최대가 2.54다. absmax 대칭 INT8 양자화(q ∈ [−127, 127])에서 스케일 s와 값 1.0의 양자화 정수 q는?
4. INT4 가중치를 그룹 크기 64, 그룹마다 FP16 스케일과 FP16 영점을 저장하면 가중치 하나당 유효 비트는?
5. SmoothQuant의 변환 \(XW = (X\,\mathrm{diag}(s)^{-1})(\mathrm{diag}(s)\,W)\)에 대한 설명으로 옳은 것은?
6. 보정 입력 X의 채널들이 서로 완전히 무상관이어서 \(H = 2XX^\top\)가 대각 행렬이라면 GPTQ의 결과는?