Embedded Machine LearningPhD course

Session 3 · page 2 of 2

Model compression: quantization, pruning and distillation

Four families of technique that make a trained network smaller and cheaper: fewer bits per number, fewer numbers, a small model taught by a large one, and lower-rank or shared weights. Each is derived from its objective, tested against what the hardware can actually exploit, and linked to the landmark papers of presentation topics A and B.

Session3 (continued)
Prerequisitespage 1 of Session 3
SlidesPDF · HTML
Presentationstopics A and B

Part EAn overview of compression

A trained network is usually far larger and more precise than it needs to be. Compression removes that excess — but each technique removes a different kind of excess, needs a different amount of retraining, and pays off only on hardware that can exploit it.

3.21Four families, one question

FamilyWhat shrinksTypical gainRetrainingPays off when
Quantizationbits per weight and activation4× memory (fp32 → int8), 2–4× speed on int8 SIMD/NPUnone (PTQ) to full (QAT)almost always — the default first step
Pruningnumber of weights, or whole channels2–10× weights (unstructured); 1.5–3× compute (structured)fine-tuning, often iterativestructured: always; unstructured: only with sparse kernels or hardware
Knowledge distillationthe model itself — a smaller student replaces the teacherwhatever the student architecture allowstrain the studentyou can afford a training run and have a good teacher
Low-rank / weight sharingrank of weight matrices; distinct weight values2–5× on large dense layers; codebook storagefine-tuninglarge dense or attention layers; storage-limited flash

Table 3.6 — The compression families. Gains are typical orders of magnitude reported in the literature for vision and audio CNNs; they vary widely by model and task.

The techniques compose. The classic pipeline of Deep Compression (Han, Mao and Dally, 2016) prunes, then quantizes the survivors by clustering, then entropy-codes the result; a modern embedded flow is more often "choose an efficient architecture, distil it from a large teacher, prune channels if latency is still too high, and quantize to int8 last". The order matters, because each step changes the statistics the next one relies on — a closing section returns to this.

Part FQuantization

In one sentence

Quantization replaces a per-value exponent with one scale shared by a whole tensor — which is why it is so cheap in silicon, and exactly why it breaks whenever the values in a tensor are not of comparable size.

3.22Number formats

FormatBitsRange / precision characterEmbedded relevance
float3232Huge dynamic range, ~7 decimal digitsTraining reference; rarely deployed on MCUs
float1616Narrow exponent; overflows and underflows easilyGPU inference; needs loss scaling in training
bfloat1616float32's exponent, 8-bit mantissaDrop-in for training; little benefit on MCUs without hardware
int8 (affine)8256 uniformly spaced levels over a chosen rangeThe workhorse. Universally supported by embedded runtimes
int4 / int24 / 2Very coarse; usually weights onlyNeeds QAT or careful PTQ; strong on LLM weights
Qm.n fixed point16 / 32Fixed binary point, no per-tensor scaleClassic DSP style; still used in hand-written kernels
Binary / ternary1 / ~1.6Sign onlyExcellent on FPGAs; large accuracy cost on hard tasks

Table 3.7 — Formats. Note the structural difference: floating point spends bits on an exponent to get dynamic range per value; integer quantization spends a single shared scale to get dynamic range per tensor. Quantization works precisely because activations and weights within a tensor have similar magnitudes — and it fails exactly when they do not.

exponent · 8 mantissa · 23 float32 — 32 bits per value: sign · exponent · mantissa exponent · 8 mantissa · 7 bfloat16 — same exponent range, coarser steps magnitude, 8 bits — plus ONE scale s and zero-point z shared by the whole tensor · 8 int8 affine — 8 bits per value float: each value carries its own exponent → wide dynamic range, per-value int8: one shared scale → uniform steps, and the whole scheme works only because values inside one tensor have similar magnitudes. When they do not — depthwise channels, transformer activation outliers — quantization fails.
Fig 3.24Two ways to spend bits. Floating point buys dynamic range per value with an exponent field, which is why it tolerates a tensor spanning ten orders of magnitude. Integer quantization buys it per tensor with a single shared scale, which is far cheaper in silicon — an int8 multiply costs roughly a twentieth of an fp32 one (Table 1.3) — but rests entirely on the assumption that values inside a tensor are of similar size. Every quantization failure in §3.29 is that assumption breaking.
Foundations · two's complement and Q-format fixed point

Two's complement is how every integer in this chapter is stored. An N-bit word represents −2N−1 … 2N−1−1; negation is “invert all bits and add one”, which is what makes addition and subtraction the same circuit for signed and unsigned values. Two practical consequences appear in real kernels: the range is asymmetric — int8 runs from −128 to +127, so a symmetric quantizer usually restricts itself to ±127 and wastes one level — and addition wraps silently on overflow, which is why quantized kernels accumulate in int32 and use saturating instructions at the boundaries.

Q-format fixed point is the older sibling of affine quantization. Qm.n means an integer interpreted with n fractional bits, i.e. a scale fixed at 2−n — so Q1.15 covers [−1, 1) in steps of 2−15. Multiplying Q1.15 by Q1.15 gives Q2.30, which is why DSP kernels accumulate in 32 bits and shift down at the end.

