수학

MATH / 중급 72번

양자화 오차: 격자 사상, 오차 분산, 이상치 채널

실수를 2^b개 격자에 사상할 때 오차의 분산이 왜 Δ²/12인지 유도하고, 그것이 비트당 6.02dB라는 SNR로 번역되는 과정을 실측과 대조했습니다. 이상치 하나가 나머지 값의 유효 비트를 어떻게 먹는지, 그리고 int4에서 성능이 무너지는 지점을 오차 예산으로 미리 계산하는 법까지.

PALDYN Team18 MIN READ

int8 양자화는 잘 됐습니다. 벤치마크 점수가 0.3%p 떨어지고 메모리는 4분의 1이 됐습니다. 같은 파이프라인에서 비트만 4로 내리자 점수가 절반 아래로 떨어졌습니다.

여기서 보통 도구를 바꿔 봅니다 — 캘리브레이션 데이터를 늘리고, GPTQ를 써 보고, 그룹 크기를 조정합니다. 그런데 왜 8에서 4로 갈 때 그 자리에서 무너지는지는 그 어느 것도 설명하지 않습니다.

설명은 계산으로 나옵니다. 양자화 오차의 크기는 비트 수와 값의 분포만으로 결정되고, 그 오차가 층의 출력에서 얼마나 커지는지도 한 줄로 예측됩니다. 이 글은 그 계산을 세웁니다. 기법과 도구는 양자화 기초와 AWQ·GPTQ 비교가 맡고, 여기서는 오차의 수학만 봅니다.

격자 사상과 스텝 크기

양자화는 실수 구간을 유한한 격자에 사상하는 일입니다. bb 비트면 격자가 2b2^b 개이고, 담을 구간이 [ℓ,h][\ell, h] 일 때

Δ=h−ℓ2b−1\Delta = \frac{h - \ell}{2^b - 1}

가 격자 사이의 간격입니다. 이 값을 스텝 크기라고 부릅니다. 분모가 2b2^b 이 아니라 2b−12^b-1 인 것은 격자가 2b2^b 개면 그 사이의 간격은 2b−12^b-1 개이기 때문입니다.

값 하나를 격자에 올리는 것은 반올림입니다.

Q(x)=Δ⋅round⁡ ⁣(x−ℓΔ)+ℓQ(x) = \Delta \cdot \operatorname{round}\!\left(\frac{x - \ell}{\Delta}\right) + \ell

양자화의 계단 함수와 톱니 모양 오차

오차 e=x−Q(x)e = x - Q(x) 는 [−Δ/2,+Δ/2][-\Delta/2, +\Delta/2] 를 톱니로 오갑니다. 반올림이 가장 가까운 격자로 가므로 오차가 간격의 절반을 넘을 수 없고, 한 칸 안에서는 왼쪽 끝의 −Δ/2-\Delta/2 에서 오른쪽 끝의 +Δ/2+\Delta/2 까지 선형으로 훑습니다.

오차의 분산은 Δ²/12

톱니 모양을 보면 다음 단계가 나옵니다. 입력이 격자 간격에 견줘 넓게 퍼져 있으면 오차는 [−Δ/2,Δ/2][-\Delta/2, \Delta/2] 위의 균등분포로 봐도 됩니다. 그러면 분산이 적분 한 줄로 나옵니다.

Var⁡(e)=E[e2]=∫−Δ/2Δ/2e2⋅1Δ de=1Δ[e33]−Δ/2Δ/2=1Δ⋅23(Δ2)3=Δ212\begin{aligned} \operatorname{Var}(e) = \mathbb{E}[e^2] &= \int_{-\Delta/2}^{\Delta/2} e^2 \cdot \frac{1}{\Delta}\,de \\ &= \frac{1}{\Delta}\left[\frac{e^3}{3}\right]_{-\Delta/2}^{\Delta/2} \\ &= \frac{1}{\Delta} \cdot \frac{2}{3}\left(\frac{\Delta}{2}\right)^3 = \frac{\Delta^2}{12} \end{aligned}

평균이 0이라 Var⁡(e)=E[e2]\operatorname{Var}(e) = \mathbb{E}[e^2] 이고, 밀도가 1/Δ1/\Delta 로 일정하니 그냥 e2e^2 을 적분하면 됩니다. Δ2/12\Delta^2/12 가 양자화 오차의 분산이고, 이 글의 나머지가 전부 이 한 값에서 나옵니다.

