Automatically generated from handwritten notes — Quantization basics.pdf

Efficient AI · Quantization notes

Quantization basics

Quantization is the art of representing many real values using a small set of discrete codes. These notes build from reconstruction error to number formats, linear / affine maps, outliers, rotations, codebooks, and downstream inner products.

Roadmap
  1. What is quantization?
  2. How computers represent numbers
  3. Quantization in ML
  4. Linear and affine quantization
  5. Outliers, clipping, and projections
  6. When linear fails: codebooks
  7. Inner products under quantization

1. What is quantization?

Quantization maps a continuous (or large) set of values to a smaller discrete set. There are two maps to keep track of:

If the only goal is to store and recover data, then a natural metric is reconstruction error. For values drawn from a distribution $P$, this is the mean squared error:

\[ \mathrm{Quantization\ error} = \mathbb{E}_{x\sim P} \bigl[ \| x - Q^{-1}(Q(x)) \|_2^2 \bigr]. \]
Q. Should we always care about reconstruction loss?
A. No — it depends on how the quantized data is used. For example, if we quantize weights $W$, we may care more about the downstream loss or about inner products than about $\|W-\hat W\|_2$.

This distinction is important in ML: a quantizer that looks good by reconstruction error may not be the one that preserves model quality.

2. How computers represent numbers

Computers already quantize numbers: a dtype determines which values are representable. Before designing our own low-bit maps, recall the two basic families of number formats.

(A) Integer formats

Example: signed INT32. Integers are stored in two’s complement (this encoding is for integer formats, not floating point):

(B) Floating-point formats

Formats such as FP16, FP32, FP64 use a sign / exponent / mantissa layout (“$1+e+m$ bits”):

S
E
M
sign
1 bit
exponent
$e$ bits
mantissa
$m$ bits

What does the bit string represent?

Normal numbers ($E \neq 0$, not all-ones)

\[ V = (-1)^{s} \times 2^{n(E)-\mathrm{bias}} \times \bigl(1 + n(0.M)\bigr), \qquad \mathrm{bias} = 2^{e-1}-1. \]

Here $n(E)$ is the integer encoded by the exponent field, and $n(0.M)$ is the fractional value of the mantissa bits.

Subnormals and zero ($E = 0$)

\[ V = (-1)^{s} \times 2^{1-\mathrm{bias}} \times n(0.M). \]

Special numbers ($E$ all ones)

FP16 bit layout and encoding cases

FP16 encoding cases (normals, subnormals, specials).

Precision and range of common dtypes

Common ML dtypes (FP32, BF16, FP16, INT8, …) trade precision (spacing between representable points) against range (max − min representable value).

3. Quantization in ML

FP32 and FP16 are the common “go-to” formats, but efficient ML often pushes further toward smaller bit widths:

\[ \mathrm{FP16,\ FP32} \;\longrightarrow\; \mathrm{FP8,\ INT8,\ INT4,\ \dots} \]
FP8 format overview

FP8-style formats: still floating point, but very low bit width.

The objects we quantize are usually tensors or matrices: weights, activations, KV cache entries, and similar model states.

Example matrix of floating-point values

Either way, once we have a tensor or a calibration distribution, the core design question is how to place a small number of integer codes on the real line.

Q. Given a set of values, how do we design $Q$?

Throughout these notes we work with signed $b$-bit integer codes: there are $2^b$ representable values, with range \[ q \in \bigl\{-2^{b-1},\ldots,2^{b-1}-1\bigr\} \] (e.g. $b=8$ gives $-128,\ldots,127$). How we place those levels on the real line really depends on the data. It helps if a simple parametric map already approximates the data well.

4. Linear and affine quantization

The simplest answer is to use a uniformly spaced grid. Linear quantization stores an integer code and one or two small parameters describing how to convert that code back to a real number.

Why linear?

Symmetric linear map

First assume the data is roughly centered around zero. We can map real values to signed integers using only one scale $\lambda$: $r = \lambda q$, with $q$ in the signed $b$-bit range above. Choose $\lambda$ so the largest magnitude maps to the largest positive code.

\[ r_{\max} = \max_i |x_i|, \qquad q_{\max} = 2^{b-1}-1, \qquad \lambda = \frac{r_{\max}}{q_{\max}}. \]

Using $q_{\max}=2^{b-1}-1$ (rather than $2^{b-1}$) keeps the positive and negative sides symmetric; the most negative code $-2^{b-1}$ is then unused by this particular scale choice.

\[ Q^{-1}(q) = \lambda q, \qquad Q(r) = \mathrm{project}\!\left(\frac{r}{\lambda}\right) \]

