Visual walkthrough — Quantization (INT8, INT4, GPTQ)
Step 1 — A weight is a point on a ruler; quantizing = snapping to the nearest tick
WHAT. Take one real number, say . A low-bit integer format only allows a handful of evenly spaced values — the grid. Quantizing means moving to the closest grid tick.
WHY. Everything GPTQ does is built on one atomic act: snap a number to a tick and notice the leftover gap. If we understand that gap, we understand the whole method.
PICTURE. In the figure, the amber dot is the true . The cyan ticks are the allowed values, spaced by the step (the distance between two ticks). The white arrow is the jump to the nearest tick .

The naive plan is: snap every weight, throw away every . The gaps pile up and the layer drifts. GPTQ's whole idea is don't throw away — spend it.
Step 2 — A layer's output is a weighted sum; that's the thing we must protect
WHAT. A layer does not care about individual weights — it cares about the number it produces. For one output, it multiplies each weight by its input and adds them:
WHY. We are about to change the weights (by quantizing). The reader must see clearly what we are trying to keep unchanged: not the weights, but . This is the single most important reframing in GPTQ.
PICTURE. Each weight is a lever; each input is how hard that lever gets pushed. The output is the total. Notice the amber lever ( large): a small wiggle in its weight moves a lot. The faint lever ( small): its weight barely matters.

Step 3 — When we snap one weight, the output jumps by a known amount
WHAT. Suppose we quantize just weight (pick one column). Its residual is . The output changes by exactly:
WHY. Because is a plain sum, changing one term by changes the total by that same amount — nothing else moved yet. This is the "damage" we now want to undo using the weights we haven't quantized.
PICTURE. The blueprint shows before (cyan bar) and after snapping weight (amber bar). The gap between the bars is — that gap is what we must erase.

Step 4 — Measuring how weights "talk to each other": the input correlations
WHAT. To cancel , we adjust the remaining weights. But by how much each? That depends on how the inputs overlap. We collect all the inputs (over many calibration samples) into a matrix and form: Here (the Hessian) is a table where entry measures how much inputs and move together.
WHY THIS TOOL, and why the second derivative. Our error is a quadratic in the weight changes — it's a sum of products of two changes (Step 2 was linear, but the squared output error is quadratic). For any quadratic , the object that tells you its curvature — how steeply error rises as you move the weights — is its second derivative, and that equals . So the Hessian is not chosen by taste; it is the thing that captures "if I move this weight, how fast does error grow, and in which coupled directions." See Hessian and Second-Order Methods for the general machinery and Weight Distributions in Neural Nets for why calibration inputs matter.
PICTURE. A heat-grid: bright cells = strongly correlated input pairs, dark cells = independent. The diagonal () is each input's own strength. Off-diagonal brightness is what lets one weight substitute for another.

Step 5 — The correction: spread the residual into the untouched weights
WHAT. After locking weight , GPTQ updates every remaining free weight by:
WHY each piece is there. Read it right-to-left:
- — the residual we must dispose of.
- — the shape of the nudge: it tells each other weight what fraction of the fix to take, based on how it correlates with weight 's input.
- in the denominator — a normaliser so the correction is exactly the right size, no more, no less.
- Minus sign — we are cancelling, pushing opposite to the error.
PICTURE. Weight snaps down (amber). The residual, instead of being discarded, flows as cyan arrows into the neighbouring free weights — big arrow to a strongly-correlated neighbour, thin arrow to a weakly-correlated one. The output bar returns to its original height.

Step 6 — Do it left-to-right until every weight is on the grid
WHAT. Repeat Steps 3–5 marching across columns: quantize weight 1, dump its error into weights ; quantize weight 2 (now including the correction it just received), dump its error into ; continue until the last weight — which has nowhere to pass its error, so it just gets snapped.
WHY greedy and ordered. Once a weight is quantized it is frozen; only future (still-free) weights can absorb error. So each step shrinks the pool of helpers by one. Processing in order keeps the bookkeeping a simple triangular sweep — no weight is ever asked to fix something already locked.
PICTURE. A column of weights; a sweep line moves left→right. Behind it: locked amber ticks. Ahead of it: cyan free weights receiving correction arrows from the weight just processed.

Step 7 — The degenerate cases (never leave the reader stranded)
WHAT & WHY & PICTURE, three edge scenarios drawn side by side:
- The last weight. No free neighbours remain, so its residual cannot be absorbed — it is simply snapped and its error is the one genuine leftover. (Picture: rightmost tick, no outgoing arrows.)
- A dead input, . Then column contributes nothing to (Step 2 said importance input size). Its weight can be rounded freely — handles this because a zero-energy input makes ; GPTQ adds a small damping to the diagonal so stays invertible.
- Perfectly independent inputs ( diagonal). Then has no off-diagonal terms, so there is nobody to pass error to — GPTQ gracefully collapses to plain independent rounding (Step 1 for every weight). Compensation only helps when weights are correlated.

The one-picture summary

The whole derivation on one blueprint: a weight snaps to the grid (Step 1) → this jolts the output (Steps 2–3) → the input-correlation table (Step 4) tells us the cheapest correction → the residual flows into the free neighbours (Step 5) → sweep left-to-right (Step 6) → edge cases handled by damping and the last-weight rule (Step 7). Output preserved; every weight now a low-bit integer.
Recall Feynman retelling — say it back in plain words
I have a row of dials (weights). The machine's answer is the sum of each dial times how hard its knob is pushed (the input). I want to replace every smooth dial with a clicky one that only stops at fixed notches — that saves memory.
If I just clicked each dial to its nearest notch and walked away, all the little clicking errors would add up and the machine would give a wrong answer. So instead I click one dial at a time, and each time I click, I look at the tiny error I made and quietly re-tune the dials I haven't clicked yet so the machine's total answer stays the same. I decide how much each neighbour re-tunes by how similarly their knobs get pushed — that's the correlation table . I sweep left to right; by the end every dial is clicky, yet the machine still answers exactly as before. The very last dial has no friends left to help it, and any dial with a dead knob gets a free pass. That's GPTQ.
Recall Quick self-test
Why do we minimise output error instead of weight error ? ::: Because the network only cares about what the layer produces; two weights with the same rounding error hurt the output very differently depending on their input size . Why does the Hessian appear as ? ::: The output error is quadratic in the weight change; the second derivative (curvature) of is , and here . What does do in the update? ::: It is the shape of the correction — it distributes weight 's residual across the remaining weights in proportion to how their inputs correlate with 's.