Affine quantization is exactly this idea with two generalisations: the scale is an arbitrary real number rather than a power of two, and a zero-point lets the representable range be off-centre. The power-of-two restriction is what let 1990s DSPs implement rescaling as a shift; §3.24's M = 2−nM₀ is the modern compromise that recovers the shift while keeping an arbitrary scale.

3.23The affine map depth

Derivation

We want to represent real values x in a range [α, β] using b-bit integers q ∈ [Qmin, Qmax] by an affine relation

x ≈ s · (q − z) (de-quantization) q = clamp( round(x/s) + z , Q_min , Q_max ) (quantization)

Requiring that α maps to Qmin and β to Qmax gives

s = (β − α) / (Q_max − Q_min) z = round( Q_min − α / s )

The zero-point z is an integer, and that is not a detail: it guarantees that the real value 0 is represented exactly. Zero must be exact because padding introduces zeros, and an inexact zero would inject a bias at every image border and every masked position.

Symmetric quantization sets z = 0 and s = max|x| / (2b−1 − 1). It wastes half the range for a strictly positive tensor such as a post-ReLU activation, but it removes the cross-terms in §3.24 and is therefore preferred for weights. The standard combination in deployment toolchains is symmetric per-channel weights, asymmetric per-tensor activations.

Worked example

A weight tensor spans [−0.62, 0.48]; quantize to int8 asymmetric, so Qmin = −128, Qmax = 127.

s = (0.48 − (−0.62)) / 255 = 1.10 / 255 = 4.3137e−3 z = round(−128 − (−0.62)/4.3137e−3) = round(−128 + 143.73) = 16 x = 0.31 → q = round(0.31/4.3137e−3) + 16 = round(71.86) + 16 = 88 x̂ = 4.3137e−3 · (88 − 16) = 0.3106 error 5.9e−4 x = −0.62 → q = round(−143.73) + 16 = −128 (clamped exactly) x = 0 → q = 16, x̂ = 0 exactly

Maximum representation error is s/2 = 2.16 × 10⁻³, uniform across the range. Compare with float32's relative error: quantization error is absolute, so small values suffer proportionally far more. This is why the distribution of a tensor, not just its extremes, determines quantization damage.

real axis — a weight distribution with its chosen clipping range α β clipped clipped z (real 0, exactly) s — one integer step int8 grid Two error sources, traded against each other by the choice of α and β: wide range → small clipping error, large rounding error (s/2) · narrow range → the reverse
Fig 3.25Affine quantization. Calibration is the choice of α and β, and it is a bias–variance trade in disguise: clipping a heavy tail costs a few large errors, while keeping it costs a small error on every value. Which is worse depends on the layer, which is why calibration is chosen per tensor by an explicit criterion (§3.26).

3.24Integer-only inference, derived depth

The core result (after Jacob et al., CVPR 2018)

Let the two operands and the output be quantized with their own parameters: r1 = s1(q1 − z1), r2 = s2(q2 − z2), r3 = s3(q3 − z3). For an inner product of length N:

s₃ (q₃ − z₃) = Σ_j s₁(q₁ⱼ − z₁) · s₂(q₂ⱼ − z₂) q₃ = z₃ + M · Σ_j (q₁ⱼ − z₁)(q₂ⱼ − z₂), M = s₁ s₂ / s₃

Everything inside the sum is an integer operation, accumulated in int32. Expanding the product isolates the terms that can be precomputed:

Σ_j (q₁ⱼ − z₁)(q₂ⱼ − z₂) = Σ_j q₁ⱼ q₂ⱼ − z₂ Σ_j q₁ⱼ − z₁ Σ_j q₂ⱼ + N z₁ z₂

The first term is the ordinary integer GEMM. The third term depends only on the weights and folds into the bias at compile time. The second is a row sum of the activations scaled by the weight zero-point z₂, computed once per row and shared across output channels. The fourth is a constant. With symmetric weights (z₂ = 0) the second term vanishes entirely — which is why asymmetric activations with symmetric weights cost nothing extra, and why asymmetric weights would cost one extra reduction per row.

Requantization. The only non-integer quantity is M = s₁s₂/s₃, empirically always in (0,1). Write it as

M = 2^(−n) · M₀ , M₀ ∈ [0.5, 1)

and store M₀ as a fixed-point int32. Multiplying by M is then a widening multiply followed by a rounding right shift by n — pure integer arithmetic, no floating-point unit anywhere in the inference path. This is what "integer-only" means, and it is what allows deployment on cores with no FPU at all.

Where the bias goes. Biases are quantized to int32 with scale s₁s₂ — the same scale as the accumulator — so they add directly into the accumulation with no rescaling. Quantizing a bias to int8 would be a serious error: biases have a much larger dynamic range than weights and are added once, so their storage cost is negligible while their precision cost is not.

3.25Granularity: per-tensor, per-channel, per-group

One scale for a whole tensor assumes its values share a magnitude. For ordinary convolutions this is roughly true. For depthwise convolutions it is false: each channel has its own independent filter, and after batch-norm folding the per-channel weight ranges can differ by two orders of magnitude. A single per-tensor scale sized for the largest channel then quantizes the smallest channels to a handful of levels — sometimes to all zeros — and the network collapses. This is the standard explanation for the well-documented failure of naive per-tensor PTQ on MobileNet-class architectures, and per-channel weight scales (one s per output channel) fix it at negligible cost, since the requantization multiplier simply becomes a vector.