Example: $\mathrm{project} =$ round to nearest integer, then clamp into $\{-2^{b-1},\ldots,2^{b-1}-1\}$.

Symmetric linear quantization diagram

Symmetric linear quantization: one scale, zero aligned at zero.

When $r=\lambda q$ is inefficient

Q. When is a pure scale map bad?

When the distribution is shifted / asymmetric: a zero-centered integer grid wastes codes on an empty region of the real line.

Affine (asymmetric) quantization

To move the grid left or right, introduce a zero-point $z_q$ as well as a scale:

\[ r = \lambda(q - z_q). \]

Fit the two parameters by mapping the observed extremes onto the signed code endpoints $q_{\min}=-2^{b-1}$, $q_{\max}=2^{b-1}-1$: $r_{\max}\mapsto q_{\max}$, $r_{\min}\mapsto q_{\min}$.

\[ r_{\max}=\lambda(q_{\max}-z_q), \qquad r_{\min}=\lambda(q_{\min}-z_q). \]
\[ \lambda = \frac{r_{\max}-r_{\min}}{q_{\max}-q_{\min}}, \qquad z_q = q_{\max} - \frac{r_{\max}}{\lambda}. \]

On paper $z_q$ may come out non-integer. In practice one usually rounds $z_q$ to an integer (and may re-fit or slightly adjust $\lambda$) so that dequantization $r=\lambda(q-z_q)$ stays an integer shift in code space — what hardware expects.

Affine linear quantization with zero point

Affine / asymmetric linear quantization (zero-point method).

5. Outliers, clipping, and projections

Q. When can linear quantization still fail?

Outliers. A few extreme values stretch the scale, so most of the mass gets too few effective bits.

Outliers stretching the quantization range

Outliers consume dynamic range that the bulk of the data needs.

(A) Clipping

Clip extreme values before fitting the scale. This is reasonable when outliers are noise or otherwise not important for the downstream task. The tradeoff is clear: we improve resolution for the bulk of the data by deliberately distorting the clipped values.

Clipping outliers before quantization
Effect of clipping on effective bit usage

(B) Rotations

Sometimes the outlier is important, so clipping is too destructive. A different idea is to change coordinates before quantizing. If one coordinate carries too much energy, a rotation can redistribute that energy so no single entry dominates the scale.

Use a simple 3D orthogonal transform that applies a 2D Hadamard rotation to the first two coordinates and leaves the third coordinate unchanged:

\[ R = \begin{bmatrix} \tfrac{1}{\sqrt2} & \tfrac{1}{\sqrt2} & 0 \\ \tfrac{1}{\sqrt2} & -\tfrac{1}{\sqrt2} & 0 \\ 0 & 0 & 1 \end{bmatrix}. \]

What matters for symmetric quantization is the abs-max $\|x\|_\infty=\max_i|x_i|$, since it sets the scale $\lambda$. Rotation “helps” only if $\|Rx\|_\infty < \|x\|_\infty$. Since $R$ is fixed, whether it helps depends entirely on the direction of the data. The next three inputs all have the same energy $\|x\|_2=100$.

Example 1 — isolated outlier: rotation helps

\[ x = [100,\ 0,\ 0] \;\xrightarrow{\;R\;}\; Rx = \left[ \tfrac{100}{\sqrt2},\ \tfrac{100}{\sqrt2},\ 0 \right] \approx [70.7,\ 70.7,\ 0]. \]

The abs-max goes $100 \rightarrow 70.7$ (down by $\sqrt2$). The energy on one coordinate is spread across two coordinates — exactly what we want.

Example 2 — already aligned with the rotation: rotation does not help

\[ x = \left[ \tfrac{100}{\sqrt2},\ \tfrac{100}{\sqrt2},\ 0 \right] \;\xrightarrow{\;R\;}\; Rx = [100,\ 0,\ 0]. \]

The abs-max goes $70.7 \rightarrow 100$ (up by $\sqrt2$). This vector has the same norm as Example 1, but its energy is already aligned with the first row of $R$. The rotation concentrates the energy instead of spreading it.

Example 3 — same outlier, different coordinate: rotation does not help

Now keep the single outlier pattern from Example 1, but move the outlier to the third coordinate, which this particular rotation leaves untouched:

\[ x = [0,\ 0,\ 100] \;\xrightarrow{\;R\;}\; Rx = [0,\ 0,\ 100]. \]

The abs-max stays $100 \rightarrow 100$. Same magnitude, same norm, and still just one outlier — but the outlier is located in a coordinate that $R$ does not mix. Changing where the outlier lives can therefore change whether a fixed rotation helps.