정말 그런지 200만 개로 재 봤습니다.

비트 Δ\Delta 오차 분산 (실측) Δ2/12\Delta^2/12 최대 오차 Δ/2\Delta/2
8 0.007843 5.125 × 10⁻⁶ 5.126 × 10⁻⁶ 0.00392 0.00392
4 0.133333 1.481 × 10⁻³ 1.481 × 10⁻³ 0.06667 0.06667
3 0.285714 6.806 × 10⁻³ 6.803 × 10⁻³ 0.14286 0.14286

소수 넷째 자리까지 맞습니다. 최대 오차도 정확히 Δ/2\Delta/2 입니다.

이 근사가 깨지는 자리도 분명합니다. 입력이 격자 간격보다 좁게 몰려 있으면 오차가 균등하지 않고 격자 위치에 따라 편향됩니다. 비트가 아주 적거나(2비트) 값이 한 격자 근처에 모여 있는 경우가 그렇고, 뒤에서 2비트가 예측과 어긋나는 것을 보게 됩니다.

비트 하나가 6.02dB다

오차의 절대 크기는 값의 규모에 따라 다르므로, 비교하려면 신호와의 비를 봐야 합니다. SNR(signal-to-noise ratio, 신호 대 잡음비)은 신호의 분산을 오차의 분산으로 나눈 값이고 데시벨로 적습니다.

SNRdB=10log⁡10σx2Var⁡(e)=10log⁡1012 σx2Δ2\mathrm{SNR_{dB}} = 10\log_{10}\frac{\sigma_x^2}{\operatorname{Var}(e)} = 10\log_{10}\frac{12\,\sigma_x^2}{\Delta^2}

여기에 Δ\Delta 를 대입합니다. 데이터의 최댓값이 표준편차의 kk 배라고 두면 — k=max⁡∣x∣/σxk = \max|x| / \sigma_x — 대칭 양자화에서 Δ≈2kσx/2b\Delta \approx 2k\sigma_x / 2^b 이므로

12σx2Δ2=12σx2⋅22b4k2σx2=3⋅22bk2SNRdB=10log⁡103+20blog⁡102−20log⁡10k=6.02 b+4.77−20log⁡10k\begin{aligned} \frac{12\sigma_x^2}{\Delta^2} &= \frac{12\sigma_x^2 \cdot 2^{2b}}{4k^2\sigma_x^2} = \frac{3 \cdot 2^{2b}}{k^2} \\ \mathrm{SNR_{dB}} &= 10\log_{10} 3 + 20b\log_{10} 2 - 20\log_{10} k \\ &= 6.02\,b + 4.77 - 20\log_{10} k \end{aligned}

비트 하나가 6.02dB입니다. σx\sigma_x 가 약분돼 사라진 것에 주목할 만합니다 — 값을 몇 배로 키우든 SNR은 안 변합니다. 남은 것은 비트 수 bb 와 분포의 꼬리 길이 kk 뿐입니다.

표준정규분포 200만 개(k=5.535k = 5.535, 20log⁡10k=14.8620\log_{10}k = 14.86)로 대조했습니다.

비트 실측 SNR 예측 6.02b+4.77−14.866.02b + 4.77 - 14.86 차이
8 38.01 dB 38.07 dB −0.06
6 25.75 dB 26.03 dB −0.27
4 12.83 dB 13.99 dB −1.16
3 5.49 dB 7.97 dB −2.48

8비트와 6비트는 0.3dB 안쪽으로 맞고, 비트가 줄수록 실측이 예측보다 나쁩니다. 앞에서 말한 균등분포 가정이 무너지는 자리입니다 — 격자가 성기면 정규분포의 봉우리가 한 칸 안에 통째로 들어가 오차가 균등하지 않게 됩니다.