per-channel weight ranges after batch-norm folding, depthwise layer ch 0ch 1ch 2 ch 3ch 4 one per-tensor scale sized for ch 0 ≈ 30 of 256 levels used ≈ 14 levels — near-total collapse Per-channel scales: one s per output channel, so every channel uses the full integer grid. Cost: a vector of requantization multipliers instead of one scalar — a few hundred bytes, no extra arithmetic in the inner loop. Activations stay per-tensor: their scale must be known before the sum, so a per-channel activation scale would break the shared accumulator.
Fig 3.26Why per-tensor quantization destroys depthwise layers. Because each depthwise channel is an independent filter, folding batch normalisation multiplies each channel by its own factor and spreads the ranges enormously. The fix is granularity, not more bits.

3.26Calibration: choosing the clipping range

MethodChooses α, β to…Behaviour
Min–maxcover the observed extremesSafe but a single outlier ruins the scale
Percentile (e.g. 99.99 %)cover a quantile of the distributionRobust; the percentile is a hyperparameter
MSE / L2minimise E[(x − x̂)²] over candidate rangesPrincipled default; cheap grid search per tensor
KL divergence (entropy)minimise divergence between the float and quantized distributionsTensorRT's classic method; effective on activations
Moving average min–maxtrack ranges over batches during trainingThe standard for QAT

Table 3.8 — Calibration criteria. A few hundred representative samples suffice; what matters is that they are representative — calibrating a keyword spotter on silence produces activation ranges that clip every real utterance.

-1 -0.5 0 0.5 1 min–max range 99.99th percentile 16 of 256 levels shown, min–max 25 outlier weights near 0.9 stretch the min–max range by 3×, so the 5 000 weights near zero get a third of the resolution they could have had. Clipping those 25 costs 25 large errors. Not clipping them costs a small error on all 5 425.
Fig 3.27Calibration is a bias–variance trade in disguise, and this histogram is why it has no universal answer. Choosing the range is choosing between a few large clipping errors and a small rounding error on everything. Which is worse depends on the layer — hence per-tensor criteria such as MSE or KL divergence rather than a single global rule.
InteractiveQuantization playground — a real heavy-tailed weight tensor
step size s–
SQNR–
weights clipped–
storage–
…

Compare min–max with a 99.9 % clip at 3–4 bits, then at 8 bits: clipping wins when levels are scarce and loses when they are plentiful, because the clipped outliers carry real signal. That trade is the whole argument for choosing the range per tensor by an explicit criterion — and it costs nothing at inference.

2 4 6 8 10 12 0 20 40 60 bit width SQNR (dB) MSE-optimal min–max percentile 99.95 +8.9 dB at 2 bits one heavy-tailed weight tensor (5 425 values), three ways to choose the range Clipping pays when levels are scarce (+8.9 dB at 2 bits, +2.5 at 4) and costs when they are plentiful: a fixed percentile clip saturates, because its clipping error never shrinks.
Fig 3.28Why calibration is a choice, not a detail. The same heavy-tailed tensor quantized with three range-selection rules. When levels are scarce, clipping the tail pays: an MSE-optimal range search gains 8.9 dB over min–max at 2 bits and 2.5 dB at 4. When levels are plentiful, the clipped outliers carry real signal: a fixed 99.95th-percentile clip saturates near 37 dB while min–max keeps improving by 6 dB per bit. No fixed rule is best everywhere — which is why toolchains choose the range per tensor by an explicit criterion such as MSE. Per-layer SQNR is also the cheapest diagnostic you have: find the layer where it collapses and you have localised the quantization problem.

3.27Advanced post-training quantization

Cross-layer equalisation. A positively-homogeneous activation such as ReLU satisfies f(αx) = αf(x) for α > 0. So for two consecutive layers you may scale the output channels of the first by a diagonal S and the corresponding input channels of the second by S−1 without changing the function at all. Choosing S to equalise the per-channel ranges makes the network far more amenable to per-tensor quantization — a data-free transformation that recovers most of the gap on MobileNet-class models (Nagel et al., ICCV 2019).

Bias correction. Quantization error has a non-zero mean per channel, E[ΔW·x] = ΔW·E[x] ≠ 0, which shifts every output. Subtracting this expected shift from the bias — using either real data or the batch-norm statistics already stored in the model — removes a systematic error for free.

AdaRound: rounding is a decision, not a function

Rounding to nearest minimises the error of each weight independently. But we do not care about weight error; we care about the error in the layer's output. A second-order expansion of the task loss around the trained weights shows that the relevant quantity couples weights through the Hessian, so the per-weight-optimal rounding is not the jointly-optimal one. AdaRound (Nagel et al., ICML 2020) therefore learns, per weight, whether to round up or down, by optimising a layer-wise reconstruction objective

min over V ‖ W x − Ŵ(V) x ‖² + λ · f_reg(V) Ŵ(V) = s · clamp( ⌊W/s⌋ + h(V) , Q_min , Q_max )

where h(V) ∈ [0,1] is a differentiable relaxation of the rounding decision and the regulariser pushes it toward 0 or 1 by the end of optimisation. It needs no labels and only a small calibration set — a striking amount of accuracy recovered for a few minutes of per-layer optimisation, and the reason "PTQ" now means something much stronger than min–max rounding.

