GPT-175B needs 350 GB and five A100s just to answer one question. This survey maps the four families of techniques — quantization, pruning, distillation, low-rank factorization — that crush a billion-parameter model down to something you can actually deploy, and shows exactly what each one costs you.
You have trained — or downloaded — a large language model. It is brilliant. It also will not fit on anything you own. Let's make that concrete with the survey's opening number.
GPT-175B has 175 billion parameters. Each parameter, stored in half precision (FP16), takes 2 bytes. So just holding the weights in memory costs:
An NVIDIA A100 has 80 GB of memory. 350 GB does not fit. You need at least five A100s wired together just to load the model — before you have served a single token, before you have paid for the electricity, before the KV cache for a long prompt eats even more.
Every byte you remove is a byte the model was using to store knowledge. The survey is honest about this: compressed LLMs "continue to exhibit a significant performance gap when compared to their uncompressed counterparts." Compression is a negotiation, not a magic shrink-ray. The whole field is the study of which bytes are safe to remove.
| Win | What it means | Why you care |
|---|---|---|
| Smaller memory footprint | Fewer GB to store the weights / KV cache | Fits on cheaper / fewer GPUs, or on a phone |
| Faster inference (speedup) | Each token generated in less wall-clock time | Lower latency for users; higher throughput |
| Lower energy / cost per query | Less compute and memory traffic per token | Sustainable, affordable deployment at scale |
Notice these can conflict. We will see in Chapter 3 that one popular technique shrinks memory beautifully but actually adds compute. That tension is the texture of the whole field.
Drag the sliders. The orange bar is the model's memory in GB; the dashed line is one A100 (80 GB). Watch how dropping from 16 bits to 4 bits is the difference between "needs a server rack" and "fits on one card." Quantization (Chapter 2) is exactly this lever.
Faced with "make the model smaller," there are only a handful of fundamentally different things you can do to a weight matrix. The survey organizes the entire field into four families. The trick to remembering them is to ask: what am I attacking?
This is the question that decides whether a technique is practical for a 70-billion-parameter model. The survey splits the four families along a second axis: task-agnostic (apply once, works for everything) vs task-based (needs retraining, often per-task).
| Technique | Needs retraining? | Practicality on huge LLMs |
|---|---|---|
| Post-Training Quantization (PTQ) | No (just a calibration pass) | Very high — minutes to hours, no gradients |
| Quantization-Aware Training (QAT) | Yes (full fine-tune) | Expensive — gradients over billions of params |
| Unstructured pruning (SparseGPT) | Often no (one-shot) | High |
| Structured pruning | Usually a recovery fine-tune | Medium (LoRA recovery makes it feasible) |
| Knowledge distillation | Yes (train the student) | Medium — student training cost |
| Low-rank factorization | Sometimes a fine-tune | Medium |
Start with the simplest, most-used idea. Quantization reduces the number of bits used to represent each parameter. A weight stored as a 16-bit float becomes an 8-bit, 4-bit, or even 2-bit integer. The survey's one-line definition: "reducing the number of bits (i.e., precision) in the parameters of the model with minimal loss in inference performance."
You can't just truncate a float. You map a range of real values onto a small set of integer levels. For symmetric INT-b quantization of a weight block with maximum absolute value max|w|:
Symbol by symbol, with intuition:
Quantize the weight block [0.10, −0.40, 0.95, 0.02] to INT4 (symmetric, so levels run −7…+7, i.e. 23−1=7).
| w | w / scale | round → wq | dequant wq·scale | error |
|---|---|---|---|---|
| 0.10 | 0.737 | 1 | 0.1357 | +0.036 |
| −0.40 | −2.948 | −3 | −0.4071 | −0.007 |
| 0.95 | 7.000 | 7 | 0.9500 | 0.000 |
| 0.02 | 0.147 | 0 | 0.0000 | −0.020 |
Two lessons jump out. The outlier 0.95 is preserved exactly (it defined the scale). But the small weight 0.02 got rounded to zero — it had no level to land on. INT4 gave us a 4× memory cut (16 bits → 4 bits) at the cost of erasing the smallest weights. That is the trade in miniature.
Blue dots are the true weights; the horizontal grid lines are the quantization levels; orange dots show where each weight snaps after rounding. Lower the bits to watch the grid coarsen. Hit Add an outlier and see how one extreme weight stretches the grid and ruins resolution for all the small weights — the motivation for Chapter 3.
The survey's first split inside quantization:
Chapter 2 ended on a villain: a single outlier weight stretches the scale and crushes resolution for everyone else. In LLMs this is not rare — it is the defining challenge of low-bit quantization, and the survey organizes PTQ around three targets and the outlier fight.
| Method | Key idea | What it achieves |
|---|---|---|
| GPTQ | Layer-wise quantize, correcting remaining weights with inverse-Hessian info (which weights matter most) | 3-4 bit with minimal loss |
| AWQ | Keep the top ~1% activation-salient weights protected; per-channel scaling | Activation-aware low-bit weights |
| SpQR / SqueezeLLM | Store the few sensitive weights (by L2 / Hessian) in high precision, rest in sparse low-bit | Near-lossless 3-bit, >2× speedup |
| QuIP | Incoherence processing (random orthogonal rotations) so no weight is an outlier | Pushes to 2-bit |
Here is the most elegant idea in the chapter. Activations have brutal outliers; weights are smooth and easy to quantize. SmoothQuant's insight: a linear layer computes Y = X W, and you can rescale by any diagonal s without changing the math:
Choose s to shrink the activation outliers (dividing X by s) while only mildly growing the weights (multiplying W by s). You have migrated the quantization difficulty from activations to weights — where it is much more tolerable. Same output, easier-to-quantize tensors.
Left column: activation channel magnitudes (note the giant outlier). Right column: weight channel magnitudes (smooth). Drag α to migrate difficulty: the activation outlier shrinks while the weights grow a little. Watch the "max range" readouts — at the right α both are comfortably quantizable, and the product X·W is unchanged.
Quantization keeps every weight but stores it cheaply. Pruning takes the opposite tack: identify weights that don't matter and set them to zero, so you can skip them entirely. The catch is in the word "matter" — and in what shape the surviving weights form, because hardware only goes fast on certain shapes.
Naive answer: prune the smallest-magnitude weights (a small number contributes little). But the breakthrough method, Wanda, found magnitude alone is wrong for LLMs. Its importance score multiplies weight magnitude by the norm of the corresponding input activation:
Decode it: |wij| is how big the weight is; ‖Xj‖2 is how large the activations flowing into that weight typically are. A small weight that always multiplies a huge activation still matters a lot; a large weight that only ever sees tiny activations doesn't. Importance = weight × how-much-it's-used. No retraining, no weight updates — and it matches the far more expensive SparseGPT.
Take a group of 4 weights with their input-activation norms. Keep the 2 highest scores, zero the rest.
| weight w | |w| | act norm ‖X‖ | score = |w|·‖X‖ | keep? |
|---|---|---|---|---|
| 0.8 | 0.8 | 0.5 | 0.40 | kept (2nd) |
| 0.1 | 0.1 | 9.0 | 0.90 | kept (1st) |
| 0.6 | 0.6 | 0.3 | 0.18 | pruned |
| 0.3 | 0.3 | 0.4 | 0.12 | pruned |
Look at the second row: the smallest weight (0.1) gets the highest score and survives, because it consistently multiplies a giant activation. A pure-magnitude scheme would have deleted it and kept the larger-but-rarely-used 0.6. That activation term is why Wanda works on LLMs where plain magnitude pruning collapses.
A weight matrix split into 2:4 groups (every 4 weights keeps 2). Brightness encodes the activation norm of each weight's input. Toggle the metric: under magnitude only, big weights survive; under Wanda, small weights that see large activations (bright) survive instead. The kept set differs — and Wanda's keeps more of what the model actually uses.
The previous two families shrink an existing model in place. Knowledge distillation (KD) does something different: it trains a brand-new, smaller model — the student — to imitate a large, capable model — the teacher. The student ends up small and fast, but punches above its weight because it learned from the giant.
The clever black-box methods don't just copy answers — they copy capabilities that only emerge at scale:
The standard distillation loss is forward KL, KL(pteacher ∥ pstudent). MINILLM showed this is wrong for generative LLMs and uses reverse KL instead, KL(pstudent ∥ pteacher). The difference is everything:
| Objective | Behaviour | Effect on a small student |
|---|---|---|
| Forward KL (p‖q) | Mean-seeking: student must cover ALL modes the teacher has mass on | Tries to mimic everything, including low-probability junk it can't represent → spreads thin, hallucinates |
| Reverse KL (q‖p) | Mode-seeking: student focuses mass where the teacher is confident | Concentrates on the major, correct modes → more reliable generation |
The teacher (gray) is a two-bump distribution. The student (teal) is a single bump with limited capacity — it cannot cover both modes. Under forward KL it splays out to cover both and lands in the empty valley (bad samples). Under reverse KL it commits to the dominant mode (reliable samples). This is the core MINILLM argument made visual.
The fourth family attacks the matrix's shape. A weight matrix W is m × n. If it has redundant structure — and trained weight matrices usually do — you can approximate it as the product of two much skinnier matrices:
Define the symbols:
Take a 4096 × 4096 weight matrix and approximate it with rank k = 256:
An 8× reduction — if rank 256 captures enough of W. And the win is double: you also do fewer multiplies at inference, because Wx becomes U(Vx) — two cheap skinny matmuls instead of one fat one.
Plain SVD minimizes the error in W itself. But the survey notes ASVD's key finding: what matters is the error in the output Wx, and the activation distribution x is wildly uneven across channels. ASVD scales W by a diagonal matrix reflecting activation magnitudes before the SVD — so the decomposition spends its precious rank on the directions the activations actually probe. Same pattern as AWQ and SmoothQuant: let the data, not the weights alone, decide what to protect.
Left: a 64×64 weight image. Right: its rank-k reconstruction using the top-k singular values. The bar strip shows the singular-value spectrum (which "ingredients" you're keeping in teal vs discarding in gray). Drag k: at low rank you keep only the dominant structure (high compression, blurry); raise it and the reconstruction sharpens while compression drops. The fast decay of the spectrum is why low-rank works.
You now know all four families. The real engineering question is never "which one is best?" — it's "given my constraint (a memory budget, a latency target, a hardware platform), which technique gets me there with the least accuracy lost?" This chapter is the survey's comparison tables made interactive.
Each dot is a real method (hover-free: labels shown when space allows). X-axis = compression ratio (right = smaller model); Y-axis = perplexity increase (down = better, lower quality loss). Toggle families on/off. Drag the budget line: everything below it meets your quality bar — among those, the rightmost dot is your best compression. This is how you actually pick a method.
| If you need… | Reach for… | Why |
|---|---|---|
| Max memory cut, no retraining, any model | Weight-only PTQ (GPTQ / AWQ / SpQR) | 3-4 bit ≈ 4-5× smaller, near-zero Δppl, one calibration pass |
| Actual hardware speedup on INT8 | Weight-activation quant (SmoothQuant / LLM.int8()) | Native low-bit matmuls — but handle activation outliers |
| Speedup on standard GPUs via sparsity | 2:4 pruning (SparseGPT / Wanda) | Ampere accelerates 2:4; one-shot, ~50% sparse |
| A genuinely smaller, portable model | Structured pruning + LoRA recovery, or distillation | Fewer params/layers → runs fast anywhere, no special kernels |
| A small model with big-model behavior | Knowledge distillation | Student inherits emergent abilities (CoT, instruction following) |
You cannot pick the rightmost dot in Chapter 7 unless you agree on how to measure both axes. The survey devotes a section to this — and getting the measurement right is where a lot of compression "wins" quietly fall apart.
| Metric | Definition | Gotcha |
|---|---|---|
| Model size | Total number of parameters (× bits) | Params alone ignore precision; report bits too |
| FLOPs | Floating-point ops per inference | Theoretical compute, not real speed |
| MFU | Actual FLOPS ÷ device's peak FLOPS | Where the FLOPs/speed gap hides — low MFU means you're memory-bound, not compute-bound |
| Inference latency | Wall-clock time per response | What users actually feel |
| Speedup ratio | latency(original) / latency(compressed) | Hardware-dependent — unstructured sparsity may give 0× speedup without custom kernels! |
| Compression ratio | size(original) / size(compressed) | Memory win ≠ speed win (weight-only quant) |
A simplified roofline. The diagonal is the memory-bandwidth ceiling; the flat top is the compute ceiling. The dot is your workload's arithmetic intensity. When it sits on the diagonal (low intensity, as in LLM decoding) you are bandwidth-bound — cutting FLOPs slides you left along the roof but achievable performance doesn't rise. Lower the bandwidth limit to see the dot drop: that's why reducing memory traffic, not FLOPs, is what speeds up LLMs.
The survey closes by admitting the field "is still in its early stages." The honest open problems are as instructive as the methods — they tell you where the next breakthroughs (and the current failure modes) live.
This survey is a map of an entire subfield. The deeper you go into any one box, the more you find a dedicated lesson. Here's the whole picture and where to go next.
| Family | Core rule | Key methods · best use |
|---|---|---|
| Quantization | scale = max|w|/(2b−1−1); wq=round(w/scale) | GPTQ, AWQ, SpQR (weight-only); SmoothQuant, LLM.int8() (weight-act); KIVI (KV cache) |
| Pruning | zero low-importance weights; Wanda score = |w|·‖X‖ | SparseGPT, Wanda (unstruct / 2:4); LLM-Pruner, SliceGPT (structured) |
| Distillation | train small student to match teacher; reverse-KL for generative | CoT/ICL/IF distill (black-box); MINILLM, GKD (white-box) |
| Low-rank | W ≈ UV via top-k SVD; compress = mn / k(m+n) | ASVD (activation-aware), LASER (layer-selective) |
| PTQ vs QAT | PTQ = no retraining (calibrate only); QAT = retrain | PTQ for huge LLMs; QAT+PEFT to push sub-4-bit |
| Metrics | compression ratio & speedup vs Δperplexity; watch MFU | FLOPs ≠ speed; memory-bandwidth is the real LLM bottleneck |
# The three weight-touching techniques in one place import torch def quantize(W, bits=4): """Symmetric per-tensor INT quantization.""" qmax = 2**(bits-1) - 1 scale = W.abs().max() / qmax Wq = torch.round(W / scale).clamp(-qmax, qmax) return Wq * scale # dequantized (sim'd low-bit) def wanda_prune_2of4(W, X): """2:4 sparsity, Wanda importance = |w| * ||x||.""" act_norm = X.norm(dim=0) # per-input-channel score = W.abs() * act_norm[None, :] # [out, in] score = score.reshape(W.shape[0], -1, 4) keep = score.argsort(dim=-1)[..., 2:] # top-2 of every 4 mask = torch.zeros_like(score, dtype=torch.bool).scatter_(-1, keep, True) return (W.reshape(W.shape[0], -1, 4) * mask).reshape(W.shape) def low_rank(W, k=256): """Best rank-k via SVD (Eckart-Young).""" U, S, Vh = torch.linalg.svd(W, full_matrices=False) return (U[:, :k] * S[:k]) @ Vh[:k] # == U' V', stores k(m+n) numbers
An LLM is too big to deploy because its weights eat memory (175B params × 2 bytes = 350 GB). Four families fix this. Quantization stores each weight in fewer bits (16→4), bottlenecked by outlier weights/activations — solved by mixed precision (LLM.int8()), salient-weight protection (AWQ), or difficulty-migration (SmoothQuant). Pruning zeros unimportant weights — importance = |w|·‖activation‖ (Wanda), shaped as unstructured/2:4/structured to trade accuracy against hardware speed (SparseGPT prunes 50% one-shot). Distillation trains a small student to copy a big teacher, using reverse-KL so the capacity-limited student commits to confident modes (MINILLM). Low-rank factorization replaces W with U·V via top-k SVD (8× at rank 256), activation-aware (ASVD). You pick among them by plotting compression vs perplexity-loss under your hardware constraint — and the biggest wins stack several together (QLoRA = quant + low-rank).