Cheng, Wang, Zhou & Zhang, 2017 (IEEE Signal Processing Magazine)

A Survey of Model Compression
& Acceleration

Your network wins the leaderboard and weighs 240 MB. The phone that has to run it has 2 GB of RAM and a 30 ms latency budget. This survey lays out the four families of techniques that shrink a network by 5–50× without throwing away the accuracy you fought for — pruning & quantization, low-rank factorization, compact filters, and knowledge distillation.

Prerequisites: Neural networks + Matrix multiplication + Convolutions
9
Chapters
5
Simulations

Chapter 0: The Problem

You spend three weeks training a convolutional network. It tops the validation leaderboard. You ship it. And then the mobile team writes back: the model is 240 MB, it allocates 1.2 GB of RAM at inference, and a single forward pass takes 600 ms on the target phone. The product needs 30 ms. The model that won is the model you cannot deploy.

This is not a corner case. It is the default. VGG-16 has 138 million parameters and performs ~15.5 billion multiply-accumulate operations (FLOPs) for one 224×224 image. AlexNet is 240 MB on disk. These numbers were fine for a server with a beefy GPU. They are hopeless on a watch, a drone, a self-driving car's embedded board, or a battery-powered sensor.

The core question this survey answers: Given a trained, accurate, oversized network, how do you produce a smaller, faster network that does almost the same job? And — crucially — which of the many published techniques should you reach for, given your specific constraint (disk size? RAM? latency? energy?)?

Why do big networks even work? Because they are redundant.

Here is the surprising fact that makes compression possible at all: most of the weights in a trained network do almost nothing. Networks are massively over-parameterized. The extra capacity helps during training (it makes the loss landscape easier to optimize), but once trained, a huge fraction of weights are near zero, redundant with each other, or contribute negligibly to the output. Compression is the art of finding and removing that redundancy.

Two numbers measure everything

The survey defines the two yardsticks every compression paper reports. Let a be the parameter count of the original model M, and a* the parameter count of the compressed model M*. The compression rate is:

α(M, M*) = a / a*

A compression rate of 10 means the small model has one-tenth the parameters. Separately, let s be the runtime of M and s* the runtime of M*. The speedup rate is:

δ(M, M*) = s / s*
These two are NOT the same, and conflating them is the #1 beginner mistake. A method can give a huge compression rate (shrink disk size) while barely speeding anything up — and vice versa. Pruning weights to zero shrinks storage but, unless your hardware supports sparse math, the dense matrix multiply still runs at full cost. Conversely, a structural change can speed inference up while shrinking parameters only modestly. Always ask: am I optimizing for size or for time?

Where does the cost actually live?

One more fact that drives every design decision: the cost is not evenly spread across a network.

Layer typeWhere it dominatesWhy
Fully-connected (dense)Parameters (memory)A 4096→4096 layer is 16.7M weights — one matrix, all stored
ConvolutionalFLOPs (compute)Each small filter is reused across millions of spatial positions

In VGG, the fully-connected layers hold ~90% of the parameters but the convolutional layers do ~99% of the compute. So if you need a smaller download, attack the dense layers; if you need lower latency, attack the convolutions. This single asymmetry is why no compression method is universally best — and why this is a survey, not a single algorithm.

A teammate prunes 90% of the weights in a network to zero and reports "10× compression." On the target hardware (a standard GPU running dense matrix multiplies), inference is exactly as slow as before. Why?

Chapter 1: The Taxonomy

Faced with hundreds of compression papers, the survey's central contribution is organization: every method falls into one of four families, distinguished by what kind of redundancy it exploits.

1. Pruning & Quantization
Remove or coarsen individual weights (sparsity + precision redundancy).
2. Low-Rank Factorization
Approximate weight matrices/tensors as products of smaller factors.
3. Compact Filters
Design conv layers to be cheap by construction (architectural redundancy).
4. Knowledge Distillation
Train a small net to imitate a big one (functional redundancy).

The mental model: each family attacks a different kind of waste.

The single most important axis: do you have, or want, a pretrained model? Pruning, quantization, and low-rank operate on a pretrained network — they start big and shrink. Compact filters and distillation are end-to-end — you decide the small architecture up front and train it (distillation borrows the big model as a teacher). This is the first question to ask yourself before reading any paper.