3.28Quantization-aware training

When PTQ is not enough — sub-8-bit weights, activation-sensitive architectures, tight accuracy requirements — simulate quantization during training.

Fake quantization. Insert x̂ = s·(clamp(round(x/s)+z) − z) into the forward pass while keeping a float32 master copy of the weights. The forward pass now sees the quantization error, so the optimiser can route around it.

The straight-through estimator

round(·) has zero derivative almost everywhere, so the gradient would vanish. The straight-through estimator (Bengio et al., 2013) simply defines the backward pass of the rounding node to be the identity inside the clipping range and zero outside:

∂x̂/∂x := 1 if Q_min ≤ x/s + z ≤ Q_max 0 otherwise

This is a biased estimator of a gradient that does not exist — and it works, reliably, which is one of the more interesting unexplained facts in the area. Note the clipping behaviour: weights pushed outside the range receive no gradient and can never come back, so range selection interacts with trainability.

Learned step size quantization (LSQ). Esser et al. (ICLR 2020) treat the step size s as a trained parameter, differentiating through the quantizer with respect to s:

∂x̂/∂s = −x/s + round(x/s) inside the range = Q_min or Q_max outside

with a gradient scale of 1/√(N·Qmax) to balance the step-size gradient against the weight gradients. LSQ reaches state-of-the-art accuracy at 2–4 bits and made low-bit QAT routine rather than heroic.

Practicalities. Batch norm must be folded during QAT, not after, or training and inference graphs differ. Freeze the batch-norm statistics part-way through. Start from a trained float model — QAT from scratch is slower and no better. Budget 10–20 % of the original training epochs.

3.29Below 8 bits, and mixed precision

Weights tolerate low precision better than activations, because activations must accommodate input-dependent outliers while weights are fixed after training. Hence the standard asymmetry: 4-bit weights with 8-bit activations (W4A8) is often nearly free with a good method, while 4-bit activations usually requires QAT. Binary and ternary networks (BinaryConnect, XNOR-Net) reduce the multiply to a sign flip and are compelling on FPGAs, at an accuracy cost that is small on easy tasks and large on hard ones.

Mixed precision assigns different bit widths to different layers according to sensitivity. Sensitivity can be measured directly (quantize one layer at a time and record the accuracy drop) or estimated from second-order information — layers with large Hessian eigenvalues are more sensitive, the basis of the HAWQ family of methods. The practical recipe: measure per-layer sensitivity, keep the first and last layers at higher precision (they usually are the most sensitive, and they are usually small), and spend the remaining budget where the sensitivity curve is flattest.

Quantization bugs, in order of how often they occur
  1. Calibration data unrepresentative of deployment — the single most common cause of "quantization broke my model".
  2. Per-tensor scales on a depthwise-separable architecture (§3.25).
  3. Batch norm not folded, or folded after calibration rather than before.
  4. Biases quantized to 8 bits instead of 32.
  5. Concatenation of tensors with different scales without re-scaling — a silent accuracy loss with no error message.
  6. Accuracy measured on the float model but latency on the quantized one, or vice versa.
  7. Residual additions where the two branches carry different scales.

Diagnose by computing per-layer signal-to-quantization-noise ratio, 10 log₁₀(‖y‖²/‖y − ŷ‖²), on a calibration batch and finding the first layer where it collapses. Debugging quantization is a localisation problem, and this is the localiser.

Part GPruning, sparsity and low rank

In one sentence

Removing weights is easy and removing them usefully is hard: the sparsity pattern that costs the least accuracy is exactly the pattern that no ordinary processor can exploit.

3.30Taxonomy

Unstructured highest accuracy per weight removed needs indices; rarely faster 2:4 semi-structured exactly 2 of every 4 fixed pattern, small metadata real speedup where hardware supports it Structured (channels) result is a smaller dense network speedup everywhere, no special support Accuracy per removed weight falls left to right. Realised speedup rises left to right. Choose by which you are short of.
Fig 3.29The three sparsity regimes. Shaded cells are pruned. Unstructured pruning removes the most parameters for a given accuracy but produces a matrix no ordinary kernel can exploit; structured pruning removes whole channels and yields a smaller dense model that every runtime already handles; N:M is the engineered compromise that some hardware decodes directly.
0 25 50 75 90 99 45 55 65 75 unstructured structured (channels) int8 + 8-bit index: sparse format is BIGGER sparsity — % of weights removed accuracy (%) schematic shapes — the crossover position is what matters, not the exact values Unstructured keeps accuracy longer; structured is what makes the device faster. Below 50 % sparsity in int8, unstructured pruning makes the model bigger and no faster.
Fig 3.30The two curves that must be read together with the two costs. Unstructured pruning dominates on accuracy per removed weight, and delivers nothing on a commodity core until very high sparsity; structured pruning gives up accuracy sooner and produces a smaller dense network that every runtime already executes faster. The shaded band is the arithmetic of §3.33: with int8 values and 8-bit indices you must remove more than half the weights before the sparse representation is even smaller. Curve shapes are schematic; the crossover reasoning is not.

3.31Saliency: which weights can go depth