kk 항이 실무적으로 중요합니다. 꼬리가 길수록 SNR이 나빠지고, 그 손해가 비트 손실로 환산됩니다. kk 가 두 배가 되면 20log⁡102=6.0220\log_{10}2 = 6.02 dB를 잃는데, 이것은 정확히 비트 하나를 버리는 것과 같습니다. 클리핑(꼬리를 잘라 kk 를 줄이는 것)이 손해처럼 보이면서도 이득인 이유가 여기 있습니다 — 잘린 소수의 값에서 큰 오차를 감수하고 나머지 전부의 Δ\Delta 를 줄입니다.

대칭인가 비대칭인가

지금까지 [ℓ,h][\ell, h] 를 데이터의 최소·최대로 잡았습니다. 이것이 비대칭 양자화입니다. 0이 격자의 어디에 놓일지 모르므로 「0에 해당하는 정수」를 따로 저장하는데, 이것을 영점(zero point)이라고 합니다.

대칭 양자화는 [−m,+m][-m, +m] (m=max⁡∣x∣m = \max|x|)으로 잡아 0이 격자의 정확히 가운데에 오게 합니다. 영점이 항상 0이라 저장할 것이 하나 줄고, 정수 연산에서 영점 보정 항이 사라져 커널이 단순해집니다.

어느 쪽이 나은지는 분포가 얼마나 치우쳤는가 하나로 갈립니다.

대칭 격자와 비대칭 격자가 치우친 분포에서 갈리는 모습

분포 비트 비대칭 Δ\Delta 비대칭 MSE 대칭 Δ\Delta 대칭 MSE MSE 비
0 대칭 (가중치) 8 0.03508 1.03 × 10⁻⁴ 0.03602 1.08 × 10⁻⁴ 1.06배
0 대칭 (가중치) 4 0.59628 2.97 × 10⁻² 0.65352 3.57 × 10⁻² 1.20배
한쪽 치우침 (ReLU 출력) 8 0.01844 1.75 × 10⁻⁵ 0.03703 7.08 × 10⁻⁵ 4.04배
한쪽 치우침 (ReLU 출력) 4 0.31351 5.09 × 10⁻³ 0.67182 2.33 × 10⁻² 4.58배

0 근처로 퍼진 가중치에서는 차이가 1.2배뿐이라 커널이 단순한 대칭 쪽을 씁니다. ReLU를 지난 활성값처럼 한쪽만 나오는 분포에서는 대칭 격자가 음수 쪽에 칸의 절반을 버려 오차가 4.6배가 됩니다. 「가중치는 대칭, 활성값은 비대칭」이라는 실무의 관행이 이 표에서 나옵니다.

MSE 비가 4배 남짓인 것도 우연이 아닙니다. 대칭이 범위를 두 배로 잡으면 Δ\Delta 가 두 배가 되고, 오차 분산은 Δ2\Delta^2 에 비례하니 네 배가 됩니다.

이상치 하나가 나머지의 비트를 먹는다

Δ\Delta 가 max⁡∣x∣\max|x| 로 정해진다는 것이 이 방식의 급소입니다. 값 4,096개 중 하나만 크면 나머지 4,095개의 격자 간격이 그것에 끌려갑니다.

이상치 크기에 따라 격자가 늘어나는 모습

4비트 대칭 양자화에서, 표준편차 0.5짜리 값 4,096개 중 첫 번째만 크게 바꿔 가며 쟀습니다.

이상치 범위 Δ\Delta 정상값이 실제로 쓰는 비트 정상값 MSE 상대오차
없음 1.75 0.2494 3.91 5.12 × 10⁻³ 0.142
2 2.00 0.2857 3.70 6.76 × 10⁻³ 0.163
5 5.00 0.7143 2.32 4.16 × 10⁻² 0.404
20 20.00 2.8571 1.58 2.51 × 10⁻¹ 0.993
100 100.00 14.2857 0.00 2.55 × 10⁻¹ 1.000

「실제로 쓰는 비트」는 정상값 4,095개가 실제로 차지한 격자 칸 수의 로그입니다. 4비트를 할당했는데 이상치가 20이면 1.58비트만 쓰고, 100이면 0비트 — 모든 정상값이 같은 칸(0)으로 사상됩니다. 상대오차 1.000은 값을 통째로 잃었다는 뜻입니다.