The decision table

The survey itself ends with practical guidance. Here is the gist, which we'll earn chapter by chapter:

FamilyWorks onBest when you needMain drawback
Pruning & Quant.Conv & FCReliable size cut, stable accuracySparse speedup needs special hardware
Low-rankConv & FCEnd-to-end FLOP reductionDecomposition is costly; layer-by-layer only
Compact filtersConv onlyFrom-scratch mobile modelHelps wide nets, not thin/deep ones
DistillationConv & FCSmall/medium data, softmax tasksSoftmax-only; often less competitive
They are orthogonal — and that's the punchline. Because each family attacks a different redundancy, you can stack them. The famous "Deep Compression" pipeline (Han et al.) chains pruning → quantization → Huffman coding to hit 35–49× on AlexNet/VGG with no accuracy loss. You can low-rank-factorize the convs and prune the FC layers of the same network. Compression is not "pick one" — it's "compose a pipeline."
You are handed a network architecture you must train from scratch for a phone — no large pretrained model exists for your task. Which two families are the natural fit?

Chapter 2: Pruning — delete the dead weights

Start with the simplest idea, and the one that started the whole field (LeCun's "Optimal Brain Damage," 1989): if a weight is near zero, it barely affects the output. So set it exactly to zero and stop storing it. Do this to enough weights and the network becomes sparse — mostly zeros — which compresses beautifully.

Magnitude pruning, step by step

The workhorse recipe (Han et al., 2015) is almost embarrassingly simple:

StepWhat you doWhy
1. TrainTrain the dense network normallyGet a good model first; you can only prune what you understand
2. PruneRemove every weight with |w| below a threshold τSmall magnitude ≈ small influence (a learned proxy for importance)
3. Fine-tuneRetrain the surviving weightsThe remaining weights compensate for the deleted ones — this recovers almost all lost accuracy
4. RepeatRaise τ, prune more, fine-tune againIterative pruning beats one-shot — the network adapts gradually
Why fine-tuning is non-negotiable. Pruning without retraining is brutal: you have changed the function the network computes. Fine-tuning lets the surviving weights re-route information around the holes. Han et al. found that one-shot pruning to 90% sparsity destroys accuracy, but iterative prune-then-finetune reaches the same 90% sparsity with no accuracy loss. The lesson: the network is plastic enough to heal, if you let it.

A worked sparsity calculation

Take a fully-connected layer mapping 4096→4096. Its weight matrix is 4096×4096 = 16,777,216 weights at 4 bytes each = 67 MB for one layer. Prune to 90% sparsity (keep 10%):

# Dense layer
dense_params = 4096 * 4096          # 16,777,216
dense_bytes  = dense_params * 4     # 67.1 MB (float32)

# Pruned: keep 10% of weights. But sparse storage needs
# the VALUE *and* the INDEX of each surviving weight.
nnz = dense_params * 0.10           # 1,677,721 nonzeros
sparse_bytes = nnz * (4 + 4)        # value(4B) + index(4B) = 13.4 MB

# Effective compression rate:
ratio = dense_bytes / sparse_bytes  # ≈ 5.0×, NOT 10×
The hidden cost of sparsity. Naively you'd expect 90% pruning → 10× smaller. But a sparse matrix must store, for every nonzero, both its value and its location (row/column index). That index doubles the per-weight cost, so 90% sparsity gives ~5×, not 10×. (Clever index encoding — relative indices, Huffman — recovers much of this, which is exactly why "Deep Compression" adds those stages.)

Unstructured vs structured: the speedup trap

The survey flags this as pruning's biggest practical issue. Two flavors:

The data-flow view. A conv layer's weight is a tensor W ∈ RC_out × C_in × k × k. Unstructured pruning zeros scattered entries — shape unchanged, the matmul is identical-sized. Structured (filter) pruning deletes whole C_out slices — shape becomes RC_out' × C_in × k × k with C_out' < C_out, so the output feature map is literally narrower and every downstream op is smaller. Shape change = real speedup.
Iterative pruning & the accuracy cliff Interactive

Drag the sparsity slider. Watch the weight matrix empty out (gray = pruned). The accuracy curve shows the difference between one-shot pruning (brittle) and iterative prune+finetune (graceful). Toggle fine-tuning to see the cliff move.

Your deployment target is a vanilla mobile CPU with no sparse-matrix library. You need genuine latency reduction, not just a smaller download. Which pruning style should you use?

Chapter 3: Quantization — fewer bits per weight

Pruning removes weights. Quantization keeps every weight but stores each one in fewer bits. A float32 weight uses 32 bits to express a number like 0.0173629. But do you really need that precision? Empirically: no. Vanhoucke et al. showed 8-bit weights barely dent accuracy. The extreme: BinaryConnect uses 1 bit per weight (just +1 or −1).

The two ways to quantize

Worked example: weight sharing math

Take that same 16.7M-weight FC layer. Cluster all weights into k = 16 groups (so each weight becomes a 4-bit index, since 2⁴=16):

# Original
N = 16_777_216
orig_bits = N * 32                  # 536.9 Mbit  (67.1 MB)

# Weight sharing with k=16 clusters → log2(16)=4 bits/index
index_bits = N * 4                  # 67.1 Mbit
codebook_bits = 16 * 32             # 512 bits — negligible
shared_bits = index_bits + codebook_bits

ratio = orig_bits / shared_bits     # ≈ 8.0×

From 32 bits to 4 bits per weight is an 8× compression, and the codebook (16 numbers) is rounding error. With k=256 (8-bit indices) you get 4×; with k=8 (3-bit) you get ~10.7×. You pick k to trade accuracy for size.

Why this works: the loss landscape is flat in many directions. Quantization perturbs every weight slightly. If the network were a knife-edge optimum, this would be fatal. But trained networks sit in wide, flat minima — small simultaneous perturbations to many weights mostly cancel out in their effect on the loss. Quantization-aware fine-tuning then nudges the (now-quantized) weights back to a good spot. This is the same redundancy that makes pruning work, seen from a different angle.

The 1-bit extreme and where it breaks

Binary networks (weights ∈ {−1, +1}) turn multiplies into additions/XNORs — potentially 32× smaller and dramatically faster. But the survey is honest about the cost: aggressive low-precision quantization does drop accuracy on large datasets (ImageNet), and the non-differentiable rounding step complicates training (you need a "straight-through estimator" to push gradients past the round operation). Binarization shines on small models / small datasets and on hardware where the energy win is decisive.

Weight sharing by k-means Interactive

Each dot is a weight on the number line. Change the cluster count k — every weight snaps to its nearest centroid (the colored bars). Fewer clusters = fewer bits = more compression, but each weight drifts further from its true value (the quantization error, shown below). Watch the bits-per-weight and compression rate update live.

Deep Compression uses weight sharing with k=32 clusters. How many bits does each weight cost (ignoring the tiny codebook), and what's the rough compression rate over float32?

Chapter 4: Low-Rank Factorization

Pruning and quantization treat weights as a bag of independent numbers. Low-rank factorization treats a weight matrix as linear algebra and asks: is this matrix really full-rank, or is it secretly the product of two thin matrices? If a 1000×1000 matrix has rank 50, you don't need a million numbers — you need two 1000×50 matrices.

The SVD recipe for a dense layer

Any matrix W ∈ Rm×n factors via the Singular Value Decomposition as W = U Σ VT, where Σ is diagonal with the singular values sorted big-to-small. Keep only the top k singular values (and corresponding columns):

W ≈ Uk Σk VkT  =  (UkΣk) · VkT  =  A · B

Symbol by symbol: Uk is m×k (the dominant output directions), VkT is k×n (the dominant input directions), Σk is the k biggest singular values (how important each direction is). We fold Σ into U to get two factors A (m×k) and B (k×n). The original one layer y = Wx becomes two smaller layers y = A(Bx) with no nonlinearity between them.

Why split one matmul into two? Because the arithmetic collapses. The original Wx costs m×n multiply-adds. The factored A(Bx) costs k×n (for Bx) + m×k (for A times that) = k(m+n). As long as k(m+n) < mn — i.e. k is small — you win. The smaller k is, the bigger the win, until the approximation hurts accuracy.

Worked FLOP-savings example

Take a 4096→4096 layer (m=n=4096) and pick rank k=256:

# Original: one big matmul
orig = 4096 * 4096                 # 16,777,216 multiply-adds

# Factored W ≈ A(4096×256) · B(256×4096)
k = 256
factored = k*4096 + 4096*k        # 1,048,576 + 1,048,576 = 2,097,152

speedup = orig / factored          # ≈ 8.0×  (both FLOPs AND params)
params_orig = 4096*4096            # 16.7M
params_new  = 256*4096 + 4096*256  # 2.1M  → same 8× on storage
The key advantage over pruning: low-rank gives you BOTH compression AND speedup, on ANY hardware, with no special sparse kernels. The two factor matrices are dense — just smaller. Every GPU/CPU runs dense matmuls fast. This is why the survey recommends low-rank (and compact filters) when you need an "end-to-end" solution, not just a smaller file.

Convolutions: the same idea on a 4D tensor

A conv kernel is a 4D tensor W ∈ RC_out×C_in×k×k, not a 2D matrix — so plain SVD doesn't apply directly. The survey covers tensor-decomposition variants: CP decomposition and Tucker / BN low-rank, which break the big convolution into a sequence of tiny convolutions (e.g. a 1×1, then a depthwise k×k, then another 1×1). The reported results on ImageNet:

ModelMethodTop-5 accSpeed-upCompression
AlexNetbaseline80.03%1.0×1.0×
AlexNetCP low-rank79.66%1.82×5.0×
VGG-16baseline90.60%1.0×1.0×
VGG-16CP low-rank90.31%2.05×2.75×
The honest drawbacks (from the survey's Discussion): (1) The decomposition itself is computationally expensive — finding the best rank-k CP decomposition is an ill-posed problem (the best may not even exist). (2) It operates layer by layer: each layer is factored, frozen, and the next is fine-tuned on its reconstruction error. This is local, not global — it can't trade rank budget across layers. (3) It needs extensive retraining to converge.
SVD truncation: rank vs reconstruction Interactive

A weight matrix has a few large singular values and a long tail of tiny ones (left bars). Slide the rank k — you keep the k largest singular values and reconstruct W from them. Watch the reconstruction error fall as k grows, while the FLOP cost rises. The sweet spot is where the curves cross: most energy captured, big compute saved.

You replace a 2048×2048 dense layer with a rank-128 factorization. Roughly what compression/speedup do you get, and on what hardware does it help?

Chapter 5: Compact Filters — cheap by design

The first three families take a big network and shrink it. Compact filters flip the philosophy: don't compress after the fact — design the convolution to be cheap in the first place. This family applies only to conv layers, but conv layers are where the FLOPs live, so it matters enormously for mobile vision.

Idea 1: transferred / equivariant filters (squeeze redundancy out)

The motivating observation (group equivariance theory): CNNs learn redundant filters. The survey writes the equivariance condition as:

T · Φ(x) = Φ(T x)

Symbol by symbol: x is an input, Φ(·) is a layer, T(·) is a transform (rotation, flip, negation). The equation says: transforming the input then running the layer equals running the layer then transforming the output. If that holds, you don't need to learn separate filters for the transformed versions — learn one base filter and generate the rest by applying T. Example (CRELU): lower conv layers learn filters in positive-negative pairs, so define T(W) = −W and store half the filters — an instant compression that also acts as a regularizer (it improves accuracy).

Idea 2: compact blocks (replace expensive convs with cheap ones)

The more impactful, more famous idea — and the foundation of SqueezeNet and MobileNet. The key move: replace a 3×3 convolution with mostly 1×1 convolutions. A 1×1 conv is 9× cheaper than a 3×3 (it touches one spatial position instead of nine).

Worked example: the FLOP cost of a conv layer

The cost of a standard conv is: (output positions) × (kernel size) × (input channels) × (output channels). Take an H×W feature map with C_in=C_out=C channels:

# Standard 3×3 conv, C in / C out, on H×W map
std = H * W * (3*3) * C * C         # = 9·H·W·C²

# Depthwise-separable (MobileNet): 3×3 depthwise + 1×1 pointwise
depthwise  = H * W * (3*3) * C      # 9·H·W·C   (each channel separately)
pointwise  = H * W * (1*1) * C * C  # H·W·C²    (mix channels)
sep = depthwise + pointwise         # 9·H·W·C + H·W·C²

# Speedup ratio for C=128:
ratio = std / sep                   # 9C²/(9C+C²) = 9C/(9+C) ≈ 8.4× for C=128
The trick is to FACTOR the convolution itself. A standard conv does two jobs at once: it filters spatially (the 3×3 footprint) AND it mixes channels (every output channel sees every input channel). Depthwise-separable conv splits these: a depthwise conv filters each channel independently (cheap), then a pointwise 1×1 conv mixes channels (cheap). Same job, ~9× fewer FLOPs. SqueezeNet's "fire module" uses the same spirit — squeeze with 1×1, then expand — to hit AlexNet accuracy with ~50× fewer parameters.
The survey's honest caveat: transferred-filter methods work well on wide/flat architectures (VGGNet, AlexNet) but not on thin/deep ones (ResNet). And the transfer assumption (e.g. "filters come in ± pairs") is a strong human prior — when it doesn't match the data, results become unstable. Compact blocks (depthwise-separable) are the more robust, widely-adopted survivor of this family.
Standard vs depthwise-separable convolution Interactive

Slide the channel count C. The left bar is a standard 3×3 conv; the right is depthwise (3×3 per channel) + pointwise (1×1 mixing). Watch how the gap explodes as C grows — this is exactly why MobileNet stacks separable convs.

Why does a depthwise-separable convolution save so much compute compared to a standard 3×3 conv?

Chapter 6: Knowledge Distillation

The previous four families all manipulate weights — deleting, coarsening, factoring, or constructing them. Distillation changes the target entirely: it ignores the big model's weights and copies its behavior. Train a small "student" network to imitate the outputs of a big "teacher" network. The student ends up far better than if it had been trained alone on the raw labels.

Why imitating the teacher beats learning from labels

Here is the deep idea (Hinton et al.). A hard label says "this image is a dog" — a one-hot vector [0,0,1,0]. But the teacher's softmax output says something richer: "90% dog, 8% wolf, 1.5% cat, 0.5% car." Those small numbers — the "dark knowledge" — encode similarity structure: the teacher has learned that dogs look more like wolves than like cars. A one-hot label throws all of that away.

Soft targets carry more information per example than hard labels. Telling the student "dog, but it's a bit wolf-like and definitely not a car" constrains the student's function far more than "dog." That's why distillation needs less data and trains a small model to accuracy it could never reach from labels alone — the teacher's soft targets are a denser supervision signal.

The temperature softmax, symbol by symbol

To expose the dark knowledge, you "soften" the teacher's softmax with a temperature T:

pi = exp(zi / T) / Σj exp(zj / T)

Here zi are the teacher's logits (pre-softmax scores), and T is the temperature. T = 1 is the normal softmax. T > 1 flattens the distribution — the small probabilities grow, revealing the relative similarities the teacher learned. (At T→∞ everything is uniform; at T→0 it's one-hot.) The student is trained with the same high T to match these softened targets, then deployed at T=1.

The distillation loss, in code

import torch.nn.functional as F

def distill_loss(student_logits, teacher_logits, labels, T=4.0, alpha=0.7):
    # 1. Soft target loss: student matches teacher's softened distribution
    soft_teacher = F.softmax(teacher_logits / T, dim=-1)
    soft_student = F.log_softmax(student_logits / T, dim=-1)
    # KL divergence, scaled by T² to keep gradient magnitudes right
    soft_loss = F.kl_div(soft_student, soft_teacher, reduction='batchmean') * (T * T)

    # 2. Hard target loss: student also matches the true labels
    hard_loss = F.cross_entropy(student_logits, labels)

    # 3. Blend: mostly imitate the teacher, partly trust the labels
    return alpha * soft_loss + (1 - alpha) * hard_loss

Two terms: soft_loss pulls the student toward the teacher's full distribution (the dark knowledge); hard_loss keeps it grounded in the actual ground truth. The factor compensates for the 1/T² shrinkage that dividing logits by T introduces into the gradient — without it, the soft term would be drowned out as T grows.

The survey's two honest limitations: (1) Classic KD only works for tasks with a softmax loss — you need a probability distribution to soften, which excludes regression and many structured tasks. (2) KD-based methods generally achieve less competitive compression than pruning/quantization/low-rank. Its sweet spot is small/medium datasets, where the teacher's transferred knowledge is most valuable. Extensions like FitNets (match intermediate feature maps) and Attention Transfer relax the softmax restriction.
Temperature reveals the dark knowledge Interactive

The teacher's logits for one image are fixed. Slide the temperature T. At T=1 the distribution is sharp (almost one-hot) — the student would learn almost nothing beyond the label. As T rises, the small probabilities swell, exposing that "dog" is also a bit "wolf" — the similarity structure the student actually learns from.

What is the "dark knowledge" that makes distillation work, and what does raising the temperature T do?

Chapter 7: Showcase — the size/accuracy tradeoff

Now the payoff. The whole point of a survey is to let you compare the families on the same footing. Here is one network — pick a family, dial its single knob, and watch where it lands on the size–accuracy plane. The bottom-left is the dream (tiny and accurate); the top-right is where you started.

How to read this. The x-axis is model size (fraction of original). The y-axis is accuracy. The big dot is the original model (top-right: full size, full accuracy). Each family traces a different curve as you compress harder — that curve's shape is the family's character. Pruning&quant stays high then falls off a cliff; low-rank degrades smoothly; distillation can't shrink as far but holds accuracy on small data; compact filters land at a few fixed design points. Combine families (the toggle) to push toward the bottom-left corner no single method reaches.
Compression families on the size–accuracy plane Showcase

Pick a family, slide its compression strength, and read the dot's position. The dashed line marks your minimum acceptable accuracy — anything below it is a failed compression. Toggle "stack" to chain pruning + quantization (the Deep Compression idea) and reach corners no single family can.

The survey's decision guide, distilled

Your situationReach for
Have a pretrained net, need a smaller file, can't change accuracyPruning & quantization — most reliable, stable accuracy
Need a true end-to-end speedup on any hardwareLow-rank or compact filters — dense, smaller ops
Building a mobile model from scratchCompact filters (depthwise-separable) ± distillation
Small/medium dataset, softmax task, have a strong teacherDistillation — transfers knowledge, robust on little data
Domain prior available (e.g. rotation symmetry in medical images)Transferred/compact filters — bakes in the prior
Want the maximum squeezeStack them — they're orthogonal (Deep Compression: 35–49×)
In the showcase, why can stacking pruning + quantization reach the bottom-left corner that neither alone reaches?

Chapter 8: Connections & cheat sheet

You can now read any compression paper and immediately place it: which redundancy does it exploit? Does it start from a pretrained model or train end-to-end? Does it optimize size or speed? Those three questions cover the whole field.

The four families at a glance

FamilyExploitsMechanismSize?Speed (any HW)?
PruningSparsityZero out small weights, fine-tuneYesOnly if structured
QuantizationPrecisionFewer bits / weight sharingYesYes (int math)
Low-rankLinear-algebra rankSVD / tensor decompositionYesYes (dense)
Compact filtersArchitectural wasteDepthwise-separable, 1×1, transformsYesYes (dense)
DistillationFunctional behaviorStudent mimics teacher's soft outputsYesYes (small net)

The equations cheat sheet

QuantityFormulaMeaning
Compression rateα = a / a*Original params ÷ compressed params
Speedup rateδ = s / s*Original runtime ÷ compressed runtime
Low-rank FLOPsk(m+n) vs mnWin when rank k < mn/(m+n)
Weight sharing bitslog₂(k) per weightk clusters → codebook + indices
Separable conv9C+C² vs 9C²Depthwise + pointwise vs standard 3×3
Temperature softmaxpᵢ = e^(zᵢ/T) / Σ e^(zⱼ/T)T>1 softens, reveals dark knowledge

What to study next

The one idea to keep. Big networks work because they're redundant — and that same redundancy is exactly what makes them compressible. Every family is a different lens on the same fact: most of the network isn't pulling its weight. Compression is the discipline of finding which parts are, and keeping only those. And because each family finds a different kind of slack, the real power is in composing them.
"There are no golden criteria to measure which approach is the best. How to choose a proper method really depends on the applications and requirements."
— Cheng, Wang, Zhou & Zhang (2017)