Magnitude. Remove the smallest |w|. Justified if all weights have comparable influence, which after batch-norm folding they roughly do within a layer. It is embarrassingly effective and remains the baseline everything is compared against.

Optimal Brain Damage, derived

Expand the loss around a trained (hence near-stationary) parameter vector:

δL = Σ_i g_i δw_i + ½ Σ_i h_ii δw_i² + ½ Σ_{i≠j} h_ij δw_i δw_j + O(δw³)

At a minimum the gradient g vanishes, so the first term drops. LeCun et al. (1990) additionally assume the Hessian is diagonal and neglect higher orders. Deleting weight i means δwi = −wi, so the predicted loss increase — the saliency — is

s_i = ½ h_ii w_i²

This says something magnitude pruning misses: a large weight in a flat direction is safe to remove, and a small weight in a sharply curved direction is not.

Optimal Brain Surgeon (Hassibi & Stork, 1993) drops the diagonal assumption and additionally allows the remaining weights to be updated to compensate. Solving the constrained problem gives the saliency and the compensating update

s_q = w_q² / (2 [H⁻¹]_qq) δw = − (w_q / [H⁻¹]_qq) · H⁻¹ e_q

which is more accurate but requires the inverse Hessian — infeasible for large models, though modern approximations of exactly this idea (layer-wise, with efficient Hessian estimates) underpin current one-shot pruning and quantization methods for large models.

First-order criteria. When the model is not at a stationary point — during training, or after fine-tuning on new data — the gradient term does not vanish and |giwi| is an effective and cheap saliency, widely used for structured channel pruning.

3.32Schedules, and the lottery ticket

One-shot pruning removes the target fraction at once and fine-tunes. Iterative magnitude pruning alternates prune-and-retrain in small steps and consistently reaches higher sparsity at the same accuracy, because the network is given the chance to redistribute function into the surviving weights.

The standard automated schedule (Zhu & Gupta, 2017) increases sparsity from si to sf with a cubic profile — fast at first, when there is slack, then slow:

s_t = s_f + (s_i − s_f) · ( 1 − (t − t₀) / (n·Δt) )³ , t ∈ [t₀, t₀ + nΔt]

The lottery ticket hypothesis (Frankle & Carbin, ICLR 2019) states that a randomly initialised dense network contains a sparse subnetwork which, trained in isolation from the same initialisation, matches the full network's accuracy in comparable time. The procedure is: train, prune by magnitude, reset the survivors to their original initial values, retrain, repeat. On MNIST and CIFAR-10 the winning tickets found were typically 10–20 % of the original size.

The claim matters because it separates two things usually conflated: whether a sparse architecture is sufficient, and whether a particular initialisation of it is trainable. Read the critiques alongside it: results are sensitive to learning-rate schedule and require rewinding to an early-training checkpoint rather than to initialisation on larger models; and Liu et al. ("Rethinking the Value of Network Pruning," ICLR 2019) argue that for structured pruning, retraining the discovered architecture from scratch often matches the inherited weights — which would make pruning a form of architecture search rather than a form of weight selection. This tension is one of the central debates of the pruning literature, and a good subject for a presentation in topic B.

3.33The systems reality: when does sparsity pay?

Break-even sparsity for storage

Store a sparse matrix in compressed-sparse-row form: for each non-zero, one value and one column index; plus one row pointer per row. With bv bits per value and bi bits per index, and a fraction σ of weights surviving, the sparse representation is smaller than the dense one when

σ · (b_v + b_i) < b_v ⇒ σ < b_v / (b_v + b_i)

For float32 values with 16-bit indices: σ < 32/48 = 0.67, i.e. any sparsity above 33 % saves storage. For int8 values with 8-bit relative indices — the embedded case — σ < 8/16 = 0.5: you need to remove more than half the weights before the sparse format is even smaller, let alone faster. Combining quantization with unstructured sparsity is therefore much less attractive than combining it with structured sparsity, and this arithmetic is the reason most microcontroller deployments use structured pruning only.

And speed is harder than size. Skipping a multiply saves ≈0.2 pJ (Table 1.3); the index decode, the irregular load, and the lost vectorisation typically cost more. General-purpose cores need very high sparsity — commonly cited thresholds are around 80–90 % — before a sparse kernel beats a dense one. This is exactly why N:M semi-structured sparsity was introduced: constraining exactly N of every M consecutive weights to be non-zero gives a fixed, tiny metadata format that hardware can decode at full rate, delivering a real speedup at a modest 50 % sparsity. It is a design in which the statistics were bent to fit the hardware, and it is worth recognising as such.

InteractiveDoes sparsity actually save anything?
dense–
sparse (CSR)–
compression–
break-even sparsity–
…

Set the values to 32-bit and the break-even drops to 20 % (33 % with 16-bit indices). Quantize to 8-bit and it rises to 50 %. Compressing one way makes the other way harder — a general pattern worth remembering.

3.34Structured pruning

