Scale, Zero Point, and Clipping
마지막 수정:
Quantized integer는 혼자서는 의미가 없다.
int8 값 61은 그냥 61이 아니라, 어떤 scale과 zero-point를 함께 가질 때 “원래 real value가 대략 얼마였는지”를 뜻한다.
기본 식
Dequantization은 integer를 다시 real value로 해석하는 과정이다.
여기서:
r = real value
q = stored integer value
S = scale, integer 한 칸의 실제 간격
Z = zero-point, real 0이 대응되는 integer 위치
반대로 quantization은 real value를 integer grid에 붙이는 과정이다.
즉 실제 구현의 핵심은 네 단계다.
divide by scale
add zero-point
round to integer
clip to valid range
Scale은 resolution이다
S가 작으면 integer grid가 촘촘하다. 가까운 값을 더 잘 구분한다.
하지만 같은 bit-width에서는 grid가 촘촘할수록 표현 가능한 real range가 좁아진다. 범위를 넓게 잡으면 S가 커지고, 값들이 같은 integer로 뭉개지는 granular error가 커진다.
wide range -> larger scale -> coarser resolution
tight range -> smaller scale -> better resolution, more clipping risk
그래서 calibration은 “어디까지를 grid 안에 넣을 것인가”를 정하는 문제다.
Zero-point는 grid를 움직인다
Symmetric quantization은 zero를 grid의 중심에 둔다. weight처럼 대체로 0을 중심으로 양쪽에 퍼진 값에는 잘 맞는다.
Asymmetric quantization은 zero-point를 이용해 grid를 데이터가 있는 쪽으로 이동시킨다. ReLU 이후 activation처럼 대부분 양수인 값에는 음수 영역에 bit를 낭비하지 않는 장점이 있다.
Clipping은 overflow를 막지만 정보를 버린다
integer range 밖으로 나가는 값은 반드시 boundary에 붙는다.
too large -> q_max
too small -> q_min
이 clipping은 단순한 rounding error보다 위험하다. 값 하나가 조금 틀리는 것이 아니라, outlier나 attention logit처럼 중요한 값이 boundary에 잘려 model behavior를 바꿀 수 있다.
따라서 quantization error는 두 종류로 나누어 봐야 한다.
granular error: grid 안에서 가까운 칸으로 반올림되는 오차
overload error: grid 밖의 값이 boundary로 잘리는 오차
좋은 quantization은 둘 중 하나를 없애는 것이 아니라, tensor 분포와 task tolerance에 맞게 둘 사이의 손실을 배치한다.
왜 weight와 activation이 다르게 다뤄지나
Weight는 보통 0 근처에 대칭적으로 분포한다. 그래서 symmetric quantization이 단순하고 효율적이다.
Activation은 입력에 따라 범위가 바뀌고, ReLU나 GeLU 이후에는 분포가 한쪽으로 치우칠 수 있다. 이때 asymmetric quantization이나 dynamic scale이 더 자연스럽다.
이 차이가 나중에 다음 선택으로 이어진다.
weights: symmetric, per-channel or group-wise
activations: asymmetric or dynamic, per-token often useful
KV cache: key/value 통계가 달라 별도 granularity 필요
확인
scale이 커지면 resolution은 어떻게 달라지는가?zero-point가 필요한 이유는 무엇인가?- granular error와 overload error는 어떻게 다른가?