Takeaway Rotation helps when energy is concentrated in a few coordinates that the transform actually mixes (Ex. 1). It does not help when the input is already aligned with a bad direction of the transform (Ex. 2), or when the outlier sits in a coordinate that the transform leaves untouched (Ex. 3). No single fixed rotation is good for all inputs.

Note that all three inputs have the same norm — orthogonal maps preserve it, $\|Rx\|_2=\|x\|_2$. The rotation only redistributes energy across coordinates; it never removes it.

If we knew $x$ in advance, we could choose or learn a better rotation for that particular vector. In ML, however, a transform should work for many inputs. Learning a full $d\times d$ orthogonal matrix for a single $x\in\mathbb{R}^d$ is usually not useful — it becomes worthwhile when one matrix applies to many vectors, e.g. a batch $X\in\mathbb{R}^{n\times d}$ with $n\gg d$, where some channels are consistently outliers.

Randomized projections as a proxy for rotations

Exact random orthogonal matrices are awkward to sample and analyze by hand. A convenient proxy is a randomized linear projection with i.i.d. Gaussian entries. It is not literally a rotation (rows are not exactly orthonormal), but in high dimension it behaves similarly for our purposes and the coordinates of $y=Mx$ are easy to compute with.

\[ M\in\mathbb{R}^{d\times d}, \qquad M_{ij}\ \mathrm{i.i.d.}\ \mathcal{N}\!\left(0,\tfrac{1}{d}\right) \quad\text{(equivalently }M_{ij}=\tfrac{1}{\sqrt{d}}X_{ij},\ X_{ij}\sim\mathcal{N}(0,1)\text{)}. \]

For $y=Mx$,

\[ y_i = \sum_{j=1}^{d} M_{ij} x_j, \qquad E[y_i]=0, \qquad \mathrm{Var}(y_i)=\frac{\|x\|_2^2}{d}, \qquad \mathrm{std}(y_i)=\frac{\|x\|_2}{\sqrt{d}}. \]

So each coordinate is (approximately) $\mathcal{N}(0,\|x\|_2^2/d)$, and $E[\|y\|_2^2]=\|x\|_2^2$. Norms are preserved in expectation (and concentrate in high $d$), even though $M$ is not exactly orthogonal. The useful intuition is that each output coordinate sees many small random contributions, so a single large input coordinate is spread across many outputs.

Exercise Bound $\Pr(y_i > t)$ using Chebyshev and Chernoff, using $y_i\sim\mathcal{N}(0,\|x\|_2^2/d)$.

This “equalizing” effect of random projections is largely an artifact of high dimension.

6. When linear fails: codebooks

Q. Where else does linear quantization fail?

Multimodal distributions. A uniform grid spends codes evenly across an interval, but the data may live in separated clusters with empty space between them.

Linear grid failing on a multimodal distribution

Linear levels miss multimodal structure.

Q. What can we do?

Codebook / clustering approximation: learn a set of centroids $\{c_i\}$ and store each value as the index of its nearest centroid. This gives flexible, data-adapted quantization — but dequantization becomes a table lookup, and arithmetic generally requires dequantizing first.

This is the main tradeoff: codebooks can fit awkward distributions much better than a linearly spaced grid, but they give up some of the hardware simplicity that makes linear quantization attractive.

Weight clustering into codebook indices and centroids

Weight clustering: float weights mapped to low-bit cluster indices plus centroids.

Aspect Linear quantization Codebook (non-linear)
Mapping Affine: $q=\mathrm{round}(x/s)+z$ Lookup: $q=\arg\min_i |x-c_i|$
Reconstruction $x\approx s(q-z)$ $x\approx c_q$
Best for Roughly uniform / unimodal mass Skewed or multimodal mass
Hardware Excellent (integer ops) Moderate / poor
Compute Often stays in quantized space Usually needs dequantization

7. Inner products under quantization

We began with reconstruction error, but in ML the quantized values are usually used inside later computations. The simplest downstream computation to analyze is an inner product.

\[ \hat{w} = w + \Delta. \]
Q. What is $\langle \hat{w},\, x\rangle$, and how well does it approximate $\langle w,\, x\rangle$?

Deterministic rounding to nearest

Assume a grid of precision $\delta$ (spacing between representable values). Round-to-nearest guarantees

\[ |\Delta_i| \le \frac{\delta}{2} \qquad\text{for all } i. \]

The quantized inner product expands as

\[ \langle x,\, \hat{w}\rangle = \sum_i x_i\,(w_i + \Delta_i) = \langle x,\, w\rangle + \sum_i x_i\,\Delta_i. \]