Removing whole output channels, filters, attention heads or layers changes the shape of the tensors, so the result is an ordinary smaller network that any runtime executes faster. Criteria in use:

  • Filter norm — remove filters with the smallest L1 norm (Li et al., ICLR 2017).
  • Batch-norm scale — add an L1 penalty on the BN γ parameters during training; channels whose γ goes to zero contribute nothing and are removed (network slimming). Elegant, because the pruning criterion is trained rather than imposed.
  • Taylor / gradient-based — estimate each channel's contribution to the loss directly.
  • Learned or searched ratios — AMC (He et al., ECCV 2018) uses reinforcement learning to choose a per-layer sparsity ratio against a hardware latency constraint, which is really a form of architecture search and a natural bridge to neural architecture search (§3.20).

A practical caution: uniform per-layer ratios are almost always wrong. Early layers have few parameters but dominate the MAC count; late layers have most of the parameters and little compute. Pruning uniformly optimises neither budget.

3.35Low-rank and tensor factorisation

When does a low-rank factorisation help?

Replace a dense layer W ∈ ℝDout×Din by W ≈ UV with U ∈ ℝDout×r, V ∈ ℝr×Din. Cost falls from DinDout to r(Din + Dout), so the factorisation is worthwhile only when

r < D_in · D_out / (D_in + D_out)

For a 1024×1024 layer that means r < 512: you must discard at least half the spectrum before you gain anything. Truncated SVD gives the optimal rank-r approximation of W in Frobenius norm — but the optimal approximation of the weights is not the optimal approximation of the function, so fine-tuning after factorisation is not optional.

For convolution kernels, which are 4-D tensors, the analogous tools are Tucker and CP decompositions; a Tucker-2 decomposition of a k×k×Cin×Cout kernel yields a 1×1 convolution, a smaller k×k convolution and another 1×1 convolution — structurally the same idea as the bottleneck blocks that efficient architectures use by design (§3.17). Note the connection: a well-designed efficient architecture is a factorisation you did not have to discover after the fact.

0 10 20 30 40 0 singular values 8 large values → the real rank the rest is noise index 0 10 20 30 40 0 % 50 % 100 % cost break-even at r = 89 — far to the right of this axis r = 8 → 3 % error relative reconstruction error retained rank r Truncated SVD gives the best rank-r approximation of the WEIGHTS. It does not give the best approximation of the FUNCTION — which is why fine-tuning after factorisation is not optional. Break-even: r < D_in·D_out / (D_in + D_out). For 200×160 that is r < 89.
Fig 3.31Low-rank factorisation, computed. The matrix here really is close to rank 8, so truncating there costs about a fifth of the Frobenius norm and reduces the layer from 32 000 parameters to 2 880. Real trained weight matrices are usually far less obliging: their spectra decay slowly, so the rank you need is above the break-even rank and the factorisation costs more than it saves. Always plot the spectrum before assuming the layer is compressible.

3.36Weight sharing and coding

Cluster the weights of a layer with k-means into 2b centroids, store a b-bit index per weight plus a small codebook, and fine-tune the centroids by summing the gradients of all weights assigned to each. This is weight sharing, and with entropy coding of the indices it forms the second and third stages of Deep Compression (Han et al., ICLR 2016), which reported 35–49× model-size reduction on AlexNet and VGG-16 without accuracy loss.

c0 = -0.80 c1 = -0.27 c2 = +0.10 c3 = +0.74 4 centroids (the codebook) 16 original float32 weights before: 16 × 32 bits = 512 bits after: 16 × 2 bits + 4 × 32 bits = 160 bits → 3.2× smaller in flash But at inference the indices must be decoded back to values before the multiply. Storage compression is not runtime compression. Gradients of all weights sharing a centroid are summed to update that centroid during fine-tuning.
Fig 3.32Weight sharing, the second stage of Deep Compression. Cluster the weights, store a small codebook plus a short index per weight, and fine-tune the centroids by summing the gradients of every weight assigned to them. The compression is real and large. The distinction the figure insists on is the one papers blur: this shrinks the firmware image and the over-the-air update, and does nothing for latency, because the values have to be reconstituted before any arithmetic happens.
The distinction that Deep Compression makes it easy to blur

Huffman coding and weight sharing compress the stored model. They do not make inference faster, because the weights must be decoded before use — and on a microcontroller the decode buffer may not fit. Distinguish carefully:

  • Storage compression — smaller firmware image, cheaper over-the-air update. Huffman, weight sharing, codebooks.
  • Runtime compression — fewer bytes moved and fewer operations executed at inference. Quantization, structured pruning, factorisation.

Papers that report only the first and readers who assume the second are a recurring source of confusion in this field.

Part HKnowledge distillation

In one sentence

A label tells the student one bit; a teacher’s softened output tells it how the whole class space is arranged — and that extra structure costs nothing at inference, because the teacher is thrown away after training.

3.37The idea

A one-hot label says "this is a keyword". A trained teacher's output distribution says "this is 'stop', it is somewhat like 'up', and nothing at all like 'off'". That relative structure over the wrong classes — Hinton's dark knowledge — encodes the teacher's learned similarity metric, and it is a far denser training signal than a single bit per class. The consequence is that a small student trained on teacher outputs can generalise better than the same student trained on the labels alone, sometimes markedly so, and it costs exactly nothing at inference because the teacher is discarded after training.