이것이 LLM 양자화에서 「이상치 채널」이 문제가 되는 이유입니다. 트랜스포머의 활성값에는 몇 개 차원에서만 다른 차원보다 수십 배 큰 값이 규칙적으로 나타나는데, 텐서 전체에 스케일 하나를 쓰면 그 몇 개가 나머지 수천 개의 비트를 먹습니다.

처방은 스케일을 나누는 것입니다. 이상치가 특정 채널에 몰려 있다면 채널마다 Δ\Delta 를 따로 두면 됩니다.

64×25664 \times 256 가중치에서 17번 채널만 40배 크게 만들어 두고 두 방식을 비교했습니다.

비트 텐서 전체에 스케일 하나 채널마다 스케일 차이
8 8.77 × 10⁻³ 4.19 × 10⁻⁵ 209배
4 2.57 × 10⁻¹ 1.24 × 10⁻² 21배

채널마다 스케일 하나(fp16 두 바이트)를 더 저장하는 값으로 오차가 20배에서 200배 줄었습니다. 채널이 256개면 추가 저장량은 512바이트, 원래 가중치의 1.6%입니다. 그룹 단위 양자화(채널을 다시 128개씩 묶어 그룹마다 스케일을 두는 것)가 실무의 기본값이 된 이유가 이 표입니다.

오차 예산으로 무너지는 지점을 미리 계산하기

서두의 질문으로 돌아갑니다. int4에서 무너질지를 돌려 보기 전에 알 수 있을까요.

선형층 y=Wx\mathbf{y} = W\mathbf{x} 에서 WW 를 양자화하면 W^=W+E\hat{W} = W + E 이고, 출력의 오차는 ExE\mathbf{x} 입니다. EE 의 성분이 분산 Δ2/12\Delta^2/12 로 독립이라고 보면, 출력 오차의 크기와 출력 자체의 크기가 각각

E∥Ex∥2=n⋅Δ212∥x∥2,E∥Wx∥2=n σW2 ∥x∥2\mathbb{E}\|E\mathbf{x}\|^2 = n\cdot\frac{\Delta^2}{12}\|\mathbf{x}\|^2, \qquad \mathbb{E}\|W\mathbf{x}\|^2 = n\,\sigma_W^2\,\|\mathbf{x}\|^2

이므로 nn 과 ∥x∥\|\mathbf{x}\| 가 통째로 약분됩니다. 남는 것은

∥Ex∥∥Wx∥≈ΔσW12\frac{\|E\mathbf{x}\|}{\|W\mathbf{x}\|} \approx \frac{\Delta}{\sigma_W\sqrt{12}}

한 줄이고, 이것을 오차 예산이라고 부르겠습니다. 필요한 값은 가중치의 표준편차와 최댓값 둘뿐이라 모델을 돌리지 않고 계산할 수 있습니다.

1024×10241024\times1024 선형층에서 예산과 실측을 대조했습니다.

비트 수별 오차 예산과 실측 상대오차

비트 예산 Δ/(σW12)\Delta/(\sigma_W\sqrt{12}) 실제로 잰 상대오차
8 0.0106 0.0103
6 0.0436 0.0438
5 0.0901 0.0910
4 0.1931 0.1814
3 0.4505 0.4403
2 1.3516 0.9730

5비트까지는 소수 셋째 자리까지 맞습니다. 2비트에서만 예산이 비관적인데, 이 지점에서는 오차가 신호만큼 커져 「독립적인 잡음」이라는 전제가 무너지기 때문입니다(양자화가 값을 아예 0으로 뭉개는 쪽으로 편향됩니다).

표에서 읽히는 것이 서두의 질문에 대한 답입니다. int8은 출력을 1% 흔들고 int4는 18% 흔듭니다. 층 하나에서 18%면 층 서른 개를 지나며 어떻게 될지는 그 층들이 오차를 얼마나 증폭하느냐에 달렸지만, 1%와 18%가 같은 결과를 낼 수 없다는 것은 분명합니다. 8과 4 사이가 아니라 5와 4 사이가 절벽이라는 것도 이 표가 알려 줍니다 — 9%에서 18%로 두 배가 되는 자리입니다.

그리고 예산 식의 분자에 Δ\Delta 가 있으므로, Δ\Delta 를 줄이는 모든 조작이 그대로 예산을 줄입니다. 채널별 스케일, 그룹 양자화, 클리핑이 전부 max⁡∣W∣\max|W| 를 낮춰 Δ\Delta 를 줄이는 일이고, 그것이 얼마나 도움이 될지도 같은 식에 넣어 미리 계산할 수 있습니다.