Worst case

If the signs align, every term $x_i\Delta_i$ can push in the same direction. For example, take $x_i \ge 0$ and $\Delta_i=\delta/2$ for all $i$. Then

\[ \bigl|\langle x,\, \hat{w}\rangle - \langle x,\, w\rangle\bigr| = \frac{\delta}{2}\sum_i |x_i| = \frac{\delta}{2}\,\|x\|_1. \]

Squaring gives a worst-case squared error of order

\[ \mathrm{MSE}_{\text{nearest}}^{\text{(worst)}} = \frac{\delta^2}{4}\,\|x\|_1^2. \]

Round-to-nearest minimizes per-coordinate error, but the inner-product error can still accumulate coherently across coordinates.

Stochastic rounding

Suppose $w_i$ lies between consecutive grid points $a < w_i < b$ with $b-a=\delta$. Stochastic rounding sets

\[ \hat{w}_i = \begin{cases} a & \text{with probability } \dfrac{b - w_i}{b - a}, \\[0.6em] b & \text{with probability } \dfrac{w_i - a}{b - a}. \end{cases} \]

Equivalently, $\hat{w}=w+\Delta$ with a random per-coordinate error $\Delta_i$.

Unbiasedness

\[ \mathbb{E}[\Delta_i] = 0 \quad\Rightarrow\quad \mathbb{E}[\hat{w}] = w. \]
\[ \langle x,\, \hat{w}\rangle = \langle x,\, w\rangle + \sum_i x_i\,\Delta_i, \]
\[ \mathbb{E}\!\bigl[\langle x,\, \hat{w}\rangle\bigr] = \langle x,\, w\rangle. \]

The quantized inner product is unbiased.

Variance / MSE

Assuming independent rounding noise across coordinates,

\[ \mathrm{Var}\!\bigl(\langle x,\, \hat{w}\rangle\bigr) = \sum_i x_i^2\,\mathrm{Var}(\Delta_i). \]

With fractional part $\alpha_i=(w_i-a)/\delta \in [0,1]$,

\[ \mathrm{Var}(\Delta_i) = \alpha_i(1-\alpha_i)\,\delta^2 \le \frac{\delta^2}{4}. \]

Therefore

\[ \mathrm{MSE}_{\text{stochastic}} = \mathrm{Var}\!\bigl(\langle x,\, \hat{w}\rangle\bigr) \le \frac{\delta^2}{4}\sum_i x_i^2 = \frac{\delta^2}{4}\,\|x\|_2^2. \]

The bound can be smaller still, depending on the actual fractional parts $\{\alpha_i\}$ and on $x$.

Nearest vs. stochastic

\[ \underbrace{\frac{\delta^2}{4}\,\|x\|_1^2}_ {\text{worst-case nearest}} \qquad\text{vs.}\qquad \underbrace{\frac{\delta^2}{4}\,\|x\|_2^2}_ {\text{MSE stochastic}}. \]

Since $\|x\|_2 \le \|x\|_1 \le \sqrt{d}\,\|x\|_2$, the $\ell_1$ worst case can be up to a factor $d$ larger in squared error than the stochastic $\ell_2$ MSE, especially for dense $x$.

Takeaway. Round-to-nearest is optimal per coordinate, but for the inner product the errors can add coherently. Stochastic rounding keeps the estimate unbiased and replaces an $\ell_1$-scale worst case with an $\ell_2$-scale MSE.
Exercise

Apply Chernoff bounds to the stochastic-rounding estimator $\langle x,\, \hat{w}\rangle$ to show that the error $S=\sum_i x_i\,\Delta_i$ concentrates around zero. Derive a bound of the form

\[ \Pr\!\bigl(|S| \ge t\bigr) \le 2\exp\!\bigl(-f(t,\delta,x)\bigr) \]

for an explicit rate function $f$.

Hint. Each coordinate under stochastic rounding is a shifted Bernoulli random variable, so $S=\sum_i x_i\,\Delta_i$ is a weighted sum of independent Bernoullis. Start from the moment generating function $\mathbb{E}[e^{\lambda S}] = \prod_i \mathbb{E}[e^{\lambda x_i\Delta_i}]$, optimize over $\lambda$, and obtain a Chernoff tail.

Randomness matters Independence of the $\Delta_i$ is what lets the variance sum as $\sum x_i^2\mathrm{Var}(\Delta_i)$, and what licenses an MGF / Chernoff argument. In practice one often wants cheap, high-quality randomness (for example, from hashing-based schemes) so the analysis applies.

Related notes: rotation_outliers.html, prune_a_model_to_quantization.html.