input x teacher (frozen) large, accurate student small, deployable logits v [8.1, 2.0, 1.7, −3] logits z softmax(v / T) [.71, .13, .11, .05] softmax(z / T) L = αT²·KL(soft) + (1−α)·CE(hard) gradients update the student only — the teacher is discarded after training T > 1 flattens the distribution, revealing the ranking over wrong classes
Fig 3.33Distillation. The temperature is what makes the wrong-class structure visible: at T = 1 the softmax of a confident teacher is nearly one-hot and carries almost no information beyond the label. The T² factor on the soft-target loss is not cosmetic — §3.38 shows why it is required.

3.38The objective, derived depth

Temperature and the T² factor

With teacher logits v and student logits z, define softened distributions pi = softmax(v/T)i and qi = softmax(z/T)i. The distillation loss is

L = α · T² · KL(p ‖ q) + (1 − α) · CE(y, softmax(z))

Differentiating the cross-entropy of the softened student against the softened teacher gives

∂L_soft / ∂z_i = (1/T) · ( q_i − p_i )

so the soft-target gradient shrinks as 1/T — and after the softening also compresses the logit differences, the effective magnitude falls as 1/T². Multiplying the soft term by T² restores it to the same scale as the hard-label term, so that α means what you think it means and you do not have to retune the learning rate every time you change T.

The high-temperature limit. For large T, expand exp(zi/T) ≈ 1 + zi/T. Assuming logits are zero-meaned per sample, the gradient becomes

∂L_soft / ∂z_i ≈ (1 / (N T²)) · ( z_i − v_i )

i.e. distillation degenerates to least-squares matching of the logits themselves. At low temperature, by contrast, the loss concentrates on the classes the teacher considers plausible and ignores the very negative logits — which is often preferable, since those logits are noisy. The temperature is therefore a knob selecting how much of the teacher's low-confidence structure the student is asked to reproduce.

0.98 T = 1 H = 0.10 stop up off go yes dog 0.82 0.08 0.06 T = 2 H = 0.71 stop up off go yes dog 0.51 0.16 0.14 0.09 0.06 T = 4 H = 1.43 stop up off go yes dog 0.32 0.18 0.17 0.13 0.11 0.09 T = 8 H = 1.70 stop up off go yes dog teacher logits [8.1, 3.4, 3.0, 1.2, −0.4, −2.1] At T = 1 the teacher says only "stop". At T = 4 it says "stop, and it is much more like up and off than like dog" — a similarity metric the one-hot label never contained. That extra structure is the dark knowledge. It is also why the loss needs the T² correction: softening shrinks the gradient by about 1/T², and the factor puts it back.
Fig 3.34Temperature, computed on one set of logits. The entropy H printed above each panel quantifies how much the teacher is telling the student: at T=1 almost nothing beyond the label, at T=8 a nearly uniform distribution that has started to wash the useful ranking away too. The usable range is in between, which is why T ∈ [2,6] is the standard starting point and why tuning T matters more than tuning α.
InteractiveDistillation temperature — where dark knowledge lives
entropy–
top class–
runner-up–
…

3.39Variants

FamilyWhat is matchedUse when
Response-based (classical KD)Output distributionDefault; architecture-agnostic
Feature-based (FitNets and successors)Intermediate activations, via a learned projectionStudent much deeper/narrower; needs layer pairing
Attention transferSpatial attention maps derived from activationsVision; cheap and robust to width mismatch
Relational KDPairwise distances/angles between samples in embedding spaceMetric learning, retrieval, speaker ID
Self-distillation / born-againSame architecture, previous generation as teacherNo larger model available; still often helps
Online / mutual learningTwo students teach each other during trainingNo pre-trained teacher; one training run
Data-free KDSynthesised inputs matching the teacher's BN statisticsTraining data cannot be shared — a real constraint in medical and industrial work

Table 3.9 — Distillation variants. Feature-based methods are more powerful and much fussier: they require choosing which layers to pair and a projection to reconcile dimensions, and a bad pairing actively hurts.

3.40The capacity gap, and the recipe

A stronger teacher is not always a better teacher. Beyond some gap in capacity the student cannot represent the teacher's function, and forcing it to try produces worse results than distilling from a moderate teacher. The standard remedies are a teacher assistant — distil large → medium → small — or simply selecting the teacher by validated student accuracy rather than by teacher accuracy. Report the pairing, not just the student.

1× 3× 5× 7× 9× 68 70 72 74 76 best teacher for THIS student teacher accuracy student accuracy after distillation teacher capacity, relative to the student top-1 accuracy (%) schematic — the shape is robust, the exact peak is task-specific A teacher the student cannot imitate is a worse teacher, however accurate it is. Remedies: a teacher assistant (large → medium → small), or pick the teacher by student score.
Fig 3.35The capacity gap. Student accuracy is not monotone in teacher accuracy: past some point the student lacks the capacity to represent the teacher's function, and forcing it to try is worse than distilling from a weaker teacher. The practical rule that follows is easy to state and widely ignored — report the pairing, and choose the teacher by validated student accuracy, never by teacher accuracy.
Practical recipe
  1. Train or obtain the teacher. For audio, a pre-trained large model (e.g. a PANNs-class network) is usually better than one you train yourself.
  2. Start with T ∈ [2,6] and α ∈ [0.5, 0.9]. Tune T first; it matters more.
  3. Use the same augmentation for teacher and student inputs, so the targets correspond to what the student sees.
  4. Exploit unlabelled data — it is free supervision under the teacher.
  5. Validate the student, not the agreement with the teacher. High teacher-agreement with low accuracy means you have distilled the teacher's errors.