정리

  • 양자화의 스텝 크기는 Δ=(h−ℓ)/(2b−1)\Delta = (h-\ell)/(2^b-1) 이고, 반올림 오차는 [−Δ/2,Δ/2][-\Delta/2, \Delta/2] 를 톱니로 오간다.
  • 오차를 균등분포로 보면 분산이 Δ2/12\Delta^2/12 다. 적분 한 줄로 나오고, 200만 개 실측과 소수 넷째 자리까지 맞았다. 이 근사는 격자가 아주 성길 때(2~3비트) 깨진다.
  • SNR로 옮기면 SNRdB=6.02 b+4.77−20log⁡10k\mathrm{SNR_{dB}} = 6.02\,b + 4.77 - 20\log_{10}k 다(k=max⁡∣x∣/σxk = \max|x|/\sigma_x). 비트 하나가 6.02dB이고, 신호의 크기 σx\sigma_x 는 약분돼 사라진다.
  • 꼬리가 두 배로 길어지면 비트 하나를 버리는 것과 같다(6.02dB). 클리핑이 손해처럼 보이면서 이득인 이유다.
  • 대칭이냐 비대칭이냐는 분포가 치우쳤는지 하나로 갈린다. 0 대칭인 가중치에서는 차이가 1.2배지만 ReLU 출력에서는 4.6배다 — 대칭 격자가 데이터 없는 음수 쪽에 칸의 절반을 버리기 때문이다.
  • Δ\Delta 가 max⁡∣x∣\max|x| 로 정해지므로 이상치 하나가 나머지 전부의 격자를 늘린다. 4비트에서 이상치가 20이면 정상값이 실제로 쓰는 비트는 1.58, 100이면 0이다.
  • 처방은 스케일을 나누는 것이다. 채널마다 스케일을 두니 오차가 8비트에서 209배, 4비트에서 21배 줄었다. 추가 저장은 가중치의 1.6%다.
  • 오차 예산 Δ/(σW12)\Delta/(\sigma_W\sqrt{12}) 은 층 출력의 상대오차를 모델을 돌리지 않고 예측한다. 5비트까지 소수 셋째 자리까지 맞았다.
  • 그 예산이 말하는 것 — int8은 출력을 1% 흔들고 int4는 18% 흔든다. 절벽은 8과 4 사이가 아니라 5와 4 사이다.

읽어주셔서 감사합니다. 😊

LATEST

수학의 최신 글

수학2026.09.07

부동소수점은 어디서 새는가: 반올림, 상쇄, 더하는 순서

0.1 + 0.2가 0.3이 아닌 이유부터 시작해 머신 엡실론을 유도하고, 같은 16비트인데 fp16과 bf16이 서로 다른 지점에서 터지는 이유, 비슷한 수를 뺄 때 유효자리가 사라지는 파괴적 상쇄, 그리고 1,000만 개를 순서만 바꿔 더했을 때 오차가 백만 배 갈리는 실험까지 직접 재 봤습니다.

중급23 MIN
수학2026.09.07

커널과 그람 행렬: 내적을 바꾸면 무엇이 달라지나

그람 행렬의 정의와 양반정치성부터 시작해, 커널이 왜 「만들지 않은 특징공간의 내적」인지를 다항 커널로 손계산해 확인하고, RBF의 γ가 유효 랭크를 어떻게 정하는지 300×300 그람 행렬로 재 봅니다. 어텐션 점수 행렬이 같은 자리에 있으면서 어디가 다른지까지.

중급26 MIN
수학2026.09.07

임베딩 분포의 이방성: 공분산으로 재고 whitening으로 펴기

검색 결과의 코사인 유사도가 전부 0.8 근처에 몰려 순위가 흐려지는 현상을 공분산 행렬의 고윳값 분포로 측정하고, 평균 제거와 whitening이 그 분포를 어떻게 바꾸는지 4,000개 벡터로 직접 재 봤습니다. 후처리가 무엇을 대가로 치르는지까지 숫자로 확인합니다.

중급24 MIN