저장만으로는 부족하다
지난 글에서 K-Means 기반 양자화를 봤다. 가중치를 몇 개의 대표값으로 묶어 모델 크기를 크게 줄였지만, 결정적인 한계가 있었다. 줄어드는 건 저장 용량뿐이고, 추론할 때는 코드북으로 디코드해서 여전히 floating-point 연산을 한다는 점이다.
이번엔 그 벽을 넘는다. 가중치를 정수로 저장하는 것을 넘어, 곱셈과 덧셈까지 전부 정수 연산으로 추론하는 방법 — Linear Quantization(선형 양자화) 이다. 2018년 Jacob et al.의 논문1이 제안했고, TensorFlow Lite의 INT8 양자화가 바로 이 방식이다.
핵심: 정수와 실수를 잇는 아핀 매핑
Linear Quantization은 정수를 실수로 보내는 아핀(affine) 매핑이다. 딱 한 줄이다.
$$r = S \cdot (q - Z)$$- $r$ — 원래의 실수(real) 값 (floating-point)
- $q$ — 양자화된 정수(quantized integer)
- $Z$ — zero point. 실수 $0$에 정확히 대응하는 정수다. (정수)
- $S$ — scale. 정수 한 칸이 실수로 얼마만큼인지. (floating-point)
즉 정수 $q$에서 zero point $Z$를 빼고 scale $S$를 곱하면 원래 실수가 복원된다. 반대로 실수를 정수로 만들 때는 $q = \text{round}(r / S + Z)$로 반올림한다.
$Z$가 따로 있는 이유가 중요하다. 실수 $0$(예: ReLU 뒤의 0, 패딩)은 신경망에서 아주 흔하고 정확히 표현돼야 한다. zero point는 실수 0이 어떤 정수에도 오차 없이 딱 맞아떨어지도록 보장하는 장치다.
아래 위젯에서 직접 확인해보자. 실수 가중치 행렬이 정수 $q$로 양자화되고, 다시 $S(q-Z)$로 복원된다. bits를 바꾸면 정수 범위가, asymmetric/symmetric을 누르면 $Z$의 처리 방식이 달라지고, 아래에 scale $S$, zero point $Z$, 양자화 오차가 실시간으로 갱신된다.
S와 Z는 어떻게 정하나
$N$비트 정수의 범위는 2의 보수 기준으로 정해진다.
| 비트 폭 | $q_{\min}$ | $q_{\max}$ |
|---|---|---|
| 2 | −2 | 1 |
| 3 | −4 | 3 |
| 4 | −8 | 7 |
| $N$ | $-2^{N-1}$ | $2^{N-1}-1$ |
이제 실수 범위 $[r_{\min}, r_{\max}]$의 양 끝이 정수 범위의 양 끝에 대응한다고 놓자.
$$r_{\max} = S(q_{\max} - Z), \qquad r_{\min} = S(q_{\min} - Z)$$두 식을 빼면 $Z$가 사라지고 scale이 나온다.
$$S = \frac{r_{\max} - r_{\min}}{q_{\max} - q_{\min}}$$위젯 기본값(2비트, 실수 범위 $[-1.08, 2.12]$)로 계산하면 $S = \frac{2.12 - (-1.08)}{1 - (-2)} = \frac{3.20}{3} \approx 1.07$ 이다.
zero point는 아래 식에서 나온다. $r_{\min} = S(q_{\min} - Z)$를 $Z$에 대해 풀고, 정수여야 하니 반올림한다.
$$Z = \text{round}\left(q_{\min} - \frac{r_{\min}}{S}\right)$$같은 예제로 $Z = \text{round}\left(-2 - \frac{-1.08}{1.07}\right) = \text{round}(-0.99) = -1$ 이다. 위젯의 stats에 나오는 $S$, $Z$와 맞는지 확인해보자.
진짜 핵심: 정수 행렬곱
여기까지는 “정수로 저장하기"다. 이제 연산도 정수로 하는 부분을 보자. 신경망의 기본 연산인 행렬곱 $Y = WX$를 생각한다. 각 값을 아핀 매핑으로 바꾸면:
$$S_Y(q_Y - Z_Y) = S_W(q_W - Z_W)\cdot S_X(q_X - Z_X)$$$q_Y$에 대해 정리하면:
$$q_Y = \frac{S_W S_X}{S_Y}\big(q_W q_X - Z_W q_X - Z_X q_W + Z_W Z_X\big) + Z_Y$$괄호 안을 보자. $q_W q_X$는 정수 곱셈이고, 나머지 $Z_W q_X$, $Z_X q_W$, $Z_W Z_X$ 항은 전부 정수끼리의 곱·합이다. 게다가 $Z_W Z_X$처럼 입력과 무관한 항은 미리 계산(precompute) 해둘 수 있다. 즉 괄호 전체가 정수 산술로 끝난다.
남는 건 앞의 $\frac{S_W S_X}{S_Y}$ 뿐인데, 이건 floating-point다. 여기가 이 방법의 묘수다. 경험적으로 이 스케일 비는 항상 $(0, 1)$ 구간에 있어서, 이렇게 쓸 수 있다.
$$\frac{S_W S_X}{S_Y} = 2^{-n} M_0, \qquad M_0 \in [0.5, 1)$$$M_0$는 고정소수점(fixed-point) 곱셈으로, $2^{-n}$은 그냥 비트 시프트(bit shift) 로 처리된다. 결국 floating-point 유닛이 전혀 필요 없다. 모든 연산이 정수 곱셈·덧셈·시프트로 끝난다.
더 단순하게: 대칭 양자화와 bias 접기
실전에서는 두 가지 단순화를 쓴다.
대칭(symmetric) 양자화 — 가중치 분포는 대개 0을 중심으로 대칭이다. 그래서 가중치의 zero point를 아예 $Z_W = 0$으로 고정한다. 그러면 위 식에서 $Z_W q_X$와 $Z_W Z_X$ 항이 사라져 훨씬 깔끔해진다.
$$q_Y = \frac{S_W S_X}{S_Y}\big(q_W q_X - Z_X q_W\big) + Z_Y$$bias 접기 — 편향이 있는 $Y = WX + b$에서는 $Z_b = 0$, $S_b = S_W S_X$로 두면 편향까지 자연스럽게 흡수된다. 입력과 무관한 부분($q_b - Z_X q_W$)을 하나의 $q_{bias}$로 미리 합쳐두면:
$$q_Y = \frac{S_W S_X}{S_Y}\big(q_W q_X + q_{bias}\big) + Z_Y$$합성곱(convolution) 층도 똑같은 구조다. $q_W q_X$ 자리에 $\text{Conv}(q_W, q_X)$가 들어갈 뿐이다. 정리하면 정수 추론 파이프라인은 이렇게 된다.
- 정수 입력·가중치로 정수 MAC(곱셈-누산) → int32 누산
- 미리 계산한 $q_{bias}$를 정수 덧셈
- $\frac{S_W S_X}{S_Y}$를 고정소수점 곱 + 시프트로 rescale → N비트 정수로
- zero point $Z_Y$를 정수 덧셈 → 정수 출력
floating-point는 어디에도 없다.
결과: 얼마나 잃고 얼마나 빨라지나
이렇게 INT8로 양자화해도 정확도는 거의 유지된다.
| 모델 | Float 정확도 | INT8 정확도 |
|---|---|---|
| ResNet-50 | 76.4% | 74.9% |
| Inception-V3 | 78.4% | 75.4% |
1–3%p 안팎의 손실로 모델은 1/4 크기, 연산은 정수가 된다. 모바일(Snapdragon)에서 float 대비 정수 전용 추론은 같은 정확도에서 훨씬 낮은 지연시간을 보인다 — 정수 유닛이 더 싸고 빠르기 때문이다. (1편에서 본 “저비트 정수 연산이 float보다 수십 배 싸다"는 이야기가 여기서 현실이 된다.)
정리
- 아핀 매핑 $r = S(q - Z)$ 하나로 정수 $q$와 실수 $r$을 잇는다. $Z$(zero point)는 실수 0을 정수에 오차 없이 맞추는 장치, $S$(scale)는 한 칸의 크기.
- $S = \frac{r_{\max}-r_{\min}}{q_{\max}-q_{\min}}$, $Z = \text{round}(q_{\min} - r_{\min}/S)$.
- 정수 행렬곱: $q_W q_X$와 precompute 항으로 괄호가 정수 산술, 앞의 스케일 비는 고정소수점 곱 + 시프트. → floating-point 없이 추론.
- 대칭 양자화($Z_W=0$)와 bias 접기로 식이 더 단순해진다.
가장 큰 차이는 여기다. K-Means 양자화는 저장만 정수였다(연산은 float). Linear Quantization은 저장도 정수, 연산도 정수다.
| 방식 | 저장 | 연산 |
|---|---|---|
| 원본 | FP 가중치 | FP 산술 |
| K-Means 양자화 | 정수 인덱스 + FP 코드북 | FP 산술 |
| Linear 양자화 | 정수 가중치 | 정수 산술 |
이걸로 신경망 양자화의 두 큰 갈래 — 저장을 줄이는 K-Means, 연산까지 정수화하는 Linear — 를 모두 봤다. 다음은 극단으로 밀어붙이는 이야기, 가중치를 $+1/-1$ 한 비트로 줄이는 Binary·Ternary 양자화다.
Jacob et al. Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference. CVPR 2018. ↩︎