Order of operations when combining. The reliable pipeline is: train the teacher → distil into the small architecture → structurally prune with fine-tuning under the distillation loss → quantize (PTQ, or QAT with the teacher still supervising). Distillation is particularly effective as the loss during QAT, because the float teacher provides a stable target while the student's forward pass is being perturbed by fake quantization. Doing it in the other order — quantize then distil — throws away the quantized model's calibration and usually has to be redone.

3.41Putting it together: a compression recipe

Faced with a model that does not meet its budget, the following order of operations is a sound default. It is not the only one, and several presentation papers argue for different orders; treat it as the baseline your own method should beat.

  1. Fix the budget and the measurement. Flash, peak SRAM, latency and energy on the target device, measured with the deployment toolchain (Session 4). Compression decisions made on proxy counts — parameters, FLOPs — are routinely wrong.
  2. Choose the architecture first. An efficient family scaled to the budget (Part D) usually beats compressing an inefficient one. If the budget is far away, change the architecture, not the compression ratio.
  3. Distil while you shrink. Train (or fine-tune) the small model with the original float model as teacher. Distillation works best between floating-point models, before any quantization noise is introduced.
  4. Remove structure, not scattered weights. If latency or SRAM still binds, prune channels (structured pruning) and fine-tune, keeping the distillation loss; unstructured sparsity only if the target has sparse kernels or hardware support.
  5. Quantize to int8 last. Post-training quantization with per-channel weights and a calibration set drawn from field-like data. If the accuracy drop exceeds the tolerance, switch to quantization-aware training initialised from the pruned float model — the teacher can stay in the loss.
  6. Go below 8 bits only with evidence. Mixed precision or 4-bit weights if flash binds and the hardware or kernel library supports them; measure, because sub-byte unpacking can cost more time than it saves.
  7. Re-measure on the device after every step, and keep the Pareto front of (accuracy, flash, SRAM, latency, energy) rather than a single "best" model.
199020152016 20182019–202021→ pruning Optimal BrainDamage Learning Wand connections Lottery tickethypothesis pipelines DeepCompression MCUNet /MCUNetV2 quantization Integer-onlyinference AdaRound,LSQ, CLE W4A8, LLMquantization Three lanes, one converging pipeline — and one method that tried to do everything at once
Fig 3.36The compression literature as a lineage, from optimal brain damage to the methods used for large language models today. The presentation topics of Session 5 sample this tree: topic A follows the quantization branch, topic B the pruning and distillation branches.
If you remember one thing from Session 3

Pick the model by the data and the budget; count its parameters, activations and operations; then compress in an order the hardware can cash in: int8 first, structured removal second, distillation to recover, and every claim checked on the device. A compression ratio the target cannot exploit is a number in a paper, not a saving.

Before Session 4
  • B. Jacob et al., "Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference," CVPR 2018. arXiv:1712.05877.The paper behind every int8 deployment toolchain; read §2–3 for the arithmetic derived above.
  • S. Williams, A. Waterman, D. Patterson, "Roofline: An Insightful Visual Performance Model for Multicore Architectures," Communications of the ACM 52(4), 2009.Short, and the single most useful mental model for Session 4.
Discussion questions
  1. Quantization replaces a per-value exponent with a per-tensor scale. Give a layer type for which this is benign and one for which it is harmful, and explain why in terms of the value distributions.
  2. Is pruning a form of weight selection or of architecture search? State the evidence on each side.
  3. Why does a teacher's "dark knowledge" help a student more on some tasks than on others? Construct a task where it cannot help at all.
  4. A paper reports 10× compression with no accuracy loss. List the five questions you ask before believing it is 10× cheaper to run.
Exercises
  1. A tensor has values in [−0.8, 2.4]. Compute scale and zero-point for asymmetric uint8 quantization and for symmetric int8. Quantize and dequantize the value 1.0 in each case and report the error.
  2. Derive the requantization multiplier for an int8 convolution with input scale 0.02, weight scale 0.005 and output scale 0.05, and express it as a 32-bit fixed-point multiplier and shift.
  3. A dense layer of 1024×1024 weights is pruned to 90 % unstructured sparsity and stored in CSR format with 16-bit indices. Compare the storage with the dense int8 version. At what sparsity do the two break even?
  4. A 512×512 weight matrix is replaced by a rank-64 factorisation. Compute the reduction in parameters and MACs, and state when the factorised version could be slower.
Further reading
  • M. Nagel et al., "A White Paper on Neural Network Quantization," 2021. arXiv:2106.08295.The best single reference on Part F; read in full at some point.
  • R. Krishnamoorthi, "Quantizing deep convolutional networks for efficient inference: A whitepaper," 2018. arXiv:1806.08342.The practitioner's companion, with measured accuracy tables.
  • D. Blalock et al., "What is the State of Neural Network Pruning?," MLSys 2020. arXiv:2003.03033.A meta-analysis that every pruning paper should be read against.
  • G. Hinton, O. Vinyals, J. Dean, "Distilling the Knowledge in a Neural Network," 2015. arXiv:1503.02531.Nine pages; the origin of the temperature-scaled objective.