Kvantisering
Kunna förklara int8/int4-kvantisering, mäta kvalitetsförlust och minnesvinst, och köra en kvantiserad modell lokalt.
Förkunskaper
Intuition
En 7B-modell i float16 tar 14 GB. I int4 tar den 3,5–4 GB och får plats på en laptop. Kvantisering = lagra vikter med färre bitar.
Recept (linjär kvantisering): för en grupp vikter, hitta max-absolutvärde → skala s = max/127 (int8). Lagra q = round(w/s) som heltal; vid beräkning w ≈ q·s. Med nollpunkt kan man använda hela intervallet asymmetriskt. Finare grupper (per kanal, per 64–128 vikter) → mindre fel, lite mer metadata.
Vad förloras? Per-token-perplexitet stiger något: int8 nästan gratis, int4 ofta +1–3 % PPL, int3 och lägre gör skada. Outliers (enstaka jättevikter/aktiveringar) är huvudproblemet — därför metoder som GPTQ/AWQ som kvantiserar «smart» med kalibreringsdata.
Kvantisering ger också snabbare inferens när minnesbandbredd är flaskhalsen (vilket den är vid dekodning): färre byte att läsa per token.
Kod
import numpy as np
def quantize(w, bits=8, group=64):
"""Symmetrisk per-grupp-kvantisering. Returnerar (q int, skalor)."""
qmax = 2 ** (bits - 1) - 1
w = w.reshape(-1, group)
s = np.abs(w).max(axis=1, keepdims=True) / qmax
s[s == 0] = 1e-8
q = np.clip(np.round(w / s), -qmax - 1, qmax).astype(np.int8 if bits <= 8 else np.int16)
return q, s
def dequantize(q, s, shape):
return (q.astype(np.float32) * s).reshape(shape)
rng = np.random.default_rng(0)
W = rng.normal(0, 0.02, (4096, 4096)).astype(np.float32); W[0, 0] = 1.0 # en outlier
for bits in (8, 4):
q, s = quantize(W, bits)
err = np.linalg.norm(W - dequantize(q, s, W.shape)) / np.linalg.norm(W)
mb = q.size * bits / 8 / 1e6 + s.size * 2 / 1e6
print(bits, "relfel", round(float(err), 4), "MB", round(mb, 1), "vs fp16", W.size * 2 / 1e6)
# 8 relfel ~0.002 MB 16.9 vs fp16 33.6
# 4 relfel ~0.04 MB 8.5
Lokalt: llama.cpp med GGUF (Q4_K_M ≈ 4,5 bit/vikt) eller bitsandbytes i transformers (load_in_4bit=True).
Formellt
Affin kvantisering: , . Kvantiseringsbrus för likformig rundning har varians ; relativt fel skalar med i gruppen, vilket är varför outliers förstör och små grupper hjälper. GPTQ minimerar lagervis med Hessian-information () från kalibreringsdata; AWQ skalar kanaler så att viktiga (aktiveringstunga) vikter får mindre relativt fel. Aktiveringskvantisering (W8A8) kräver hantering av aktiverings-outliers (SmoothQuant). Minnesbandbredd: dekodning av token läser alla vikter en gång → tid ≈ bytes/bandbredd; halverade bytes ≈ dubbel hastighet tills beräkning blir flaskhals.
Behärskning innebär
- Förklarar int8/int4-kvantisering: skala, nollpunkt, per-kanal/grupp
- Mäter minnesvinst och kvalitetsförlust
- Kör en kvantiserad modell lokalt
Logga in för att göra övningarna och bygga upp din behärskning.
Källor
- arXiv — GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers — arXiv (öppen åtkomst; licens per artikel)
- arXiv — AWQ: Activation-aware Weight Quantization — arXiv (öppen åtkomst; licens per artikel)
- llama.cpp (MIT) — MIT