COE 592Lecture 4.2Full guide
Pruning ratios, fine-tuning and sparse hardware
The whole lecture on one page, taught concept by concept. Work through the parts in order, mark each concept once you understand it, and open the slide chips when you want the original slides.
- Parts
- 13
- Concepts
- 44
- Slides
- 115
- Reading
- 264 min
Part 01: Where we are: the pruning problem so far
A compact recap of lecture 04-1: pruning as constrained optimization, the granularity spectrum, magnitude as the default criterion and neuron or channel pruning as coarse-grained weight pruning, setting up the two open questions this lecture answers.
3 concepts, slides 1-7
Why this part matters
Every method in this lecture, from sensitivity curves and AMC to NetAdapt, iterative fine-tuning, EIE and 2:4 tensor cores, is either a way of choosing how many nonzeros each layer may keep or a way of exploiting the zeros that choice creates. None of it makes sense unless the pruning problem itself is crisp in your head.
This part is a bridge, not a second lecture. The first seven slides of the deck repeat lecture 04-1 almost word for word, so the aim here is to compress what that lecture settled into one page you can reproduce under exam conditions: the formulation with every symbol defined, the reason the constraint cannot be optimized directly, the magnitude criterion on a 2 x 2 matrix, and the granularity ladder from single weights to whole channels. Expect to be asked for the formulation and for what ||W_P||_0 means, and the edge deployment in your research project starts by deciding a nonzero budget per layer, which is exactly the symbol N below.
By the end you can
- Write the pruning formulation and define L, x, W, W_P, ||W_P||_0 and N.
- Explain why the L0 count is neither a norm nor differentiable, and why that forces heuristic criteria.
- Reproduce the 2x2 magnitude example and state the pruned matrix and its sparsity.
- Place fine-grained through channel pruning on the flexibility versus hardware-friendliness axis.
- Say which of the five questions 04-1 answered and which two this lecture answers.
Take one layer with 16 weights and suppose the deployment budget allows you to keep only 8 of them. Which eight? That single question is the whole of Pruning. Every answer in lectures 04-1 and 04-2 is a different way of choosing those eight, and every hardware trick at the end of this lecture is a way of profiting from the eight zeros that remain.
The general rule states the question as a constrained optimization. Among all weight tensors that have at most N nonzero entries, pick the one that makes the training loss smallest.
Every symbol in the formulation
- L
- The training objective, the same loss the network was trained with, for example cross-entropy
- x
- The input data the loss is evaluated on
- W
- The original dense weights of the trained network
- W_P
- The pruned weights: the same shape as W, with some entries forced to exactly zero
- ||W_P||_0
- The number of nonzero entries in W_P, the L0 norm
- N
- The target number of nonzeros, the budget the pruned network must respect
Read the formula from the inside out. L(x; W_P) asks how badly the network with weights W_P does on the data. The arg min says we want the W_P that makes that number smallest. The constraint says we may only search among tensors whose nonzero count fits the budget. The budget is what connects this formula to the Pruning ratio of the next part: with M weights in the layer and N survivors, the fraction removed is 1 - N / M, so for M = 16 and N = 8 the layer is 50% sparse. The weight count is written M rather than |W|, because |W| below means the element-wise absolute value.
Why nobody solves this formula directly
The formula looks like something you could hand to gradient descent, and that is the trap. The nonzero count is a step function: nudge a weight from 0.30 to 0.31 and the count does not move, set it to exactly zero and the count drops by one. Its gradient is zero almost everywhere and undefined at zero, so no gradient flows through the constraint. Louizos, Welling and Kingma open their ICLR 2018 paper on this exact point: the L0 norm of the weights is non-differentiable, which is why it cannot simply be added to the training objective. Without a gradient, the exact problem is a combinatorial search, choosing which N of the M positions to keep, and for a layer with millions of weights that search is hopeless.
The heuristics are not arbitrary. Every one of them is a proxy for the same quantity: how much would L change if this weight were removed. The constraint side of the formula only fixes the budget; the loss side is what actually decides the answer, so the best criterion is the one whose ranking best tracks the change in loss. That is why the slide on selection later in this part says that the less useful the removed neurons are, the better the pruned network performs. Useful means low loss change, nothing else.
| Model | Before | After | Reduction |
|---|---|---|---|
| AlexNet | 61M | 6.7M | 9x |
| VGG-16 | 138M | 10.3M | 13x |
Recall
Write the pruning formulation and name every symbol.
Recall
Why can you not just run gradient descent on the constraint ||W_P||_0 <= N?
Quick check
In the pruning formulation, what does the term ||W_P||_0 measure?
Quick check
Why do all pruning criteria rank weights by an importance score instead of solving the arg min directly?
The formulation says nothing about how to find good survivors. Lecture 04-1 gave two practical answers, a shape and a score, and slides 4 to 6 of this deck replay them in the space of one minute. Start with the score on the smallest example that still teaches something: a 2 x 2 weight matrix that must lose half of its entries.
Worked example
Magnitude pruning on a 2 x 2 matrix at 50%
Start from the weights
W = [[3, -2], [1, -5]], four weights, two of which must go.Score every weight by its absolute value
Element-wise |W| = [[3, 2], [1, 5]]. The sign is discarded; only distance from zero counts.Keep the N = 2 highest scores
Sorted importances are 5, 3, 2, 1. The top two are 5 and 3, which belong to -5 and 3. The entries scored 2 and 1 are set to zero.Result
W_P = [[3, 0], [0, -5]], with ||W_P||_0 = 2 and sparsity 50%. Notice that -5 survives although it is the most negative weight in the matrix.
This is Magnitude-based pruning, and the slide is honest about its status: it is a heuristic criterion. The assumption is that a weight far from zero contributes more to the output, and therefore to the loss, than a weight near zero. Han et al. (NeurIPS 2015) used exactly this threshold rule to produce the 9x and 13x reductions quoted in the first concept, which is strong evidence that the assumption is usually good enough. It is not the only score. Lecture 04-1, part 05, adds scaling factors such as batch-norm gammas for whole channels, and part 06 adds second-order saliency from Optimal Brain Damage, the percentage of zero activations, and regression-based selection. All of them plug into the same three steps: score, sort, keep the top N.
The shape of what is removed
Scoring weights one at a time and zeroing the smallest gives the pattern the slide calls fine-grained: zeros scattered wherever the small weights happened to be. The pruned network figure on that slide, again from Han et al., shows synapses vanishing at arbitrary positions and whole neurons disappearing once every synapse into them, or every synapse out of them, is gone. Fine-grained removal has the most freedom, since any index may be pruned, and that freedom is what buys it the highest compression ratios. The cost is that the survivors no longer form a dense block. Their positions must be stored as indices, and the hardware needs a sparse kernel that skips the holes. Mao et al. (2017) measured the other end of the trade: coarse-grained pruning reaches a sparsity similar to unstructured pruning without losing accuracy, needs far fewer indices, and saves about 2x the memory references compared with fine-grained sparsity.
| Level | What is removed | Flexibility | Hardware friendliness |
|---|---|---|---|
| Fine-grained | Single weights at arbitrary positions | Highest | Needs stored indices and sparse kernels |
| Pattern-based | Weights in a fixed pattern, such as M:N (for example 2:4) | High | Regular enough for special hardware support |
| Vector-level | One 1-D row of a kernel, W[o, i, r, :] | Medium | Moderate, fewer indices per block |
| Kernel-level | One whole k x k kernel | Lower | Good, whole blocks disappear |
| Channel-level | A whole filter and its output channel | Lowest | Best, the layer simply gets narrower |
That ladder is the Pruning granularity axis, and the two ends pull against each other. Irregular patterns give the criterion freedom and therefore compression; regular patterns give the hardware dense blocks and therefore speed. Every design choice later in this lecture sits somewhere on this axis, and the 2:4 pattern of the tensor-core part is the industry's attempt to sit in both places at once.
Recall
Weights 3, -2, 1, -5, keep half by magnitude: what survives and what is ||W_P||_0?
Quick check
Applying Importance = |W| to 3, -2, 1, -5 and keeping half, which weights survive?
The coarse end of the ladder deserves one concrete picture, because it explains a sentence that students often quote without understanding: Neuron pruning is coarse-grained weight pruning. Slide 6 draws both cases, the linear layer and the convolution layer, and the same picture in matrix form makes the sentence obvious.
Removing a neuron is removing a row
A linear layer computes y = W x with W of shape out x in. Output neuron i is nothing more than row i of W: its incoming weights are the entries of that row, and its output is that row's dot product with x. Deleting the neuron therefore deletes the whole row at once, which is the white stripe in the slide's weight matrix, and the next layer loses the matching column because that input no longer exists. That is neuron pruning, and it is weight pruning where the removed set is a structured block of in weights chosen together rather than one weight at a time. Lecture 04-1, part 06, first drew this equivalence next to Optimal Brain Damage.
The convolution version is the same idea one dimension up. A conv layer holds weights of shape C_out x C_in x k x k. Output channel j is produced by filter j, which is the slice of all C_in kernels that feed it. Deleting a channel deletes that entire filter, the two dashed blocks in the slide's stack of six filters and the two white rows of kernels in its weight grid (two of six output channels removed). That is Channel pruning, and its reward is that nothing sparse is left behind: the layer simply has C_out minus the pruned count of channels and runs on the same dense kernels as before.
| Work | Model and data | Result |
|---|---|---|
| Li et al., ICLR 2017 | VGG-16, CIFAR-10 | Up to 34% fewer FLOPs |
| Li et al., ICLR 2017 | ResNet-110, CIFAR-10 | Up to 38% fewer FLOPs |
| He et al., ICCV 2017 | VGG-16 | 5x speed-up, +0.3% error |
Five questions, three answered
The outline that opens this deck on slide 2, and returns on slide 7 to close this part, lists five questions, and the same outline appeared three times in lecture 04-1. It is the map of both lectures, so it is worth knowing where each question was answered. The formulation above answers the first. Granularity, the pattern of removal, was answered in 04-1. Criterion, the score used to rank weights, was also answered in 04-1. What remains open is how many weights each layer should lose, and how to recover the accuracy once they are gone.
| Question | Asks | Answered in |
|---|---|---|
| Introduction | What is pruning and how do we formulate it? | Lecture 04-1, part 01, and this part |
| Granularity | In what pattern should weights be removed? | Lecture 04-1, parts 03 and 04 |
| Criterion | Which synapses or neurons should go? | Lecture 04-1, parts 05 and 06 |
| Ratio | What target sparsity should each layer get? | This lecture, parts 02 to 05 |
| Fine-tune or train | How do we recover the accuracy we lost? | This lecture, part 06 |
On slide 2 both open questions, ratio and fine-tuning, are highlighted in yellow. On slide 7, which closes this part, ratio turns green while fine-tuning stays yellow: ratio is being opened now, fine-tuning is still queued. The outline also under-sells the deck. After the five questions, parts 07 onward add a story the list never mentions, how EIE, 2:4 sparse tensor cores and sparse convolution engines turn the zeros produced by pruning into real speed and energy savings on hardware.
Quick check
Removing one neuron from a linear layer deletes what from its weight matrix?
Recall
What does removing one neuron of a linear layer do to W, and one channel of a conv layer?
Recall
Which of the five questions did 04-1 answer, and which does 04-2 answer?
Recap
If you remember nothing else
- Pruning: minimize L(x; W_P) subject to ||W_P||_0 <= N, where N is a budget on nonzeros.
- ||.||_0 counts nonzeros. It is not a norm and has no gradient, so every criterion is a heuristic proxy for the change in L.
- Slide 3 mixes < N with <= N and W_p with W_P. Read <= N and one matrix.
- Magnitude criterion: Importance = |W|. Weights 3, -2, 1, -5 at 50% keep 3 and -5.
- Granularity runs from fine-grained (flexible, index heavy) to channel (regular, dense-friendly).
- Neuron pruning removes a row of W. Channel pruning removes a filter. Both are coarse-grained weight pruning.
- 04-1 settled formulation, granularity and criterion. 04-2 answers ratio and fine-tuning, then adds sparse hardware.
Sources
- Learning both Weights and Connections for Efficient Neural NetworkPaperNeurIPS 2015, Han, Pool, Tran and DallyMagnitude threshold pruning with the train, prune, retrain loop; AlexNet 61M to 6.7M (9x), VGG-16 138M to 10.3M (13x).(opens in a new tab)
- Deep Learning, chapter 2: Linear Algebra, section 2.5 NormsBookMIT Press, Goodfellow, Bengio and CourvilleThe so-called L0 norm is incorrect terminology: the nonzero count does not scale with its argument, so it is not a norm.(opens in a new tab)
- Learning Sparse Neural Networks through L0 RegularizationPaperICLR 2018, Louizos, Welling and KingmaStates that the L0 norm of the weights is non-differentiable, the reason it cannot be optimized by gradient descent.(opens in a new tab)
- Optimal Brain DamagePaperNIPS 1989, LeCun, Denker and SollaSecond-derivative saliency as a criterion for removing weights.(opens in a new tab)
- Exploring the Regularity of Sparse Structure in Convolutional Neural NetworksPaperarXiv 2017, Mao et al.Granularity spectrum, index saving, and about 2x fewer memory references for coarse-grained sparsity.(opens in a new tab)
- Pruning Filters for Efficient ConvNetsPaperICLR 2017, Li, Kadav, Durdanovic, Samet and GrafWhole filters removed with their feature maps; FLOP reductions of up to 34% on VGG-16 and 38% on ResNet-110 for CIFAR-10 with dense BLAS.(opens in a new tab)
- Channel Pruning for Accelerating Very Deep Neural NetworksPaperICCV 2017, He, Zhang and SunLASSO-based channel selection; 5x speed-up on VGG-16 with a 0.3% increase in error.(opens in a new tab)
- MIT 6.5940 TinyML and Efficient Deep Learning Computing, Fall 2024DocsMIT HAN Lab, Song HanLectures 3 and 4, Pruning and Sparsity parts I and II, the deck these COE 592 slides follow.(opens in a new tab)
Part 02: Why every layer needs its own pruning ratio
Uniform shrinking loses to non-uniform pruning, so each layer needs its own ratio. Sensitivity analysis measures how much accuracy each layer loses as it is pruned harder.
3 concepts, slides 8-17
Why this part matters
Every embedded deployment you will ship in this course, and every exam question on this lecture, starts from one decision: how much to prune each layer. Get it wrong by treating all layers alike and you pay accuracy at the same latency, about 2.1 points on MobileNet at roughly 70 ms. Get it right per layer and you have the foundation that AMC, NetAdapt and the threshold method in the next part all build on.
Part 01 left two questions open, and this part answers the first: what pruning ratio should each layer get? The answer comes in three moves. First the evidence that one ratio for all layers is a bad idea. Then the reason, which is that layers differ in sensitivity. Then the measurement, a sweep that prunes one layer at a time and records how much accuracy it costs, producing the family of curves that the next part reads ratios from.
By the end you can
- Explain, with the MobileNet numbers, why non-uniform pruning dominates uniform shrinking on accuracy versus latency.
- Define layer sensitivity and Delta Acc, and give three reasons the first layer is usually the most sensitive.
- Carry out the four-step sensitivity sweep and read a sensitivity chart for VGG-11 on CIFAR-10.
- Compute the evaluation cost of a sweep as layers times ratios, and explain why it is evaluation only, not training.
- State what the sweep cannot tell you (interactions between layers), preparing for the threshold and automated methods that follow.
Start with a measurement, not a principle. Take MobileNet on ImageNet and run it on a Google Pixel 1 CPU with TensorFlow Lite. The dense network scores 70.6% top-1 at 123.3 ms per image. Now shrink it two different ways to roughly half the work. The first way multiplies every layer's width by 0.75, the built-in MobileNet knob. The second way, AMC, lets every layer keep a different fraction of its channels (He et al., ECCV 2018, Table 4). MMACs counts millions of multiply-accumulate operations per image, a hardware-neutral measure of compute; a FLOPs target asks AMC to halve that compute, while a latency target asks it to halve measured time on the phone.
| Model | Top-1 | MMACs | Pixel 1 latency |
|---|---|---|---|
| 1.0 MobileNet (dense) | 70.6% | 569 | 123.3 ms |
| 0.75 MobileNet (uniform width multiplier) | 68.4% | 325 | 72.3 ms |
| AMC, 50% FLOPs target | 70.5% | 285 | 68.3 ms |
| AMC, 50% latency target | 70.2% | 272 | 63.3 ms |
Read the middle two rows against each other. At nearly the same latency, 72.3 ms versus 68.3 ms, the per-layer version keeps 2.1 points more accuracy. Read the first and third rows together and the gap is even more striking: AMC's 68.3 ms model loses only 0.1 points against the full network at 123.3 ms. Slide 9 plots the same story as a chart (AMC Figure 5b), and the values read off it land in one table.
| Series | Latency | Top-1 |
|---|---|---|
| Uniform (width or resolution multiplier) | 52 ms | 67.4% |
| Uniform (width or resolution multiplier) | 72 ms | 68.4% |
| Uniform (width or resolution multiplier) | 91 ms | 69.1% |
| Uniform (width or resolution multiplier) | 123 ms | 70.6% |
| AMC (per-layer pruning) | 52 ms | 69.2% |
| AMC (per-layer pruning) | 63 ms | 70.2% |
| AMC (per-layer pruning) | 68 ms | 70.5% |
Every AMC point sits above every uniform point. The uniform line on that chart mixes MobileNet's width multiplier with its input-resolution multiplier, which is why it has four points while Table 4 lists two; either knob shrinks every layer by the same factor.
The two stacks of bars on the slide are the whole idea in one picture. Uniform shrinking keeps every layer the same shape, just thinner: MobileNet's width multiplier alpha "thins a network uniformly at each layer" (Howard et al. 2017, section 3.3). Per-layer channel pruning ends with a ragged stack, some layers barely touched and others cut hard, because each layer got its own pruning ratio.
Why the ragged stack wins
Uniform shrinking rests on a hidden assumption: that every layer has the same slack. It does not. Han et al. (NeurIPS 2015, section 5) found that "the first convolutional layer, which interacts with the input image directly, is most sensitive to pruning", and suspected this sensitivity is "due to the input layer having only 3 channels and thus less redundancy than the other convolutional layers". The AMC paper records the standard hand-crafted rule of thumb that grew from such findings, one it then argues is non-optimal because layers are not independent: "prune less parameters in the first layer which extracts low level features and have the least amount of parameters". To see how little the first layer has to give, count the weights of the first six convolution layers of VGG-11 configuration A (Simonyan and Zisserman 2015, Table 1), each a 3 x 3 kernel over its input channels.
| Layer | Shape | Weights | Left at r = 0.9 |
|---|---|---|---|
| L0 | 3 x 3 x 3 x 64 | 1,728 | 173 |
| L1 | 3 x 3 x 64 x 128 | 73,728 | 7,373 |
| L2 | 3 x 3 x 128 x 256 | 294,912 | 29,491 |
| L3 | 3 x 3 x 256 x 256 | 589,824 | 58,982 |
| L4 | 3 x 3 x 256 x 512 | 1,179,648 | 117,965 |
| L5 | 3 x 3 x 512 x 512 | 2,359,296 | 235,930 |
Prune 90% of L0 and 173 weights are left to describe every edge and colour detector that the rest of the network depends on. Prune 90% of L5 and 235,930 weights remain. A uniform rule takes the same 90% from a 1,728-weight layer and a 2.36-million-weight layer as if both had the same room to spare. This difference in slack is what the lecture calls sensitivity, and the next concept defines it precisely.
Quick check
On slide 9, what does uniform shrinking do to a network?
Recall
Give the MobileNet numbers that show non-uniform pruning beating uniform shrinking at about the same latency.
Here is the same experiment on a network you can count by hand. Train VGG-11 on CIFAR-10 until it reaches about 93% test accuracy. Prune 90% of the weights in L0, the first convolution, and touch nothing else: accuracy falls to about 32%, a drop of about 61 points. RestoreL0, prune 90% of L1 instead: accuracy falls only to about 85%, a drop of about 8. Same ratio, roughly eight times the damage.
That difference is what layer sensitivity measures: how much accuracy the network loses when one layer alone is pruned at a given ratio, with every other layer left dense. Write the dense accuracy as Acc_dense and the accuracy after pruning only layer L_i at ratio r as Acc_r^i. The degradation is their difference.
Plot Acc_r^i against r and a sensitive layer gives a steep curve while a redundant layer gives a flat one. Slide 10 states the two ends of the spectrum: some layers are more sensitive, the first layer being the usual example, and some are more redundant. The word "usual" matters, because sensitivity is measured, not assumed, and the reasons the first layer tends to top the list are worth spelling out rather than memorizing.
Three reasons the first layer is usually most sensitive
- Fewest parameters. VGG-11's L0 has 1,728 weights against 73,728 in L1 and millions further in (VGG Table 1 arithmetic). Every weight removed from L0 is a larger share of what the layer knows.
- Only three input channels. The layer sees raw RGB, so there is little redundancy to absorb a loss. This is the explanation Han et al. (2015) give for AlexNet, where the first convolution was the most sensitive layer in their per-layer sweep (Figure 6).
- Everything downstream depends on it. Every feature in L1 through the classifier is a function of L0's output, so an error introduced there is inherited by every later layer rather than corrected.
Recall
Why is the first layer usually the most sensitive to pruning?
Recall
Write the definition of Delta Acc_r^i in words and as a formula.
If sensitivity is a curve per layer, the procedure to obtain it is fixed by the definition: isolate one layer, vary its ratio, measure, repeat. Slides 12 to 17 build that chart one curve at a time for VGG-11 on CIFAR-10. Here is the procedure as a whole, carried out on L0, then generalized.
Worked example
Sensitivity analysis of VGG-11 on CIFAR-10
Pick a layer L_i in the model
Start with L0, the first convolution, 3 x 3 x 3 x 64 with 1,728 weights. Every other layer stays exactly as trained.Prune only L_i with ratio r in {0, 0.1, 0.2, ..., 0.9}
For each r, apply magnitude-based fine-grained pruning to that one tensor: zero the smallest r fraction of its weights by absolute value. The slide allows "other strides", for example steps of 0.05, at proportionally more cost.Observe the accuracy degradation Delta Acc_r^i for each ratio
Evaluate the pruned model on the CIFAR-10 test set, 10,000 images, 1,000 per class (Krizhevsky). For L0 the readings are about 2 points lost at r = 0.5, 10 at 0.7, 22 at 0.8 and 61 at 0.9.Restore L_i and repeat the process for all layers
Copy the saved dense tensor back so the next sweep starts from the same model, then move to L1, L2 and onward. Plot every layer's curve on the same axes.A family of curves, one per layer
All curves share an x axis (pruning rate) and a y axis (accuracy). Slide 21, in the next part, reads per-layer ratios from this chart by drawing a horizontal threshold across it.
The completed chart on slide 17 is the payoff. Every layer stays close to 93% until about 50% pruning, which tells you that any one layer can lose half its weights while the rest stay dense; whether every layer can lose half at once is a different question, taken up below. Past that point the layers separate. Values below are read off the slide to the nearest point.
| Layer | r = 0.5 | r = 0.6 | r = 0.7 | r = 0.8 | r = 0.9 |
|---|---|---|---|---|---|
| L0 (first conv, blue) | 92 | 88 | 83 | 71 | 32 |
| L1 (green) | 93 | 93 | 93 | 92 | 85 |
| L2 (red, added on slide 15) | 93 | 93 | 92 | 90 | 79 |
| L3 (orange) | 93 | 93 | 91 | 86 | 51 |
| L4 (red, added on slide 17) | 93 | 93 | 90 | 77 | 39 |
Try the sweep yourself. The simulator holds the chart values, lets you pick the layer being pruned and slide its ratio, and reports the accuracy, the drop and how many of that layer's weights are gone. Leave the ratio at 0.9 and switch between L0 and L1 to feel the difference in one click.
Leave the slider at r = 0.9 and switch between L0 and L1: the first layer loses about 61 points, the second about 8. Every point on every curve comes from one evaluation with only that layer pruned and nothing retrained. Values are read from the slide chart to the nearest point, so treat them as approximate.
Why each layer is swept alone
Sweeping one layer while the rest stay dense is what makes the curve interpretable. If two layers were pruned together and accuracy fell, the drop could not be attributed to either one. Isolation buys attribution. It also has a price, which the next part turns into a whole discussion: it assumes the damage from pruning several layers adds up. AMC's authors put it bluntly, the single-layer approach "assumes that errors of different pruned layers can be summed up linearly, which does not stand according to our experiments" (He et al. 2018, section 4). Keep that interaction in mind: the sweep tells you which layers are fragile, not what happens when you prune them all at once.
What the sweep costs
No gradient step runs during a sweep, but every point on every curve is one full pass over the evaluation set. The number of evaluations is the number of layers times the number of ratios, and each evaluation is a forward pass over every test image.
| Network | Layers | Ratios | Evaluations | Images per evaluation | Forward passes |
|---|---|---|---|---|---|
| VGG-11 on CIFAR-10 | 9 | 10 | 90 | 10,000 | 900,000 |
| 50-layer network on ImageNet | 50 | 10 | 500 | 50,000 | 25 million |
The CIFAR-10 VGG-11 behind this chart has 9 weight layers (8 convolutions plus a 1-layer classifier), so ten ratios mean 90 evaluations over the 10,000-image CIFAR-10 test set, about 900,000 forward passes. One small saving: r = 0 is the same dense model for every layer, so it only needs to be evaluated once. A 50-layer ImageNet network evaluated on the 50,000 ILSVRC validation images (Russakovsky et al. 2015) needs 25 million. The cost is linear in depth, which is tolerable for VGG-11 and painful for deep networks, and it is one of the reasons the automated methods later in this lecture, AMC and NetAdapt, search the ratios instead of sweeping them.
The sweep in four lines
- Input
- A trained dense model and a held-out evaluation set
- Loop
- for each layer L_i, for each r: prune only L_i, evaluate, restore
- Output
- one curve per layer, Delta Acc_r^i against r
- Cost
- layers x ratios evaluations, no training
Quick check
In the sensitivity sweep, which layers are pruned while layer L_i is being measured?
Quick check
What happens to weights during a sensitivity sweep?
Quick check
VGG-11 on CIFAR-10: pruning L0 to 90 percent gives about what accuracy?
Recall
State the four steps of sensitivity analysis.
Recall
During the sweep, what state are the other layers in, and why?
Recall
How many evaluations does a sweep cost, and what is it for VGG-11 with ten ratios? Does any training happen?
Recap
If you remember nothing else
- Uniform shrinking gives every layer the same factor. AMC's per-layer ratios reach 70.5% at 68.3 ms, while 0.75 MobileNet reaches 68.4% at 72.3 ms.
- Layers differ in sensitivity. The first layer of VGG-11 has only 1,728 weights and 3 input channels, and every later feature depends on its output.
- Sensitivity analysis: pick L_i, prune only L_i at r in {0, 0.1, ..., 0.9}, record Delta Acc for each r, restore the layer, repeat for all layers.
- On VGG-11 CIFAR-10 every layer stays near 93% up to about 50% pruning. At 90%, L0 falls to about 32, L4 to 39 and L3 to 51, while L1, L2 and L5 stay near or above 80.
- The sweep is evaluation only, with no fine-tuning, and costs layers times ratios evaluations: 90 for the CIFAR-10 VGG-11 with ten ratios.
- Sweeping one layer at a time isolates causes but ignores interactions between layers, which is the limitation the next parts address.
Sources
- AMC: AutoML for Model Compression and Acceleration on Mobile DevicesPaperECCV 2018, He, Lin, Liu, Wang, Li and HanTable 4 MobileNet numbers on Pixel 1, Figure 5b accuracy versus latency, section 1 first-layer heuristic, section 4 critique of single-layer sensitivity.(opens in a new tab)
- Learning both Weights and Connections for Efficient Neural NetworksPaperNeurIPS 2015, Han, Pool, Tran and DallyFigure 6 per-layer sensitivity of AlexNet; first conv layer most sensitive, attributed to its 3 input channels.(opens in a new tab)
- Pruning Filters for Efficient ConvNetsPaperICLR 2017, Li, Kadav, Durdanovic, Samet and GrafSection 3.2 prune each layer independently and evaluate; section 4.1 first layer robust under filter pruning on CIFAR-10.(opens in a new tab)
- MobileNets: Efficient Convolutional Neural Networks for Mobile Vision ApplicationsPaperHoward et al., 2017Section 3.3 width multiplier thins a network uniformly at each layer; Table 6: 0.75 MobileNet 68.4 percent, 325 MMACs.(opens in a new tab)
- Very Deep Convolutional Networks for Large-Scale Image RecognitionPaperICLR 2015, Simonyan and ZissermanTable 1 configuration A: 11 weight layers and the channel widths used for the weight counts.(opens in a new tab)
- The CIFAR-10 datasetDocsAlex Krizhevsky, University of Toronto60,000 32x32 images in 10 classes; 10,000 test images with 1,000 per class.(opens in a new tab)
- ImageNet Large Scale Visual Recognition ChallengePaperIJCV 2015, Russakovsky et al.50 thousand validation images across 1,000 classes, used for the sweep-cost example.(opens in a new tab)
- MIT 6.5940 TinyML and Efficient Deep Learning Computing, Fall 2023DocsMIT HAN LabLecture 4, Pruning and Sparsity Part II: the sensitivity analysis slides and VGG-11 on CIFAR-10 chart this part is built on. The linked Lab 1 notebook implements the sweep as prune one tensor, evaluate, copy the saved clone back, with no training step.(opens in a new tab)
Part 03: From sensitivity curves to per-layer ratios
Pick an accuracy threshold, read off each layer's pruning rate where its curve crosses it, and see why this heuristic ignores the interaction between layers.
3 concepts, slides 18-23
Why this part matters
Part 02 ended with a wall of six curves and no numbers. This part is the step that converts that chart into the six per-layer ratios you actually type into a pruning script, and it is the exact place where an exam will hand you a small accuracy table, a threshold and a parameter count per layer, and ask for the per-layer rates and the overall rate.
It is also the baseline that every automated method in the rest of the lecture is judged against. AMC and NetAdapt exist because the threshold read-off has a specific, nameable flaw, so for the research project you need to be able to run this heuristic, defend it as a cheap starting point, and say precisely why it falls short. One horizontal line, six crossings, one weighted sum, one honest caveat. That is the whole part.
By the end you can
- Read a sensitivity chart and classify layers as sensitive or redundant from the slope of their curves.
- Apply the threshold rule to read off a pruning rate for every layer, including layers that never cross T.
- Compute the overall pruning rate as a parameter-weighted average and adjust T until it meets a target.
- Explain in one sentence why the result is sub-optimal, using the words single-layer sweep and interaction.
- Connect the limits of the heuristic to the motivation for automated pruning in the next two parts.
Put your finger on the 80% column of the VGG-11 chart and read straight down. The green L1 curve is still at about 92% accuracy. The blue L0 curve has already dropped to about 71%. Same network, same dataset, same pruning ratio, and the two layers are twenty points apart. That gap is the entire reason per-layer pruning ratios exist, and it is what the six curves are there to expose.
Recall what each curve is. Sensitivity analysis prunes one layer L_i alone at ratios r in {0, 0.1, ..., 0.9}, measures the accuracy at each ratio with every other layer left dense, then moves on to the next layer and repeats. The result is one accuracy versus ratio line per layer. Every line starts at the same place, the dense accuracy of about 93% on CIFAR-10, so the starting point carries no information at all. What differs is the slope: how soon and how steeply each line bends down as r grows. That slope is the layer's sensitivity.
| Layer | At 70% pruned | At 80% pruned | At 90% pruned | Verdict |
|---|---|---|---|---|
| L0 | 83.5% | 71% | 32% | Most sensitive: bends first, falls off a cliff |
| L1 | 93% | 92% | 85% | Most redundant: flat almost to the end |
| L2 | 91.5% | 89.5% | 79% | Redundant: still about 79% at 90% |
| L3 | 91.5% | 85.5% | 51% | Moderate: bends late, drops hard at 90% |
| L4 | 90.5% | 77% | 39% | Sensitive past 70% |
| L5 | 92% | 90% | 82% | Redundant: about 82% at 90% |
The rule that falls out of the table is simple. A curve that stays flat as r grows belongs to a redundant layer: most of its weights can go with no visible cost, so it should be pruned hard. A curve that bends early belongs to a sensitive layer: its weights are doing work that nothing else in the network can absorb, so it should be pruned gently. The slide summarizes it as "some layers are less sensitive to pruning" (L1, the flattest) and "some layers are more sensitive to pruning" (L0, the steepest), and the whole point of drawing all six on one axis is that you can rank them by eye.
Why the first layer is the fragile one
L0 being the most sensitive is not a quirk of this run. Han et al. (2015), the paper the chart's method comes from, report the same pattern on AlexNet: "The first convolutional layer, which interacts with the input image directly, is most sensitive to pruning. We suspect this sensitivity is due to the input layer having only 3 channels and thus less redundancy than the other convolutional layers" (section 5, Figure 6). Their Figure 6 also shows convolutional layers as a group being more sensitive than fully connected layers, which is the same story at coarser resolution: the layers with the fewest weights per unit of work have the least slack. A 3 x 3 kernel over three input channels has 27 weights per filter; removing 80% of them leaves five, and five numbers cannot describe an edge detector.
Recall
Which VGG-11 layer in the chart is most sensitive, and what physical reason does Han et al. give?
Quick check
On the VGG-11 chart, which layer tolerates 90 percent pruning best, and what does that say about it?
Now draw one dashed horizontal line across the chart just under 80% accuracy, where the slide puts it (measured against the gridlines it sits at about 79%). Walk along the blue L0 curve from the left. It sits above the line through 60%, is still above it at 70% (about 83.5%), and has dropped to 71% by 80%. Somewhere between those two grid points it crossed the line, at roughly 73% pruning. That crossing is L0's pruning rate. Do the same for the orange L3 (about 82%) and the steep red L4, whose 80% point sits just under the line: strict interpolation puts the crossing at about 78.5%, and the slide rounds its drawn guide up to 80%. L1, the flat red L2 and L5 never reach the line inside the sweep, so they get the largest tested rate, 90%, which is where the slide draws its last vertical guide.
Pruning rates read off at T of about 79 to 80 percent (from the dashed guides on the slide)
- L0
- about 73%: crosses T between the 70% and 80% points
- L1
- 90% or beyond: still about 85% accuracy at the last swept ratio
- L2
- 90% or beyond: about 79% accuracy at 90%, on the line
- L3
- about 82%: crosses just past the 80% point
- L4
- about 78% by interpolation; the slide rounds its drawn guide up to 80%
- L5
- 90% or beyond: about 82% accuracy at 90%
That is the whole mechanism, and it deserves to be stated as an algorithm rather than a picture, because the exam version comes as a table, not a chart. Choose an accuracy threshold T. For each layer, the pruning ratio is the largest swept ratio whose accuracy is still at or above T. Layers whose curves never dip below T inside the sweep get the maximum swept ratio.
The read-off table above and the worked example below follow the slide's drawn guides, which use the chart form and interpolate between grid points. By the strict table form L0 and L4 would snap to 70% and L3 to 80%, and exact interpolation puts L4 at about 78.5%, so the slide's 80% guide for L4 is a rounding of its own chart. The formula is the exam rule; the guides are how the slide applies it by eye.
From six rates to one overall rate
The slide bullet reads "pick a degradation threshold T such that the overall pruning rate is desired", and the word overall hides a calculation students routinely get wrong. The overall rate is not the average of the six numbers. It is the fraction of all weights removed, so each layer's rate is weighted by how many weights that layer has. A 90% rate on a layer with 2.36 million weights removes far more than a 73% rate on a layer with 1,728.
T is the one knob. If R comes out below the target, lower T: every curve now runs further right before it crosses, so every r_i grows or stays pinned at the maximum swept ratio, and R never falls. If the pruned network turns out too inaccurate, raise T and no rate can grow. The loop is: pick T, read off six rates, compute R, compare with the target, move T, repeat. It converges in a handful of iterations because R is monotone in T.
Worked example
What the slide's T buys on VGG-11
Assign illustrative weight counts
The slide does not say which six layers L0 to L5 are, so take the first six 3 x 3 conv layers of VGG configuration A (Simonyan and Zisserman, Table 1) with biases ignored: 3 x 64 x 9 = 1,728, 64 x 128 x 9 = 73,728, 128 x 256 x 9 = 294,912, 256 x 256 x 9 = 589,824, 256 x 512 x 9 = 1,179,648, 512 x 512 x 9 = 2,359,296. Total 4,499,136. These counts are illustrative; the read-off rule does not depend on them, but R does.Multiply each rate by its count
Rates in layer order are 0.73, 0.90, 0.90, 0.82, 0.80, 0.90, taken from the slide's drawn guides rather than the strict grid rule: exact interpolation puts L4 at 0.785, and the 0.80 here is the slide's rounding of that guide. So 1,728 x 0.73 + 73,728 x 0.90 + 294,912 x 0.90 + 589,824 x 0.82 + 1,179,648 x 0.80 + 2,359,296 x 0.90 is about 3,883,778 weights pruned.Divide by the total
R = 3,883,778 / 4,499,136 = 86.3%. About 615,358 weights remain.Weighted versus unweighted
Quantity Value Why it differs Unweighted mean of the six rates 84.2% Treats the 1,728-weight L0 like the 2.36M-weight L5 Parameter-weighted rate R 86.3% The big late layers are pruned at 80 to 90%, so R is higher Weights remaining 615,358 of 4,499,136 About one in seven survives Compression factor 7.3x 1 / (1 - 0.863)
The simulator below runs this loop on curves digitized from the slide, so at its default T of 79% the interpolated crossings land within about a point and a half of the slide's guides (L4 reads 78.5% against the drawn 80%) and R reads 86.0% against the worked example's 86.3%. Drag T and watch all six vertical guides move at once; switch between snapping to the 10% grid and interpolating between grid points; and read R, the unweighted mean and the compression factor as they update. Try T at 90 first, then 70, and note which direction R moves.
| Layer | Shape (illustrative) | Rate | Accuracy there | Weights | Pruned |
|---|---|---|---|---|---|
| L0 | 3 x 64 x 3 x 3 | 73.6% | 79.0% | 1,728 | 1,272 |
| L1 | 64 x 128 x 3 x 3 | 90.0% | 85.0% | 73,728 | 66,355 |
| L2 | 128 x 256 x 3 x 3 | 90.0% | 79.0% | 294,912 | 265,421 |
| L3 | 256 x 256 x 3 x 3 | 81.9% | 79.0% | 589,824 | 482,972 |
| L4 | 256 x 512 x 3 x 3 | 78.5% | 79.0% | 1,179,648 | 926,242 |
| L5 | 512 x 512 x 3 x 3 | 90.0% | 82.0% | 2,359,296 | 2,123,366 |
Drag T down and every vertical guide slides right at once: one knob moves all six rates. Drag it up and the guides retreat, so a higher T prunes less. The six curves are digitized from the slide chart, and the default T of 79% is where the slide draws its dashed line, a hair under the 80 mark. The weight counts are illustrative: the first six 3 x 3 conv layers of VGG configuration A with biases ignored, since the slide does not say which layers L0 to L5 are. Snap mode returns the last grid point still at or above T; interpolate mode places the crossing between grid points, which is what the dashed guides on the slide do.
The exam version: a table instead of a chart
On paper you will get an accuracy table for two or three layers, a threshold and a weight count per layer. The procedure is identical. Read each row until the accuracy falls below T, take the last ratio that was still at or above T, weight by the counts, and add.
| Layer | r = 50% | r = 60% | r = 70% | r = 80% | r = 90% |
|---|---|---|---|---|---|
| A (100,000 weights) | 90% | 84% | 70% | 52% | 30% |
| B (400,000 weights) | 95% | 93% | 91% | 86% | 75% |
| C (500,000 weights) | 95% | 95% | 94% | 93% | 90% |
Worked example
Three layers, T = 90 percent
Read each row
A is at 90% at r = 50 and 84% at 60, so r_A = 50%. B is at 91% at 70 and 86% at 80, so r_B = 70%. C is still at 90% at the last ratio, so r_C = 90%.Weight by the counts
100,000 x 0.5 + 400,000 x 0.7 + 500,000 x 0.9 = 50,000 + 280,000 + 450,000 = 780,000.Divide by the total
R = 780,000 / 1,000,000 = 78%. 220,000 weights remain, a compression of about 4.5x. The unweighted mean would have been 70%, which is wrong.One sentence on optimality
The rates come from single-layer sweeps, so the accuracy of pruning A, B and C together is never measured and is usually below T. The next concept explains why.
Recall
State the rule that turns one layer's sensitivity curve into a pruning rate.
Recall
Your overall pruning rate comes out below target. Do you raise or lower T, and why?
Recall
Three layers with 100k, 400k and 500k weights read off at 50, 70 and 90 percent. What is the overall rate?
Quick check
You raise the accuracy threshold T from 80 percent to 88 percent on the sensitivity chart. What happens to the per-layer pruning rates read off the curves?
Quick check
Layer A has 200,000 weights and crosses T at 60 percent, B has 300,000 and crosses at 80 percent, C has 500,000 and crosses at 90 percent. Overall pruning rate?
Take two of the rates you just read off. L0 pruned to 73% on its own costs about 14 points (93 down to the line at 79). L4 pruned to 80% on its own costs about 16 points. Now prune both at once. L4 was trained on features that flow through a dense L0. Its tolerance to losing 80% of its weights was measured with those features intact, and that condition no longer holds. The network now sees both perturbations at the same time, and the combined drop is usually larger than either single-layer drop, and the chart contains no measurement of it.
| Experiment | Accuracy | Drop |
|---|---|---|
| L0 pruned to 73%, nothing else touched | 93 to about 79 | about 14 points, measured on the chart |
| L4 pruned to 80%, nothing else touched | 93 to about 77 | about 16 points, measured on the chart |
| Both pruned at once | not on any curve | usually more than either single drop, never measured by the sweep |
The slide asks "is this optimal?" and answers itself: "maybe not. We do not consider the interaction between layers." The next slide of the source deck puts it even more directly, "sensitivity analysis ignores the interaction between layers, sub-optimal". The reason is built into the procedure. Each curve is a one-dimensional slice of accuracy along one layer's axis, taken with every other layer frozen dense. The read-off then treats those axes as independent, as if you could add up six separate tolerances and get the tolerance of the whole. Layers are not independent. That is the Layer interaction the heuristic leaves out, and it is why T is only a proxy for the accuracy you will actually get, not a guarantee.
Every other layer stays dense while one layer is pruned.
Each rate assumes the other five layers are still dense.
Losses compound. Fine-tuning recovers some of the gap.
Why the heuristic ignores interactions on purpose
The omission is a cost decision, not an oversight. The sweep needs (layers) x (ratios) evaluations, 6 x 9 = 54 here, each a forward pass over the validation set. Measuring every joint setting would need 9^6 = 531,441 evaluations for six layers, and real networks have dozens of layers. The AMC paper says exactly this about hand-crafted rules: "as the layers in deep neural networks are not independent, these rule-based pruning policies are non-optimal, and doesn't transfer from one model to another model", and "the design space has exponential complexity, which is infeasible to be solved by greedy, rule-based methods" (He et al., 2018, section 1). The heuristic trades optimality for a search that finishes in an afternoon.
Two things keep it usable in practice. First, Fine-tuning after pruning (part 06) recovers a large share of the compounded loss, so the read-off does not have to be exact, only in the right region. Second, it is the starting point that the automated methods improve on rather than throw away. NetAdapt removes filters from one layer per iteration, re-measures accuracy after a short fine-tune, and keeps the best proposal, so interactions get folded in one step at a time (Yang et al., 2018). AMC goes further and learns the whole per-layer assignment as one policy, rewarded on the accuracy of the jointly pruned network (He et al., 2018). Both are Automated pruning, and both exist because the single-layer sweep leaves accuracy on the table.
Recall
In one sentence, why is the threshold read-off sub-optimal?
Recall
How many evaluations does the sweep cost for six layers and nine ratios, and how many would a full joint search cost?
Quick check
Why does pruning every layer at its threshold-read rate usually lose more accuracy than T predicts?
Recap
If you remember nothing else
- Sensitivity is the slope of a layer's accuracy versus ratio curve. L0 (first conv, 3-channel input) is the most sensitive, L1 the most redundant.
- The threshold rule: r_i is where the curve crosses T. In table form it is the largest swept ratio at or above T; in chart form it is the interpolated crossing between grid points. Layers that never cross T get the maximum swept ratio.
- With T at about 79 to 80 percent (the slide's dashed line) the guides read off roughly 73, 90+, 90+, 82, 80 and 90+ percent for L0 to L5.
- The overall rate is parameter-weighted, not the mean of the six rates. With illustrative VGG-11 counts it is about 86 percent (7.3x) against an unweighted 84 percent.
- Higher T keeps more weights, lower T prunes more. Tune T until the overall rate hits the target.
- Every curve is a single-layer experiment, so simultaneous pruning compounds losses the chart never measured. T is a proxy and the assignment is sub-optimal.
- Han et al. used this heuristic successfully (9x on AlexNet, 13x on VGG-16 with iterative retraining). AMC and NetAdapt exist because a better joint assignment exists.
Sources
- MIT 6.5940 TinyML and Efficient Deep Learning Computing, Fall 2024DocsMIT HAN LabCourse page for Lecture 4, Pruning and Sparsity Part II, the source of this deck(opens in a new tab)
- Lecture 4 slides: Pruning and Sparsity Part IIDocsMIT HAN LabVGG-11 on CIFAR-10 sensitivity chart, the threshold bullet, and the interaction between layers slide(opens in a new tab)
- Lecture 4 video: Pruning and Sparsity Part IIVideoMIT HAN LabSpoken walkthrough of the sensitivity analysis and threshold read-off(opens in a new tab)
- Learning both Weights and Connections for Efficient Neural NetworksPaperHan, Pool, Tran and Dally, NIPS 2015Section 5: first conv layer most sensitive, thresholds set from sensitivity, 9x AlexNet and 13x VGG-16(opens in a new tab)
- AMC: AutoML for Model Compression and Acceleration on Mobile DevicesPaperHe, Lin, Liu, Wang, Li and Han, ECCV 2018Layers are not independent, rule-based policies are non-optimal, exponential design space(opens in a new tab)
- NetAdapt: Platform-Aware Neural Network Adaptation for Mobile ApplicationsPaperYang et al., ECCV 2018One layer simplified per iteration, the highest short-term accuracy proposal kept(opens in a new tab)
- Very Deep Convolutional Networks for Large-Scale Image RecognitionPaperSimonyan and Zisserman, ICLR 2015Table 1, configuration A (VGG-11) channel widths used for the illustrative per-layer weight counts(opens in a new tab)
- What is the State of Neural Network Pruning?PaperBlalock, Ortiz, Frankle and Guttag, MLSys 2020Global versus layerwise budget allocation changes accuracy at a fixed model size(opens in a new tab)
- Distiller documentation: pruning algorithms, sensitivity prunerDocsIntel LabsSensitivity analysis as an empirical starting guess for per-layer thresholds in a production toolkit(opens in a new tab)
Part 04: AMC: pruning ratios as a reinforcement learning problem
Given an overall compression target, AMC lets a DDPG agent choose each layer's sparsity, rewarded by accuracy under a FLOPs or latency constraint, and beats hand-tuned and uniformly scaled MobileNets on a real phone.
4 concepts, slides 24-32
Why this part matters
Your research models will have to meet a latency or FLOPs budget on one specific device, and someone has to decide how much of that budget each layer gives up. Part 03 showed the hand method. This part shows the first method that learns the answer, and it is the one the exam will ask you to formulate.
AMC (He et al., ECCV 2018) is the canonical example of turning a hand-tuned hyperparameter search into a learned policy. You will see why the search is hard, how the four ingredients of reinforcement learning map onto pruning, what the agent discovered on ResNet-50 that no expert had written down, and a table of phone measurements that settles the argument between counting FLOPs and measuring time.
By the end you can
- Explain why per-layer ratio selection is a combinatorial search and why sensitivity analysis is sub-optimal.
- Name AMC's state, action, agent and reward, and say why the action is continuous and the reward is minus error under a constraint.
- Describe what DDPG's actor and critic each do in one AMC episode.
- Read the ResNet-50 density plot: peaks at 1x1, crests at 3x3, 5x versus 3.4x at equal accuracy.
- Interpret the MobileNet table: measured time versus FLOPs targets, and why both beat uniform 0.75 shrinking.
Take a ResNet-50 and allow each of its roughly fifty prunable layers to keep one of ten possible fractions of its weights. That is 10^50 ways to spend one overall budget. The Sensitivity analysis of part 03 escapes the explosion by never looking at combinations at all: it prunes one layer at a time, runs 50 x 10 = 500 single-layer experiments, and reads each layer's Pruning ratio off its own curve where it crosses the accuracy threshold.
The saving comes from a hidden assumption: that the accuracy lost by pruning several layers at once is the sum of what each loses alone. The AMC authors tested exactly this and report that the sensitivity approach "assumes that errors of different pruned layers can be summed up linearly, which does not stand according to our experiments" (He et al., 2018). That is the Layer interaction that slide 24 says the analysis ignores. Pruning layer 3 changes what layer 4 receives, so the curve you measured for layer 4 on a dense network is the wrong curve once layer 3 is thin. The ratios are usable, but they are sub-optimal, and they belong to the network they were measured on. Change the architecture and every curve must be measured again.
Worked example
Counting the search space
Combinations
Fifty layers, ten candidate ratios each: 10^50 full configurations. No amount of GPU time enumerates that.What sensitivity analysis actually tries
One layer at a time: 50 x 10 = 500 pruned networks, each with only one layer changed. It then picks the ratios by a threshold, never trying the chosen combination until the very end.What is never measured
Any configuration in which two or more layers are pruned together. The compounding of part 03 (both layers at once losing more than either alone) lives entirely in the unmeasured region.A first-order estimate, not an optimum
Sensitivity analysis is a valid linear approximation. The per-layer rates it produces are a starting point, not the best allocation of the budget.
The bottleneck is people
Slide 25 shows the practical consequence. Conventionally the allocation relies on human expertise and trial and error. Three customers with three engineers is a workable shop. Many customers overwhelm even a team of engineers (the red cross and the alarmed manager in the middle column), and every new model, new target device or new budget restarts the trial and error from scratch, because rules such as prune the first layer less and the fully connected layers more are, in the paper's words, "non-optimal, and doesn't transfer from one model to another" (He et al., 2018). The right column serves the same crowd with one engineer and an engine that takes the model and the constraint and returns the compressed network.
Slide 26 names the ambition: a push-the-button solution. Today an efficient network needs someone who is both a machine learning expert and a hardware expert. The goal is that a non-expert plus a hardware-centric AutoML tool reaches the same efficient network. This is the definition of Automated pruning in this lecture: an algorithm, not a person, chooses the per-layer ratios for an overall target, and it does so with the target hardware in the loop.
| Method | Who chooses the ratios | Cost | Interaction modelled | Transfers to a new model |
|---|---|---|---|---|
| Human expert rules | An engineer, by trial and error | Days of experiments per model | Only in the engineer's head | No, rules are written per model |
| Sensitivity analysis | A curve per layer plus one threshold | Layers x ratios single-layer runs | No, one layer at a time | No, curves belong to one network |
| Learned policy (AMC) | A DDPG agent, layer by layer | Hundreds of pruned networks, no retraining | Yes, the reward sees the whole network | Same method, new search per model and budget |
Recall
An overall compression target is given. Why is choosing the per-layer ratios still a hard problem, and what does sensitivity analysis do about it?
Quick check
Why do the ratios from sensitivity analysis end up sub-optimal?
Follow one pass of AMC over MobileNet. Layer t-1 has just been pruned at 30%. The agent now looks at layer t: it receives a short vector describing that layer, its index, its channel counts, its kernel size, its FLOPs, how many FLOPs earlier layers already gave up and how many remain in later layers. It answers with one number, say 50%. The environment removes half of that layer's channels by magnitude and presents layer t+1. When the last layer is done, the whole pruned network is evaluated on a held-out set, and a single number comes back: minus the error. That number is the only feedback the agent ever gets, and it arrives once per pass.
That story contains every ingredient of a reinforcement learning problem, which is what slide 27 means by "pruning as a reinforcement learning problem". The paper's own description: the agent "processes the network in a layer-wise manner", "receives a layer embedding s_t", "outputs a precise compression ratio a_t", and after every layer is compressed the "validation accuracy of the pruned model with all layers compressed is evaluated without fine-tuning, which is an efficient delegate of the fine-tuned accuracy" (He et al., 2018). Only the best network found after the search is fine-tuned.
The four RL ingredients in AMC, plus two words the exam expects around them
- State
- The Layer embedding of layer t: eleven features (t, n, c, h, w, stride, k, FLOPs[t], reduced, rest, a[t-1]), each scaled to [0, 1]. The slide's [N, C, H, W, i, ...] abbreviates this list.
- Action
- One continuous number, the sparsity ratio a_t in (0, 1], for the current layer only.
- Agent
- DDPG, an actor-critic method: the actor proposes a_t from s_t, the critic estimates the value Q(s_t, a_t) of that choice.
- Environment
- Channel pruning of the pretrained network, one layer per step, using magnitude selection inside the layer.
- Reward
- R = -Error when the FLOPs or latency budget holds, effectively minus infinity otherwise (slide 29). For accuracy-guaranteed search, R = -Error x log(FLOPs) (slide 28).
- Episode
- One full pass over all layers, producing one pruned network and one reward. The signal is validation accuracy before fine-tuning, on a few thousand training images.
Why the action must be continuous, and why an actor and a critic
A pruning ratio is a real number, and the compressed model's accuracy is very sensitive to it. A discrete agent would need a grid fine enough to tell 48% from 52%, which explodes the number of actions, and a grid also throws away the order between neighbouring ratios (He et al., 2018), so the agent could not exploit the fact that neighbouring ratios behave alike. DDPG (Lillicrap et al., 2015) is the standard actor-critic method for continuous control: it concurrently learns a Q-function and a policy and can only be used with continuous action spaces (OpenAI Spinning Up). Sutton and Barto give the naming: when a value function is used "to assess, or criticize, the policy's action selections, then the value function is called a critic and the policy is called an actor". In AMC the critic learns, from replayed transitions, how much reward a state and ratio pair leads to; the actor is then nudged by gradient ascent on that estimate to propose ratios the critic scores higher. The critic judges, the actor proposes, and neither ever sees a gradient of the pruned network itself.
Why the reward is minus error under a constraint
Reinforcement learning maximizes reward, so maximizing -Error is minimizing error. The budget appears as a constraint rather than a bonus on purpose: if the agent were paid for shrinking, it would keep shrinking past the target and lose accuracy for nothing. With a hard constraint there is no reward for finishing under budget, so the agent "can precisely arrive at the target compression ratio" (He et al., 2018). The minus infinity branch is the slide's compact way of saying an infeasible network earns nothing useful.
A wasted episode teaches the critic nothing, so the paper never lets one happen. Before each action it computes the duty: the share of the removal target alpha W_all that this layer must carry, given what earlier layers already removed (W_reduced) and the most the remaining layers could remove at the cap a_max (0.8 for convolutions and 0.98 for fully connected layers in fine-grained pruning; 0.8 for every layer in channel pruning). If the actor's proposal is too timid, it is raised to the duty. The budget is therefore met by construction, and the minus infinity case is a formal backstop, not a common outcome.
Slide 28 shows the other protocol. When the goal is the smallest model with no accuracy loss, the budget is unknown in advance, so the reward itself must push on size. The bubble chart on the slide (Canziani et al., 2016) shows that top-1 accuracy rises roughly with the logarithm of the operation count, so multiplying -Error by log(FLOPs) gives, in the paper's words, "a small incentive for reducing FLOPs" while staying "sensitive to Error". The ResNet-50 and MobileNet results in the next two concepts use the constrained reward, not this one.
The constraint need not be FLOPs. The paper notes that the resource can be "FLOPs or the actual inference time on mobile device", and slide 29 adds the mechanism: a pre-built Latency lookup table of measured per-layer times on the target phone, the same device-in-the-loop idea NetAdapt uses in part 05. Substituting measured time for FLOPs turns a FLOPs-constrained search into a latency-constrained one, and the MobileNet table at the end of this part shows why that matters.
- L1a=0.5020M, 3x3
- L2?60M, 3x3
- L3?100M, 3x3
- L4?80M, 1x1
- L5?40M, 3x3
| Feature | Raw | Scaled to [0, 1] |
|---|---|---|
| t | 1 | 0.00 |
| n | 32 | 0.13 |
| c | 3 | 0.02 |
| k | 3x3 | 1.00 |
| FLOPs[t] | 20M | 0.20 |
| reduced | 0M | 0.00 |
| rest | 280M | 0.93 |
| a[t-1] | none | 0.00 |
Toy numbers. Error is 30 + 100 x sum of s_j a_j^2 with sensitivities 0.20, 0.06, 0.04, 0.05, 0.10, so the first and last layers are expensive to prune. The budget bar projects the unpruned layers at full cost until you act on them.
Recall
Name the four RL ingredients of AMC and what each is concretely.
Recall
Why is the reward minus error rather than accuracy, and why is it given only at the end of the episode?
Recall
Why must the action space be continuous?
Recall
What does AMC not learn?
Quick check
Which fact makes AMC choose DDPG rather than a discrete-action agent?
Quick check
Under a FLOPs budget, what reward does the agent get when the pruned model breaks the budget?
Slide 30 puts the agent up against Song Han's own hand-pruned ResNet-50 from his PhD thesis. The human expert kept 29% of the weights, a 3.4x reduction. The agent kept 20%, a 5x reduction, at the same accuracy: 76.13% top-1 for the original and 76.11% for AMC (He et al., 2018). This experiment uses fine-grained weight pruning, not channel pruning, and it is run as Iterative pruning in four rounds at 50%, 35%, 25% and 20% overall density with 30 fine-tuning epochs after each round, which is the schedule part 06 explains.
| Region | Human expert | AMC |
|---|---|---|
| Conv1 | 50% | 43% |
| ResBlock1 | 31% | 28% |
| ResBlock2 | 31% | 28% |
| ResBlock3 | 30% | 23% |
| ResBlock4 | 30% | 19% |
| FC | 20% | 10% |
| Total | 29% | 20% |
Worked example
From density to compression ratio
Human expert
Density 29%, so compression 1 / 0.29 = 3.4x. The thesis records the rules behind it: first layer 50%, residual blocks about 30%, fully connected layer 20% (Han, 2017).AMC
Density 20%, so compression 1 / 0.20 = 5.0x, with the biggest gains in the late blocks (30% to 19% in ResBlock4) and the classifier (20% to 10%).Same accuracy, 1.5x fewer weights
76.13% versus 76.11% top-1, a difference well inside run-to-run noise, for 5x instead of 3.4x.
What the agent noticed inside a residual block
The per-region bars hide the interesting pattern, which slide 31 shows layer by layer. ResNet-50 is built from bottleneck blocks: a 1x1 convolution that reduces the channel count, a 3x3 convolution, and a 1x1 convolution that restores it (He et al., 2016). Walk along the layer index and the kept density forms a sawtooth. The peaks, where the agent kept more, are the 1x1 layers. The crests, where it cut deep, are the 3x3 layers. The paper draws the conclusion directly: the agent "automatically learns that 3x3 convolution has more redundancy than 1x1 convolution and can be pruned more" (He et al., 2018). Nobody told it about kernel shapes; the kernel size k is just one of the eleven features in the state.
The finding makes sense once you think about where redundancy lives. A 1x1 kernel mixes channels and has no spatial extent, so every weight is a distinct channel-to-channel connection with nothing next to it to stand in for it. A 3x3 kernel has nine spatial taps per channel pair, many of which are near zero after training, and it also holds most of a block's weights: in a stage-3 bottleneck the 3x3 layer carries about 590K of the block's 1.1M parameters against 262K for each 1x1 layer (Han, 2017). Cutting the 3x3 layers hard is where the compression is, and it is also where accuracy is cheapest to spend, which is exactly the trade the reward rewards.
Recall
What did AMC learn about 3x3 versus 1x1 convolutions in ResNet-50, and what did that buy?
Quick check
Inside the residual blocks of ResNet-50, which layers did the agent keep densest?
The final slide moves from weights to milliseconds. MobileNet is run with TF-Lite on a Samsung Galaxy S7 Edge with a Qualcomm Snapdragon SoC, single core, batch size 1, which is the latency-oriented setting of a phone serving one image at a time. Four models are measured: the full 1.0 MobileNet, two AMC results and the 0.75 MobileNet baseline, which is the same architecture with every layer's width scaled by 75%.
| Model | MAC | Top-1 | Latency | Speedup | Memory |
|---|---|---|---|---|---|
| 1.0 MobileNet | 569M | 70.6% | 119.0 ms | 1x | 20.1 MB |
| AMC (50% FLOPs) | 285M | 70.5% | 64.4 ms | 1.8x | 14.3 MB |
| AMC (50% Time) | 272M | 70.2% | 59.7 ms | 2.0x | 13.2 MB |
| 0.75 MobileNet | 325M | 68.4% | 69.5 ms | 1.7x | 14.8 MB |
Worked example
Checking the table
Speedups
119.0 / 64.4 = 1.85 (shown as 1.8x), 119.0 / 59.7 = 1.99 (2.0x), 119.0 / 69.5 = 1.71 (1.7x).MAC fractions
285 / 569 = 0.50, 272 / 569 = 0.48, 325 / 569 = 0.57. The width multiplier scales cost by roughly alpha^2 = 0.5625 (Howard et al., 2017), which matches the 0.57.Accuracy deltas from 70.6%
-0.1, -0.4 and -2.2 points.Both AMC rows dominate the uniform baseline
Each AMC model has fewer MACs, lower latency, less memory and higher accuracy than 0.75 MobileNet. Halving FLOPs gave 1.85x, not 2x; targeting time came closest, at 1.99x.
Reading the two AMC rows against each other
- Latency
- 50% Time is 4.7 ms faster (59.7 versus 64.4 ms)
- Accuracy
- 50% Time loses 0.3 points (70.2% versus 70.5%)
- MACs
- 272M versus 285M: the time target also ends up slightly smaller
- Against 0.75 MobileNet
- Both are at least 1.8 points more accurate, at least 5 ms faster, with fewer MACs
Two lessons in one table
First, FLOPs are a proxy. Halving the multiply-accumulates bought 1.85x, not 2x, because a phone does not spend time in proportion to arithmetic. MobileNet's depthwise layers have a low ratio of computation to memory traffic, so trimming them saves fewer milliseconds than the MAC count suggests; the paper reports about 2x speedup on the 1x1 convolutions but less on the depthwise ones (He et al., 2018). When the agent is instead constrained by measured time from the lookup table, it removes work where the phone is actually slow, and the search lands at 59.7 ms, a 1.99x speedup that all but hits the 2x target. That allocation is less accuracy-friendly, which is the 0.3 point cost. You choose the target you care about, and you pay in the other currency.
Second, non-uniform beats uniform. Uniform shrinking with the width multiplier is a single knob turned on every layer, and the thinner model must be trained from scratch (Howard et al., 2017). AMC prunes a pretrained network with a different ratio per layer, keeps 2.1 (50% FLOPs) or 1.8 (50% Time) more points of accuracy with fewer MACs than 0.75 MobileNet, and does it after a short fine-tune. In the accuracy versus latency plane the AMC points sit above and to the left, which is the definition of a better Pareto frontier.
Recall
In the MobileNet table, why does 50% Time beat 50% FLOPs on latency but lose 0.3 points?
Quick check
Why does AMC (50% Time) run faster than AMC (50% FLOPs) on the Galaxy S7 Edge?
Recap
If you remember nothing else
- An overall compression ratio fixes the sum; allocating it across layers is a search whose objective is only observable by trying it.
- Sensitivity analysis assumes per-layer losses add. Layers interact, so its ratios are sub-optimal and do not transfer between models.
- AMC: state = layer embedding of 11 scaled features, action = continuous sparsity ratio, agent = DDPG, reward = minus error once all layers are pruned, budget enforced as a constraint.
- Continuous actions because ratios are real numbers and grids lose ordering; the critic scores Q(s, a), the actor proposes a.
- AMC learns only the ratios. Magnitude selection inside each layer and one final fine-tune are unchanged.
- ResNet-50: 20% density (5x) versus the expert's 29% (3.4x) at 76.1% top-1; 3x3 layers are pruned harder than 1x1 layers.
- MobileNet on a Galaxy S7 Edge: 50% FLOPs gives 64.4 ms at 70.5%, 50% time gives 59.7 ms at 70.2%, both beating 0.75 MobileNet at 69.5 ms and 68.4%.
- Targeting measured time lands within a whisker of the speed goal; targeting FLOPs is only a proxy.
Sources
- AMC: AutoML for Model Compression and Acceleration on Mobile DevicesPaperECCV 2018, He, Lin, Liu, Wang, Li and HanEleven-feature state, continuous action, rewards, Algorithm 1, ResNet-50 density, Pixel 1 MobileNet table. DOI 10.1007/978-3-030-01234-2_48.(opens in a new tab)
- 6.5940 TinyML and Efficient Deep Learning Computing, Lecture 4: Pruning and Sparsity Part IIDocsMIT HAN Lab, Fall 2023Source of slides 27 to 32 and of the Galaxy S7 Edge measurements.(opens in a new tab)
- Continuous control with deep reinforcement learningPaperLillicrap et al., 2015DDPG: an actor-critic, model-free algorithm for continuous action spaces.(opens in a new tab)
- Deep Deterministic Policy GradientDocsOpenAI Spinning UpLearns a Q-function and a policy concurrently; only for continuous actions; off-policy; actor trained by ascent on Q.(opens in a new tab)
- Reinforcement Learning: An Introduction, 2nd editionBookMIT Press 2018, Sutton and BartoChapter 13: the critic assesses the policy's action selections, the policy is the actor.(opens in a new tab)
- Efficient Methods and Hardware for Deep LearningPaperStanford PhD thesis 2017, Song HanTable 3.8: human-expert ResNet-50 densities, 3.4x; per-layer parameter counts of a bottleneck block.(opens in a new tab)
- MobileNets: Efficient Convolutional Neural Networks for Mobile Vision ApplicationsPaperHoward et al., 2017Table 6: 1.0 MobileNet 569M and 70.6%, 0.75 MobileNet 325M and 68.4%; the width multiplier thins every layer uniformly and needs retraining.(opens in a new tab)
- Deep Residual Learning for Image RecognitionPaperHe, Zhang, Ren and Sun, CVPR 2016The bottleneck block: 1x1 reduce, 3x3, 1x1 restore.(opens in a new tab)
- An Analysis of Deep Neural Network Models for Practical ApplicationsPaperCanziani, Paszke and Culurciello, 2016The accuracy versus operations bubble chart on slide 28; accuracy rises roughly with log operations.(opens in a new tab)
- mit-han-lab/amcDocsGitHubReference implementation of AMC.(opens in a new tab)
Part 05: NetAdapt: platform-aware pruning to a latency budget
A rule-based automatic method that removes latency in fixed steps, tries pruning each layer with a measured latency lookup table, keeps the layer whose short fine-tune loses the least accuracy, and produces a whole series of models.
2 concepts, slides 33-40
Why this part matters
Your edge deployments do not start from a FLOPs target. They start from a latency spec on a specific board: the camera pipeline must answer in 7 ms on this phone, or the classifier must fit one frame period on that microcontroller. NetAdapt is the pruning method built for that situation. It takes a pretrained network, a measured latency budget and the device itself, and hands back a network that meets the budget.
It is also the rule-based counterpart to AMC from part 04, so exam questions like to contrast the two, and it is the finishing step inside MobileNetV3. This part walks the loop once in words, once as a worked example you can redo by hand, and once in a simulator, then shows why a single run leaves you with a whole family of models rather than one.
By the end you can
- Write the NetAdapt loop from memory: Delta R, one proposal per layer, lookup table, short-term fine-tune, pick the highest accuracy, repeat, long-term fine-tune.
- Explain why a measured per-layer latency lookup table beats counting FLOPs, using the 19 percent fewer MACs but 29 percent slower example.
- Run three iterations by hand on a four-layer network and bring it from 10.0 ms under a 7.0 ms budget.
- Contrast NetAdapt with AMC on who decides the ratios, the cost model, the fine-tuning and what comes out.
- Explain why one run yields a whole accuracy versus latency frontier and read the slide 40 chart.
Suppose a pretrained MobileNet runs in 10.0 ms on one core of a Pixel 1 and the product needs 7.0 ms. The Sensitivity analysis of part 03 cannot help directly, because its curves are in accuracy versus Pruning ratio, not milliseconds, and it ignores Layer interaction. AMC (AutoML for Model Compression) from part 04 could be pointed at latency, but it needs a reinforcement learning agent and a training loop of its own. NetAdapt asks a much simpler question, and asks it many times: which single layer can I thin right now so that latency falls by a fixed step while accuracy falls the least?
The slides call it a rule-based iterative, or progressive, method, and every word matters. Rule-based means no learned policy: the decision each round is a comparison of measured numbers. Iterative means the budget is reached in many small steps rather than one cut. Progressive means each step starts from the winner of the previous one. It is Automated pruning in the sense of part 04, because nobody hand-picks per-layer ratios, but the automation is a loop you could run with a spreadsheet.
The problem, and the trick of tightening it slowly
Yang et al. state the goal as a constrained optimization. Accuracy should be as high as possible while every resource of interest (latency, energy, model size) stays under its budget.
Solving that in one shot is hopeless, so the paper breaks it into a chain of easier problems. At iteration i the constraint is not the final budget but the previous network's resource use minus a step ΔR.
The paper calls ΔR the resource reduction schedule and compares it to a learning-rate schedule. In the small MobileNetV1 experiments it starts at 0.5 ms and decays by 0.96 every iteration; for larger networks the initial step is scaled with the network's latency. The slides simplify this to a manually defined constant, and the worked example below does the same. Think of it as a progressive barrier: each round the wall moves in a little, and the network only has to squeeze past the new wall, never the final one.
One iteration, step by step
Read slides 34 to 39 as a single loop body. The paper's Algorithm 1 has the same shape, with K equal to the number of convolutional and fully connected layers, so a network with K such layers produces K proposals per iteration.
Time the pretrained network on the target once. Everything after this reads tables.
The target for this round is only ΔR below the current latency.
Pick the largest filter count whose summed table latency meets Con, keep the largest-l2 filters, short-term fine-tune, measure.
Net_(i+1) is the proposal with the best accuracy. Its latency becomes Res_(i+1).
Every iteration starts from the previous winner and moves the wall in by ΔR again.
Recover accuracy on the final architecture. This is the number you report.
- Set the constraint for this round: Con = Res_i minus ΔR_i.
- For each layer L_k, choose the number of filters to keep, from the lookup table, so the whole network meets Con; then choose which filters to keep by l2 magnitude.
- Short-term fine-tune that proposal (the slides say about 10k iterations) and measure its accuracy on a holdout set.
- Keep the proposal with the highest accuracy; it becomes the starting point of the next iteration.
- Repeat while the latency is still above the budget.
- Long-term fine-tune the final network until convergence.
Why a lookup table and not FLOPs
The constraint in Eq. 2 is a latency, so the loop needs to know the latency of every proposal, and there are K of them per iteration. Timing each one on the phone is slow and hard to parallelize. NetAdapt instead builds a Latency lookup table per layer before the loop starts: for every shape a layer might take (input channels, output channels, resolution), measure it once on the device and store the number. Layers that share a shape share an entry. The latency of a whole proposal is then the sum of its layers' entries. The paper's own illustration is a two-layer network where layer 1 with 4 filters on a 3-channel input costs 6 ms, and layer 2 with 6 filters on the 4 channels that layer 1 now produces costs 4 ms, so the network is estimated at 6 + 4 = 10 ms. Notice that the second entry is indexed by the first layer's filter count, which is how the table accounts for the removed input channels. A table indexed by whole networks would grow exponentially with depth; a table per layer grows linearly.
Why not skip the measurement and count multiply-accumulates? Because MACs are an indirect metric, and their relation to latency is neither linear nor the same across devices. The paper makes the point with a striking table: a network guided by MACs ended up with 19% fewer MACs than the baseline and 29% longer latency on a Pixel 1 CPU.
| Network | Top-1 | MACs | Latency |
|---|---|---|---|
| 25% MobileNetV1 (128) | 45.1% | 13.6 M (100%) | 4.65 ms (100%) |
| MorphNet | 46.0% | 15.0 M (110%) | 6.52 ms (140%) |
| NetAdapt guided by MACs | 46.3% | 11.0 M (81%) | 6.01 ms (129%) |
The lesson carries over to your own boards. Memory traffic, kernel launch overheads, cache behaviour and how well a library tiles a particular layer shape all change latency without changing the MAC count. The honest number is the one the device reports, and the lookup table is a cheap way to have that number on hand for every candidate. The paper checks the approximation on a Pixel 1 and finds the summed estimate highly correlated with the real measurement. Part 04 noted that AMC can also use a pre-built lookup table to optimize latency; NetAdapt makes it the default rather than an option.
Why fine-tune twice
There are two kinds of Fine-tuning in the loop and they serve different purposes. The short-term fine-tune happens once per proposal, so K times per iteration. Its only job is to make the K accuracies comparable. The paper reports that without it, the accuracy of a small network after pruning rapidly drops to nearly zero, and the algorithm then picks the best proposal solely based on noise. With 10k iterations the accuracy stays above 20% and the ranking becomes meaningful.
The long-term fine-tune happens once, after the loop has stopped, and runs until convergence. This is the step that repairs the damage of all the cuts on the final architecture. In the paper it adds between 1.8 and 4.5 points, 3.4 on average, on top of the last short-term number.
A run you can redo by hand
Take a four-layer network with 32, 64, 64 and 128 filters (layers A to D), a measured latency of 10.0 ms and a budget of 7.0 ms. Fix ΔR = 1.0 ms, ten percent of the starting latency. The lookup tables below are illustrative, the accuracies are synthetic, and the effect of one layer's cut on the next layer's input channels is ignored so the sums stay readable. The paper decays ΔR and accounts for the next layer.
Illustrative latency lookup tables, filters kept: ms
- Layer A (32 filters)
- 32: 3.0, 24: 2.4, 16: 1.8, 8: 1.2
- Layer B (64 filters)
- 64: 3.0, 48: 2.3, 32: 1.6, 16: 1.0, 8: 0.5
- Layer C (64 filters)
- 64: 2.5, 48: 2.0, 32: 1.5, 16: 1.0, 8: 0.5
- Layer D (128 filters)
- 128: 1.5, 96: 1.2, 64: 0.9, 32: 0.6, 16: 0.4
Worked example
Three iterations from 10.0 ms to a 7.0 ms budget
Check the starting point
3.0 + 3.0 + 2.5 + 1.5 = 10.0 ms at 71.0%. Above budget, so the loop runs.Iteration 1, Con = 10.0 minus 1.0 = 9.0 ms
For each layer, read the largest filter count whose sum meets 9.0 ms, short-term fine-tune the proposal and measure it.
Layer Filters kept Layer ms Total ms Short-term acc A 16 of 32 1.8 8.8 61.0% B 32 of 64 1.6 8.6 68.2% C (kept) 32 of 64 1.5 9.0 69.3% D 16 of 128 0.4 8.9 67.3% All four proposals meet the constraint, and NetAdapt does not reward going further below it (the 8.6 ms proposal earns nothing for its extra margin), so accuracy alone decides: layer C loses the least. Net_1 = A32 B64 C32 D128, 9.0 ms, 69.3%.
Iteration 2, Con = 9.0 minus 1.0 = 8.0 ms
Start from Net_1. Layer C already sits at 32, so its next table entry that saves a full millisecond is 8 filters, a much deeper cut.
Layer Filters kept Layer ms Total ms Short-term acc A 16 of 32 1.8 7.8 59.2% B (kept) 32 of 64 1.6 7.6 66.4% C 8 of 64 0.5 8.0 65.0% D 16 of 128 0.4 7.9 65.5% Thinning C again would now cost more than thinning B for the first time, so the greedy rule switches layers. Net_2 = A32 B32 C32 D128, 7.6 ms, 66.4%.
Iteration 3, Con = 7.6 minus 1.0 = 6.6 ms
7.6 ms is still above 7.0 ms, so one more round. Note that the constraint is set from the current latency, not from the budget.
Layer Filters kept Layer ms Total ms Short-term acc A 16 of 32 1.8 6.4 56.4% B 8 of 64 0.5 6.5 59.6% C 8 of 64 0.5 6.6 62.2% D (kept) 16 of 128 0.4 6.5 62.7% Layer D, the widest and least sensitive, wins. Net_3 = A32 B32 C32 D16, 6.5 ms, which is at or below 7.0 ms. The loop stops.
Long-term fine-tune
Train Net_3 to convergence. Short-term 62.7% becomes 65.2%, a gain of 2.5 points, inside the paper's 1.8 to 4.5 range.Result
Three iterations, three valid networks along the way (9.0, 7.6 and 6.5 ms), a final model at 6.5 ms and 65.2%. Layer A, the first layer, was never chosen, because the synthetic model gives it the highest Layer sensitivity by construction, mirroring the part 03 intuition that early layers are expensive to prune.
Now run it yourself. The simulator uses the same tables and the same synthetic accuracy model, so its default run reproduces the example above. Then change the budget or the step and watch which layer gets picked: a smaller ΔR takes more iterations, produces more intermediate models, and tends to end slightly higher in accuracy, which is what the paper's schedule study found.
- A32/32
- B64/64
- C64/64
- D128/128
The network starts dense at 10.0 ms and 71.0%. Each press builds one proposal per layer from the lookup table and keeps the one with the highest short-term accuracy.
Lookup tables and accuracies are synthetic. Accuracy is 71.0 minus a per-layer penalty that grows with the fraction of filters removed, so early layer A is expensive to cut and layer C is cheap. The latency effect on the next layer's input channels is ignored for readability.
NetAdapt against AMC
Both methods answer the question of part 02, which Pruning ratio for which layer, without a human in the loop, and both were published at the same conference. They differ in almost every mechanism, and the NetAdapt paper even uses AMC (under its earlier name, ADC) as a baseline, beating it by 1.2x in latency on the large MobileNetV1.
| Aspect | AMC (part 04) | NetAdapt |
|---|---|---|
| Who decides the ratios | A DDPG agent learns a policy from rewards | A greedy rule: the proposal with the highest accuracy wins |
| Search unit | The agent visits every layer once per episode | One layer changed per iteration, all layers tried |
| Cost model | FLOPs or latency in the reward, optionally a lookup table | Per-layer latency lookup table measured on the device and summed |
| Fine-tuning | One fine-tune of the final network | Short-term per proposal, long-term once at the end |
| Output | One model per target | A model at every iteration, the whole frontier |
| Interpretability | A learned policy | Every pick is explainable from measurements |
| Paper | He et al., ECCV 2018 | Yang et al., ECCV 2018 |
Recall
List the NetAdapt steps of one iteration in order.
Recall
Why does NetAdapt use a measured per-layer lookup table instead of counting FLOPs or MACs?
Recall
What is the short-term fine-tune for, and which accuracy is reported for the final model?
Quick check
In one NetAdapt iteration, what decides which layer's pruned proposal is carried to the next iteration?
Quick check
Why does NetAdapt read a pre-measured lookup table instead of counting FLOPs?
Quick check
Which accuracy number describes the final NetAdapt model reported in the paper?
Look back at the worked example. The run was aiming for one network at 7.0 ms, but on the way it produced Net_1 at 9.0 ms and Net_2 at 7.6 ms, and neither took any extra work. Each was the best of its round and each already satisfied its own, slightly looser, constraint. Slide 40 is that observation at full scale: the number of models equals the number of iterations.
The paper states it directly. Besides the final network, NetAdapt can generate a sequence of simplified networks, the highest-accuracy network from each iteration Net_1 to Net_i, which together provide the efficient frontier of accuracy and resource consumption trade-offs. The authors call it a family of simplified networks that allows dynamic network selection. With the 0.5 ms initial step and 0.96 decay, the small MobileNetV1 run in Table 2 took 28 iterations, so it delivered 28 networks. The red dots on slide 40 are a series of the same kind plotted the same way, one dot per iteration winner, from about 3.5 ms to 11 ms.
Reading the chart
The horizontal axis is latency on a single large core of a Pixel 1 CPU, measured with TensorFlow Lite as the median of eleven runs. The vertical axis is ImageNet top-1 accuracy. The red dots are the NetAdapt model series for the small MobileNetV1; the green triangles are MobileNetV1 shrunk with the width and resolution multipliers, which is Uniform shrinking from part 02; the blue diamond is MorphNet. The two arrows pick a multiplier point and the MorphNet point and slide left along a horizontal line to the NetAdapt curve, which is where the speedups on the slide come from.
| Method | Latency | Top-1 |
|---|---|---|
| NetAdapt, smallest point | about 3.5 ms | about 43.0% |
| NetAdapt, matched to MorphNet | about 4.4 ms | about 46.3% |
| MorphNet | about 7.0 ms (6.52 ms in Table 1) | 46.0% |
| NetAdapt, matched to the multiplier | about 7.3 ms | about 53.1% |
| Width multiplier baseline | about 12.1 ms | about 52.7% |
| NetAdapt, largest point | about 11.1 ms | about 56.8% |
From about 12.1 ms to about 7.3 ms is 1.7x faster with 0.3% higher accuracy than the multiplier baseline. From about 7.0 ms to about 4.4 ms is 1.6x faster with 0.3% higher accuracy than MorphNet. Across the whole curve the paper summarises it as up to 1.7x faster with the same or higher accuracy. On a mobile GPU (Samsung Galaxy S8 through SNPE) the gain drops to about 1.2x, because about 6.2 ms of that pipeline's latency is overhead that no amount of pruning can remove.
Why does the frontier beat the multipliers at all? A width multiplier thins every layer by the same factor, so it cannot express that some layers matter more. NetAdapt's greedy picks build a non-uniform architecture: the paper's Fig. 10 shows it keeping more filters in layer 6, where the feature map resolution drops, and in the last convolution that feeds the 1000-class classifier, while cutting layers 7 to 10 harder. That is the same lesson as part 02, now discovered by measurement rather than by a sensitivity sweep.
What the schedule does to the series
Because the series is a by-product of the loop, the step size shapes it. The paper compares three schedules for the same target latency.
| Initial ΔR | Decay | Iterations | Top-1 | Latency |
|---|---|---|---|---|
| 0.5 ms | 0.96 | 28 | 47.7% | 4.63 ms |
| 0.5 ms | 1.0 | 20 | 47.4% | 4.71 ms |
| 0.8 ms | 0.95 | 20 | 46.7% | 4.65 ms |
Recall
Why does one NetAdapt run give a series of models, and how many?
Quick check
A NetAdapt run needs 28 iterations to reach its latency budget. How many trade-off models does it produce along the way?
Quick check
Compared with the width-multiplier baseline on slide 40, what does the NetAdapt model series achieve?
Recap
If you remember nothing else
- NetAdapt solves maximize Acc(Net) subject to Res(Net) <= Bud by tightening the constraint by Delta R every iteration, a progressive barrier rather than one big cut.
- Each iteration thins exactly one layer: for every layer, read the filter count that meets Res minus Delta R from the lookup table, keep the largest-l2 filters, short-term fine-tune, measure holdout accuracy; keep the best proposal.
- Latency comes from summed per-layer lookup tables measured on the target device. MACs are an indirect metric: the paper shows 19 percent fewer MACs running 29 percent slower.
- The short-term fine-tune only ranks candidates; one long-term fine-tune at the end recovers 1.8 to 4.5 points and is the accuracy that gets reported.
- Delta R is a schedule: 0.5 ms decaying by 0.96 per iteration gave 28 iterations and 47.7 percent for the small MobileNetV1; larger steps finish sooner at a cost in accuracy, and for the same iteration count a smaller initial step with slower decay is preferable.
- Number of models equals number of iterations, so one run traces the accuracy versus latency frontier: 1.7x faster than width multipliers and 1.6x faster than MorphNet at equal or 0.3 percent higher accuracy on a Pixel 1 CPU.
- Versus AMC: a greedy rule instead of an RL agent, one layer per iteration, a measured lookup table, and a model at every iteration.
Sources
- NetAdapt: Platform-Aware Neural Network Adaptation for Mobile ApplicationsPaperECCV 2018, Yang, Howard, Chen, Zhang, Go, Sandler, Sze and Adam (arXiv)Eq. 1 and 2, Algorithm 1, lookup tables, Table 1 (MACs versus latency), Table 2 (schedules), Fig. 5 (slide 40), fine-tuning ablations.(opens in a new tab)
- NetAdapt, ECCV 2018 open-access PDFPaperEuropean Computer Vision AssociationCamera-ready version with the figures reproduced on slides 33 to 40.(opens in a new tab)
- 6.5940 TinyML and Efficient Deep Learning Computing, Fall 2023, Lecture 4: Pruning and Sparsity Part IIDocsMIT HAN LabThe source deck for slides 33 to 40 of this lecture.(opens in a new tab)
- AMC: AutoML for Model Compression and Acceleration on Mobile DevicesPaperECCV 2018, He, Lin, Liu, Wang, Li and Han (arXiv)The reinforcement learning counterpart, used as the ADC baseline in the NetAdapt paper.(opens in a new tab)
- MobileNets: Efficient Convolutional Neural Networks for Mobile Vision ApplicationsPaperHoward et al., 2017 (arXiv)Width and resolution multipliers, the uniform-shrinking baseline on slide 40.(opens in a new tab)
- MorphNet: Fast and Simple Resource-Constrained Structure Learning of Deep NetworksPaperCVPR 2018, Gordon et al. (arXiv)The MorphNet baseline point on slide 40.(opens in a new tab)
- Searching for MobileNetV3PaperICCV 2019, Howard et al. (arXiv)NetAdapt as the finishing step after hardware-aware architecture search.(opens in a new tab)
Part 06: Fine-tuning, iterative pruning and regularization
Pruning costs accuracy, fine-tuning at a much smaller learning rate recovers it, repeating prune and fine-tune pushes AlexNet from 5x to 9x compression, and L1 or L2 regularization during training makes weights easier to prune.
4 concepts, slides 41-52
Why this part matters
Every pruning method in this course, magnitude pruning, AMC, NetAdapt and the 2:4 sparsity of part 10, only reaches its quoted ratio because a fine-tuning step follows the cut. The EIE numbers in the next part assume the roughly 89% weight sparsity that this part explains how to obtain.
This is the fifth of the five questions the lecture opened with, and for embedded research it is the recipe you will actually run: cut, retrain the survivors gently, cut again. Two hyperparameters decide whether the loop works, the learning rate during fine-tuning and the regularizer used during training, and both are favorite exam questions because each has a single number or a single formula attached.
By the end you can
- Explain why accuracy drops after pruning and why fine-tuning at 1/10 to 1/100 of the original learning rate recovers it.
- Draw the Train Connectivity, Prune Connections, Train Weights pipeline with its loop arrow, and define one iteration.
- Read the three accuracy-loss curves and quote the 5x to 9x AlexNet result with its parameter counts.
- Write the L1 and L2 regularized losses, say which yields exact zeros, and explain why L2 still won for magnitude pruning.
- Connect Network Slimming's penalty on batch norm scaling factors to scaling-based channel pruning from lecture 04-1.
Take the AlexNet that Han, Pool, Tran and Dally started from in 2015: 61 million parameters, five convolution layers and three fully connected ones, 57.2% top-1 accuracy. They kept roughly one weight in nine and ended with a network that was not measurably worse. That is the headline of this part, and the whole trick behind it is what happens after the cut.
AlexNet before and after prune plus retrain (Han et al. 2015, Table 1 and section 4.2)
- Parameters
- 61M to 6.7M (9x)
- Top-1 error
- 42.78% to 42.77%
- Top-5 error
- 19.73% to 19.67%
- Original training time
- 75 hours on a Titan X
- Retraining time after pruning
- 173 hours at 1/100 of the initial learning rate
Now look at what those hours say. Retraining took more than twice as long as training. The authors did not treat it as optional polish; section 3 of the paper calls the final retraining step critical and states that if the pruned network is used without retraining, accuracy is significantly impacted. So the answer to the outline's fifth question, how to fine-tune a pruned network, is a method, not a footnote: the Pruning mask decides which weights exist, and Fine-tuning decides whether the survivors can still do the job.
Why the survivors are wounded, and why the wound heals
A trained layer is a set of weights that were optimized together. Zeroing the smallest of them, the magnitude criterion from lecture 04-1, is a small perturbation to any one output, but a large Pruning ratio removes so many small contributions that the outputs shift and the accuracy drops, more steeply the higher the ratio (this is what the chart on the slide shows for the dashed curve). The survivors are still near a good solution, though. Nothing about them was wrong; the function they were tuned to complete simply lost some of its terms. Fine-tuning continues gradient descent on exactly those survivors, with the removed weights held at zero, so they can absorb the work of the missing ones.
This is why the learning rate matters so much. The slide states the rule: the fine-tuning learning rate is usually 1/100 or 1/10 of the original learning rate. In the paper, LeNet was retrained at 1/10 of the original rate (section 4.1) and AlexNet at 1/100 of the initial rate (section 4.2). A large step would throw the weights out of the basin in which the magnitude ranking was measured, undoing the very judgement the pruning made. Small steps walk the network back down the loss surface from where the cut left it.
Slide 41 makes the same point as an optimization statement. Pruning poses the problem as minimizing the loss over the pruned weights W_P subject to a budget N on the L0 norm, the count of nonzero weights. The mask chooses which entries of W_P may be nonzero at all (the constraint), and fine-tuning is the argmin over the survivors with that mask fixed: the best values the kept weights can take.
The paper adds a second reason to keep the survivors instead of re-initializing them. Section 3.3 observes that networks contain fragile co-adapted features: gradient descent finds a good solution when the network is first trained, but not after re-initializing some layers and retraining them. Fine-tuning starts from the co-adapted weights and preserves that structure. The paper also notes that during retraining it can help to fix the convolution parameters while the fully connected ones retrain, and vice versa, to avoid vanishing gradients through the sparse layers.
The three-box pipeline
The figure on the slide is Figure 2 of the paper. The first box, Train Connectivity, is ordinary training, but its purpose is reframed: it learns which connections are important, not their final values. The second box, Prune Connections, applies the magnitude threshold. The third box, Train Weights, retrains the sparse network. In Han et al.'s implementation the threshold was a quality parameter multiplied by the standard deviation of each layer's weights, and Caffe was modified to add a mask that disregards pruned parameters during network operation for each weight tensor.
Learn which connections matter, not just their values.
Zero weights below the threshold and fix the mask.
Retrain the sparse network to recover accuracy.
Reading the chart on slide 43
The chart plots accuracy loss against the fraction of parameters pruned away for AlexNet. The dashed purple curve is pruning with no retraining; the green curve adds fine-tuning. Reading the points off the figure gives the following.
| Pruned away | Pruning only | Pruning + fine-tuning |
|---|---|---|
| 50% | about -0.1 | about 0.0 |
| 67% | about -0.9 | about +0.2 |
| 75% | about -2.1 | about +0.2 |
| 80% | about -4.0 | about 0.0 |
| 85.5% | off the chart | about -0.5 |
| 90% | off the chart | about -1.7 |
| 93% | off the chart | about -3.8 |
The paper summarizes the same curves in section 5: without retraining, accuracy begins dropping much sooner, at one third of the original connections rather than one tenth. It describes a free lunch of removing half the connections with no loss even without retraining, while with retraining the connections can be reduced by 9x. Read that 9x carefully: it is reached with the iterative scheme of the next two concepts. A single prune and retrain, the green curve, is already at about -1.7% by 90% pruned. Two green points (at about 67% and 75% pruned) sit slightly above zero, which the authors attribute to pruning finding the right capacity of the network and thereby reducing overfitting. Because sparsity and compression ratio are two ways of saying the same thing, keep the conversion at hand: ratio = 1 / (1 - s).
| Ratio | Pruned away |
|---|---|
| 2x | 50% |
| 3x | 66.7% |
| 5x | 80% |
| 9x | 88.9% |
| 10x | 90% |
| 13x | 92.3% |
Quick check
Fine-tuning a pruned network usually uses which learning rate, relative to the original?
Recall
What learning rate does fine-tuning a pruned network usually use, and why?
Once retraining is part of the recipe, a natural question follows: why cut to the final sparsity in one go? The slides tell the story as a sequence. Prune to 30%, retrain the weights. Prune to 50%, retrain. Prune to 70%, retrain. The only change to the pipeline figure is a single arrow from Train Weights back up to Prune Connections, and that arrow is the whole idea of Iterative pruning.
Define the unit first: one iteration is a prune followed by a fine-tune. Iterative pruning repeats that unit while gradually increasing the target sparsity in each iteration, instead of jumping to the final sparsity in one step. Han et al. put it plainly in section 3.4: learning the right connections is an iterative process, pruning followed by retraining is one iteration, and after many such iterations the minimum number of connections can be found. Each iteration is a greedy search for the best connections. They also tried pruning parameters probabilistically by absolute value and found it gave worse results.
Why gradual beats one-shot
The magnitude criterion ranks weights on the network as it is right now. After a 30% cut and a fine-tune, the survivors have re-settled: some grew to cover the removed terms, some shrank because their job was taken over. The ranking for the next cut is therefore measured on a network that has adapted, and the weights it marks as small really are the least needed. A one-shot cut to 90% ranks all 90% on a network that has never adapted to any loss, so it discards weights that would have become important once their neighbors were gone. Zhu and Gupta describe the same principle in the general form of a sparsity schedule: the binary mask is updated every few hundred steps to gradually increase the sparsity of the network while allowing the training steps to recover from any pruning-induced loss in accuracy. Their cubic schedule prunes quickly at first, when redundant connections are abundant, and slowly near the end.
The schedule in this part uses five hand-picked targets rather than a closed form, but the shape is the same: larger cuts early, smaller ones late. On a 6 x 6 matrix of 36 weights, rounding 36 s gives the following zero counts, which are also what the simulator below shows.
| Target | Zeros | Nonzeros left | Actual sparsity | Ratio |
|---|---|---|---|---|
| 30% | 11 | 25 | 30.6% | 1.4x |
| 50% | 18 | 18 | 50.0% | 2.0x |
| 70% | 25 | 11 | 69.4% | 3.3x |
| 80% | 29 | 7 | 80.6% | 5.1x |
| 90% | 32 | 4 | 88.9% | 9.0x |
Illustrative only. Fine-tuning is stood in for by letting each surviving weight in a row absorb 0.5 of the magnitude its row just lost, an echo of the surviving weights spreading outward in Han et al. Figure 7. The two loss curves are shape fits to the green and red curves of slide 51, not measured data. Cells with a teal border were zeroed in the latest step; survivors with a bright border moved up the magnitude ranking.
The loop also connects backwards to part 05. NetAdapt runs a short-term fine-tune after every layer it thins and a long-term fine-tune at the end, which is the same prune-then-fine-tune loop driven by a latency budget instead of a sparsity schedule. Whatever criterion or granularity you choose, the outer loop looks like this figure.
Quick check
In iterative pruning, what exactly counts as one iteration?
Recall
Define one iteration of iterative pruning and say what changes between iterations.
Slide 51 adds one bullet and one curve, and together they carry the number you will be asked for: Iterative pruning boosts the Pruning ratio from 5x to 9x on AlexNet compared to single-step aggressive pruning. The red curve is what that sentence looks like.
| Curve | Within 0.5% loss up to | Reaches about -4% at |
|---|---|---|
| Pruning only | about 60% | about 80% (5x) |
| Pruning + fine-tuning | about 85% | about 93% (14x) |
| Iterative pruning + fine-tuning | about 92% (12.5x) | about 95.5% (22x) |
| Pruned away | Accuracy loss |
|---|---|
| 87.5% | +0.1 |
| 89% | +0.05 |
| 90% | 0.0 |
| 91.5% | -0.3 |
| 92.5% | -0.6 |
| 93.5% | -1.0 |
| 94.5% | -2.0 |
| 95.5% | -4.1 |
Notice where the curve begins. It does not start at 40% like the others. The paper explains why in section 5: the biggest gain comes from iterative pruning, where the pruned and retrained network of the green curve is pruned and retrained again. The leftmost red dot corresponds to the point on the green line at 80% (5x) pruned further to 8x. There is no accuracy loss at 9x, and not until 10x does the accuracy begin to drop sharply.
Worked example
The 5x to 9x claim in parameters
Single-step tolerance
5x of 61M leaves 12.2M weights, which is 80% pruned away.Iterative result
9x leaves about 6.8M; the paper's measured count is 6.7M (61 / 6.7 = 9.1x, quoted as 9x), at about 89% pruned away.What the extra iterations removed
12.2M - 6.8M = 5.4M further weights, 44% of what single-step pruning had kept, at no accuracy cost.Where it stops
10x would be 6.1M weights, and there the paper reports the accuracy beginning to drop sharply.
The same paper reaches 13x on VGG-16 with five iterations of pruning and retraining, shrinking it to 7.5% of its original size with fc6 and fc7 each pruned to less than 4% of their original size. These pruned networks are the starting point of Deep Compression, which quantizes the surviving weights to 8 bits in convolution layers and 5 bits in fully connected layers and Huffman codes the result to reach 35x on AlexNet (240 MB to 6.9 MB) and 49x on VGG-16. The roughly 90% Weight sparsity that EIE assumes in the next part is this number.
Quick check
On AlexNet, iterative pruning raised the achievable pruning ratio from what to what?
Recall
Quote the AlexNet number for iterative versus single-step pruning and convert both to percent pruned.
Fine-tuning repairs the network after the cut. Regularization (for pruning) prepares it before the cut. Follow one weight w = 0.05 through training with a penalty coefficient lambda = 0.01 and a learning rate eta = 0.1, ignoring the data loss for the moment so only the penalty acts.
Worked example
One weight under an L1 and an L2 penalty
L1 pull
The gradient of lambda |w| is lambda sign(w), so each step subtracts eta lambda = 0.001 regardless of how small w is. From 0.05 the weight reaches exactly zero in 50 steps and stays there.L2 pull
The gradient of lambda w^2 is 2 lambda w, so each step subtracts eta 2 lambda w = 0.002 w. The weight is multiplied by 0.998 every step: after 50 steps 0.05 x 0.998^50 = 0.0452, after 1000 steps 0.0068, never zero.Two different destinations
L1 subtracts a constant and lands on zero. L2 multiplies by a constant and only approaches it.
| Steps | L1 | L2 |
|---|---|---|
| 0 | 0.0500 | 0.0500 |
| 50 | 0.0000 | 0.0452 |
| 200 | 0.0000 | 0.0335 |
| 1000 | 0.0000 | 0.0068 |
The two regularized losses
The slide states the general rule. During training, or during the fine-tuning of a pruned network, a penalty is added to the loss to penalize nonzero parameters and to encourage smaller ones. The two common choices are the L1 and L2 penalties on the weights W, with lambda setting how strongly the penalty competes with the data loss L(x; W).
Goodfellow, Bengio and Courville make both halves precise. L2 regularization, commonly known as weight decay, drives the weights closer to the origin; its update multiplicatively shrinks the weight vector by a constant factor on each step (their equation 7.5). L1 regularization, in comparison, results in a solution that is more sparse, where sparsity means that some parameters have an optimal value of exactly zero, and this property is why L1 has been used extensively for feature selection (LASSO). The gradient forms above are the reason. Near zero the L1 gradient lambda sign(w) keeps its full size, so the weight is pushed onto zero and pinned there. The L2 gradient 2 lambda w shrinks with the weight, so the push fades before it arrives.
| L1 | L2 | |
|---|---|---|
| Gradient of the penalty | lambda sign(w), constant | 2 lambda w, shrinks with w |
| Effect per step | Subtract a fixed amount | Multiply by a factor below one |
| Where weights end | Exactly zero, then stay | Small but never zero |
| Accuracy before retraining (Han et al.) | Better | Worse |
| Accuracy after retraining (Han et al.) | Worse | Better, best overall |
Why both help pruning, and why L2 won anyway
Either penalty shrinks the weights the data loss does not defend. That does two things for magnitude pruning. The ranking becomes a cleaner signal, because a weight that stayed large did so against a constant pull, and the mass of the distribution near zero grows, so more weights fall under the threshold at a given accuracy. L1 goes further and parks weights on exactly zero, so removing them changes nothing at all.
It is tempting to conclude that L1 must be the better choice for pruning, and this is the classic trap. Han et al. (section 3.1) report that L1 regularization does give better accuracy after pruning but before retraining, since more parameters sit near zero. However, the remaining connections are not as good as with L2, resulting in lower accuracy after retraining, and overall L2 regularization gives the best pruning results. They also tried L1 for the pruning phase followed by L2 for retraining and found it did not beat using L2 for both, because parameters from one mode do not adapt well to the other. That is why the slide says magnitude-based fine-grained pruning applies L2 regularization on weights.
Network Slimming: the same penalty on channel scaling factors
The second example on the slide moves the penalty from weights to channels, which connects back to the scaling-based criterion of lecture 04-1. Network Slimming (Liu et al., ICCV 2017) notes that every batch normalization layer already computes z_out = gamma z_hat + beta per channel, so gamma is a free scaling factor for that channel. Their training objective adds a sparsity penalty on those factors.
Channels whose gamma has been pushed toward zero contribute almost nothing and are removed with a global percentile threshold (pruning 70% of channels means choosing the 70th percentile of all gamma values), followed by fine-tuning. Because a whole channel goes, this is Channel pruning, the coarse end of Pruning granularity, and the resulting network stays dense. On VGGNet the method reports a 20x smaller model and 5x fewer computing operations. The paper also describes a multi-pass scheme that repeats train, prune and fine-tune, the same loop as the previous concepts, now driven by gamma instead of |w|.
Quick check
Why does an L1 penalty drive weights exactly to zero while L2 only shrinks them?
Quick check
Network Slimming applies its sparsity penalty to which quantity?
Recall
Write the L1 and L2 regularized losses and say which one produces exact zeros.
Recall
Which regularizer did Han et al. find best overall for pruning, and what does Network Slimming penalize?
Recap
If you remember nothing else
- Pruning without retraining starts losing accuracy once only one third of the original connections remain (about 67 percent pruned). One prune plus fine-tune holds to about 80 percent, and the full retraining scheme reaches one tenth remaining (Han et al.).
- Fine-tuning retrains only the survivors, with the mask fixed, at 1/10 to 1/100 of the original learning rate. AlexNet took 173 hours to retrain versus 75 hours to train.
- One iteration is prune then fine-tune. Iterative pruning raises the target sparsity each round and lifted AlexNet from 5x to 9x (61M to 6.7M parameters, top-5 error 19.73 to 19.67 percent).
- On the curve, iterative pruning stays within 0.5 percent loss to about 92 percent pruned and reaches -4 percent only near 95.5 percent; single prune plus fine-tune holds zero loss only to 80 percent (5x).
- L1 (lambda |W|) parks weights at exact zero; L2 (lambda ||W||^2) shrinks every weight multiplicatively. Both make small weights cheaper to remove.
- Han et al. found L2 best overall for magnitude pruning; Network Slimming puts an L1 penalty on batch norm scaling factors to select channels, and its multi-pass scheme is the same loop.
- Deep Compression and EIE (next part) start from exactly this 9x to 13x pruned network.
Sources
- Learning both Weights and Connections for Efficient Neural NetworksPaperNeurIPS 2015, Han, Pool, Tran and DallyThree-step pipeline, 1/10 and 1/100 learning rates, 5x to 9x iterative result, L1 versus L2 (3.1), dropout adjustment (3.2), Figures 5 and 7, Table 1(opens in a new tab)
- Learning Efficient Convolutional Networks through Network SlimmingPaperICCV 2017, Liu, Li, Shen, Huang, Yan and ZhangEquation 1 with g(s) = |s|, batch norm gamma as scaling factor, smooth-L1 as an alternative, percentile threshold, 20x size and 5x compute on VGGNet, multi-pass scheme(opens in a new tab)
- Deep Learning, chapter 7: Regularization for Deep LearningBookMIT Press, Goodfellow, Bengio and Courville7.1.1 weight decay shrinks multiplicatively (equation 7.5); 7.1.2 L1 yields sparse solutions (equation 7.18) and LASSO feature selection(opens in a new tab)
- To prune, or not to prune: exploring the efficacy of pruning for model compressionPaperarXiv 2017, Zhu and GuptaGradual sparsity schedule (equation 1), masks updated every delta t steps so training recovers between cuts(opens in a new tab)
- The Lottery Ticket Hypothesis: Finding Sparse, Trainable Neural NetworksPaperICLR 2019, Frankle and CarbinIterative magnitude pruning over n rounds; winning tickets at 10 to 20 percent of size; related reading only, not in the deck(opens in a new tab)
- Deep Compression: Compressing Deep Neural Networks with Pruning, Trained Quantization and Huffman CodingPaperICLR 2016, Han, Mao and DallyPruning at 9x to 13x feeds 35x on AlexNet and 49x on VGG-16(opens in a new tab)
- MIT 6.5940 TinyML and Efficient Deep Learning Computing, Fall 2024, Lecture 4: Pruning and Sparsity Part IIDocsMIT HAN Lab, Song HanSource of slides 43 to 52 (MIT slides 44 to 53), including the inherited wording errata(opens in a new tab)
Part 07: EIE: the first accelerator for sparse, compressed networks
Why sparsity needs hardware support, Han's co-design paradigm, and how EIE exploits weight sparsity, activation sparsity and weight sharing by splitting a sparse matrix-vector product across processing elements.
3 concepts, slides 53-60
Why this part matters
Parts 02 to 06 chose pruning ratios and recovered accuracy. They never asked the uncomfortable question: after you remove 90 percent of the weights, is the network actually faster? On a GPU the honest answer is often no, and sometimes it is slower. This part explains why, and shows what hardware must do for pruning to become speed and energy.
The vehicle is EIE, the Efficient Inference Engine from Han et al. at ISCA 2016, the first accelerator built to run directly on a pruned, quantized model. You will learn its three sources of savings with the exact numbers on the slide, why one of them is dynamic and the other two static, and how a sparse matrix-vector product is split across processing elements so that zero weights are never stored and zero activations are never multiplied. This is the bridge to the M:N tensor cores and point-cloud engines later in the lecture, to the exam question "explain EIE's three savings and its PE dataflow", and to any research project that deploys a pruned model on an embedded accelerator.
By the end you can
- Explain, with the EIE paper's Table IV numbers, why fine-grained sparsity gives little or even negative speedup on CPUs and GPUs.
- Name the three systems on slide 54 and the kind of sparsity each one exploits.
- State EIE's three sources of savings with their sparsity or bit width and their computation and memory factors, and explain the 5x versus 10x gap.
- Distinguish static from dynamic sparsity and say why ReLU makes activation sparsity dynamic.
- Draw the 8 x 4 example: assign rows to PEs round-robin, broadcast the nonzero activations, and count the multiplications that actually happen.
Take AlexNet's FC6 layer, a 9216 x 4096 matrix that Han's Pruning left 91 percent zeros. Feed it one input vector. The EIE paper timed exactly this layer on a desktop CPU and a Titan X GPU, once with the dense matrix and once with the sparse one stored in a compressed format and run through the vendor's sparse kernels (MKL and cuSPARSE). The results are the whole motivation for this part.
| Platform | Batch | Dense matrix | Sparse matrix | Sparse versus dense |
|---|---|---|---|---|
| Core i7-5930k CPU | 1 | 7516.2 μs | 3066.5 μs | 2.5x faster |
| GeForce Titan X GPU | 1 | 541.5 μs | 134.8 μs | 4.0x faster |
| GeForce Titan X GPU | 64 | 19.8 μs | 94.6 μs | 4.8x slower |
| EIE, 64 PEs | 1 | runs only the sparse form | 30.3 μs | 248x vs dense CPU |
Removing 91 percent of the multiplications bought only 2.5x on the CPU and 4x on the GPU, not the 11x the arithmetic promises. Worse, once the GPU batches 64 inputs so that the dense kernel can use its full width, the sparse kernel falls 4.8x behind. The paper's summary is blunt: "the irregular pattern caused by compression hinders the effective acceleration on CPUs and GPUs". A general-purpose core cannot skip a zero for free. It has to read an index, compute an address, gather a scattered activation and suffer the cache miss, and that bookkeeping costs more than the multiply it avoided. Custom accelerators before EIE did no better: sparse matrix-vector (SpMV) engines from scientific computing handle the static zeros in the weights but not the run-time zeros in the activations, and DNN accelerators of the day "must expand the network to dense form" before they can run it.
Why memory is the real enemy
| Operation (45 nm) | Energy | Relative to SRAM read |
|---|---|---|
| 32-bit SRAM read | 5 pJ | 1x |
| 32-bit DRAM read | 640 pJ | 128x |
| 32-bit float multiply | 3.7 pJ | about 0.7x |
The table is the second half of the argument, the one that decides whether a model can run on a phone at all: the 128x gap between an on-chip and an off-chip read dwarfs the multiply itself. A network with one billion connections evaluated at 20 Hz spends 20 x 10^9 x 640 pJ = 12.8 W on DRAM traffic alone, far past any mobile power budget. The lesson that Deep Compression drew from this is that the goal is not fewer FLOPs but a model small enough to live entirely in SRAM: AlexNet shrinks from 240 MB to 6.9 MB and VGG-16 from 552 MB to 11.3 MB, both with no loss of accuracy. Once the whole model fits on chip, every weight read is the cheap kind.
This is the point at which the five questions of the outline slide (what pruning is and how to formulate it, which granularity, which criterion, what ratio per layer, and how to fine-tune) hand over to a sixth that the outline never lists: on what hardware. All five are now answered, in lecture 04-1 and in parts 02 to 06 here, and the constraint ||W_P||_0 <= N has produced a model with few nonzeros. The rest of the lecture is about turning that small N into small time and small energy.
Han's paradigm: co-design the compression and the engine
Slide 56 draws the conventional flow as training on a server, then a big network shipped to a phone for slow, power-hungry inference. The proposed flow inserts a model compression stage between them and replaces the phone's generic processor with accelerated inference. The labels under each stage are five papers by the same group, and reading them as a set is the fastest way to see that compression and the engine were designed together. Neither is useful alone: a compressed model on a GPU gives the Table IV numbers above, and an engine for sparse models with nothing sparse to run is idle silicon. Together they deliver what the slide calls fast and power efficient: EIE with 64 PEs at 800 MHz draws about 600 mW and beats both baselines on the same nine FC and LSTM benchmarks by the margins below.
| EIE versus | Speedup | Energy efficiency |
|---|---|---|
| Core i7-5930k CPU | 189x | 24,000x |
| Titan X GPU | 13x | 3,400x |
The five paper labels on slide 56
- ICLR 2017, under Training
- DSD: dense-sparse-dense training, a regularizer that prunes and regrows during training to reach a better dense model
- NeurIPS 2015, under Model Compression
- Learning both Weights and Connections: train, prune, retrain, giving 9x fewer AlexNet and 13x fewer VGG-16 parameters without accuracy loss
- ICLR 2016 best paper, under Model Compression
- Deep Compression: pruning, trained quantization with a k-means codebook, then Huffman coding; AlexNet 240 MB to 6.9 MB (35x), VGG-16 552 MB to 11.3 MB (49x)
- ISCA 2016, under Accelerated Inference
- EIE: the ASIC that runs directly on the pruned, codebook-quantized weights
- FPGA 2017 best paper, under Accelerated Inference
- ESE: the same idea for sparse LSTMs on a Xilinx XCKU060 FPGA, 20x compression and 282 GOPS with load-balance-aware pruning
Three systems, three kinds of sparsity
Slide 54 lists the hardware this section covers, and each entry targets a different sparsity. EIE exploits Weight sparsity and Activation sparsity at the same time, which is what made it the first of its kind. The NVIDIA sparse tensor core accepts only structured M:N sparsity, trading flexibility for a dense-friendly pattern. TorchSparse and PointAcc exploit activation sparsity of a very different origin: point clouds are mostly empty space, so the zeros are in the input, not in the weights.
Roadmap for the rest of the lecture, from slide 54
- EIE (Han et al., ISCA 2016)
- Weight sparsity plus activation sparsity in fully connected layers, on a custom ASIC. This part and parts 08 and 09.
- NVIDIA Tensor Core (Ampere)
- M:N weight sparsity, specifically 2:4: two of every four consecutive weights must be zero, and the hardware skips the matching activations. Part 10.
- TorchSparse and PointAcc
- Activation sparsity of point clouds, where most voxels are empty, handled by sparse convolution on GPUs and on a custom accelerator. Parts 11 to 13.
Recall
Why does a 91 percent sparse FC6 layer run only 2.5x faster on a CPU, and slower than dense on a GPU at batch 64?
Recall
Name the three systems on slide 54 and the sparsity each exploits.
Look at one fully connected layer of AlexNet, FC7, a 4096 x 4096 matrix of 16.8 M weights that occupies 64 MB in 32-bit floating point. A dense engine stores all 16.8 M values and performs 16.8 M multiply-accumulate operations (MACs) for every input. After Deep Compression, the EIE paper reports that only 9% of the weights survive, about 35% of the input activations are nonzero, and 3% of the original FLOPs remain. EIE reaches that 3 percent by combining three savings that the slide states in round numbers.
| Source | Sparsity or bits | Computation saving | Memory saving | Rule of thumb |
|---|---|---|---|---|
| Sparse weight | 90% static sparsity | 10x less computation | 5x less memory footprint | 0 x A = 0 |
| Sparse activation | 70% dynamic sparsity | 3x less computation | none claimed on the slide | W x 0 = 0 |
| Weight sharing | 4-bit weights | none claimed on the slide | 8x less memory footprint | 2.09, 1.92 => 2 |
The first column is Weight sparsity. Pruning zeroed about 90 percent of the matrix, so a product 0 x A is known to be zero without looking at A. An engine that never stores those weights skips their multiplications for free, hence 10x less computation. The second column is Activation sparsity. About 70 percent of the input vector is zero because it came out of a ReLU, so W x 0 is also known without looking at W. Skipping those columns removes another factor of roughly 1 / 0.3 = 3.3, which the slide rounds to 3x, and the paper measures that skipping them saves about 65 percent of the computation cycles. The third column is Weight sharing: the surviving weights are not stored as32-bit floats but as 4-bit indices into a per-layer codebook of 2^4 = 16 shared values, which is where the crossed-out 2.09, 1.92 => 2 comes from. Both weights snap to the same centroid and are stored as the same index, and 32 / 4 is the 8x memory saving.
The formula packs all three savings into one line. The sum runs only over X_i ∩ Y, the columns that are nonzero in both the weight row and the activation vector, which is the 10x and the 3x. Each weight appears as S[I_ij], a codebook lookup, which is the 8x. The two computation factors multiply to 10 x 3 = 30x, which is why the paper can describe 102 GOPS (giga operations per second) of work on the compressed network as about 3 TOPS (tera operations per second) on the uncompressed one. The 8x from the codebook is a memory factor and does not reduce the operation count.
Why memory shrinks 5x and not 10x
The one number that trips students is the 5x. Ten percent of the weights survive, so why not 10x less memory? Because a nonzero that is stored without its neighbors must carry its position. EIE stores each surviving weight together with a 4-bit relative index (the number of zeros since the previous nonzero in the column), a scheme explained fully in part 08 under Compressed sparse column (CSC). The retrospective on the paper states it directly: "the weight and index are both 4bit giving a 50% storage overhead". Half of every stored entry is bookkeeping, so the 10x from sparsity is halved to 5x. Computation keeps its full 10x, since the index is read but never multiplied.
Worked example
From 3200 bits to 80 bits
Dense storage
100 weights in 32-bit floating point occupy 100 x 32 = 3200 bits.Prune to 10 percent, keep full precision
10 survivors, each with a 32-bit value plus a 32-bit position: 10 x 64 = 640 bits. That is 3200 / 640 = 5x, which is the slide's sparsity row: the index costs as much as the value.Add weight sharing
Weight sharing drops the value to a 4-bit codebook index (32 / 4 = 8x). EIE also keeps the position the same width as the value, a 4-bit relative index, so the index overhead stays at 2x and the 5x from step 2 holds: 10 x (4 + 4) = 80 bits. Relative to the 640-bit step this is 8x, the slide's weight-sharing row.40x overall
3200 / 80 = 40x, which is exactly 5 x 8. The decomposition assumes the index is as wide as the value, which is how EIE stores it: the slide assigns the index overhead to the sparsity factor and the bit-width gain to the sharing factor, and the two multiply.
Static versus dynamic
The italic words on the slide, static and dynamic, are the conceptual core of this part and the key to Static versus dynamic sparsity. The paper defines X_i as the set of columns where row i of W is nonzero and Y as the set of indices where a is nonzero, then says: "The set X_i is fixed for a given model. The set Y varies from input to input." Weight zeros are decided once, when pruning and Fine-tuning finish, so the storage format can be laid out offline with every zero already gone. Activation zeros are made fresh by ReLU for every input, since a different image produces a different set of negative pre-activations. No format can remove them in advance; the engine must find them at run time, which is the job of the Leading non-zero detection unit in part 08.
What the two words on the slide mean
- Static sparsity (weights)
- The set X_i of columns where row i has a nonzero is fixed once pruning and fine-tuning finish. It can be encoded offline into the storage format and never changes from input to input.
- Dynamic sparsity (activations)
- The set Y of indices where a_j is nonzero depends on this input: ReLU zeroed whatever came out negative. It must be detected at run time by scanning the vector.
The four factors behind the paper's 28,800x energy figure
- SRAM instead of DRAM
- 120x
- Weight sparsity
- 10x
- Weight sharing
- 8x
- Skipped activations
- 3x
- Product
- 120 x 10 x 8 x 3 = 28,800x
Quick check
Which of EIE's savings is dynamic, meaning it depends on the input at run time?
Quick check
Why does 90 percent weight sparsity cut EIE's memory only 5x while cutting computation 10x?
Recall
State EIE's three sources of savings with the numbers on slide 57.
Recall
Why is activation sparsity called dynamic while weight sparsity is static?
Slides 58 to 60 show the same small figure three times, and it is worth working it with real numbers before reading the rule. The input is a = (0, a1, 0, a3), the weight matrix is 8 x 4 with eleven nonzeros, and there are four processing elements. Give the symbols values: a = (0, 2, 0, 1), and in the matrix w00 = 1, w01 = 3, w03 = -2, w12 = 5, w21 = -1, w23 = 1, row 3 empty, w42 = 2, w43 = -3, w50 = 6, w63 = 2, w71 = -4. The colors on the slide say who owns what: row 0 is PE0, row 1 is PE1, row 2 is PE2, row 3 is PE3, and row 4 wraps around to PE0 again.
Worked example
Two broadcasts, seven multiplications
Scan a for its first nonzero
a0 = 0, so column 0 is skipped for every PE at once. The first nonzero is a1 = 2, and the controller broadcasts the pair (2, j = 1) to all four PEs.Each PE works column 1 of its own rows
PE0 holds w01 = 3: b0 += 3 x 2 = 6. PE2 holds w21 = -1: b2 += -2. PE3 holds w71 = -4: b7 += -8. PE1 has no nonzero in column 1 and does nothing.Scan on and broadcast a3
a2 = 0, so column 2 is skipped, and with it w12 and w42, which are never read. The next nonzero is a3 = 1, broadcast as (1, j = 3).Each PE works column 3
PE0: b0 += -2 x 1, giving 4; and b4 += -3 x 1 = -3. PE2: b2 += 1 x 1, giving -1; and b6 += 2 x 1 = 2. PE1 and PE3 have nothing in column 3.ReLU inside each PE
b = (4, 0, -1, 0, -3, 0, 2, -8) becomes (4, 0, 0, 0, 0, 0, 2, 0). The negative rows 2, 4 and 7 are the ones the slide draws as -b2, -b4, -b7 and zeroes after ReLU.7 multiplications instead of 32
The dense product needs 8 x 4 = 32 MACs. EIE performs 7, a 4.6x reduction, stores 11 weights instead of 32, and never touches columns 0 and 2.
| PE | Rows owned | Nonzero weights stored | MACs performed | Outputs before ReLU |
|---|---|---|---|---|
| PE0 | 0, 4 | 5 | 3 (w01, w03, w43) | b0 = 4, b4 = -3 |
| PE1 | 1, 5 | 2 | 0 (columns 0 and 2 skipped) | b1 = 0, b5 = 0 |
| PE2 | 2, 6 | 3 | 3 (w21, w23, w63) | b2 = -1, b6 = 2 |
| PE3 | 3, 7 | 1 | 1 (w71) | b3 = 0, b7 = -8 |
| Total | 8 rows | 11 of 32 | 7 of 32 dense MACs | ReLU keeps b0 = 4 and b6 = 2 |
The rule: interleave rows, broadcast activations
The paper states the partition in one sentence: with N PEs, "PE_k holds all rows W_i, output activationsb_i, and input activations a_i for which i (mod N) = k". Rows are dealt out round-robin like cards, so PE0 gets rows 0, 4, 8 and so on. Each PE keeps only the nonzeros of its rows, in its own CSC arrays and its own SRAM, so no PE ever sees the full matrix and no zero weight is stored anywhere. That is the rule of thumb 0 x A = 0 made physical. On the left of slide 58 the same idea appears as hardware: a grid of identical PEs wired to one central control unit that does the scanning and broadcasting (the slide draws 16; the EIE configuration evaluated in the paper uses 64).
The dataflow follows from the ownership. The paper describes it as "scanning vector a to find its next non-zero value a_j and broadcasting a_j along with its index j to all PEs. Each PE then multiplies a_j by the non-zero elements in its portion of column W_j, accumulating the partial sums in accumulators for each element of the output activation vector b." The broadcast is necessary because a_j lives in a column, and a column cuts across every PE's rows: any of the four might hold a nonzero in column j, and only the PE that owns row i is allowed to update b_i. The reward is that every output belongs to exactly one PE, so there is no reduction step between PEs at the end. The paper weighs this explicitly among three ways to partition the matrix and concludes that distributing rows gives "full locality for vector b. The drawback is that vector a needs to be broadcast". The broadcast is cheap: a is about 4 K long and about 30 percent dense, so around 1.2 K broadcasts per layer, each followed by many cycles of local work, and FIFOs decouple the controller from the PEs so the broadcast is not on the critical path.
Zero activations, the Activation sparsity of the previous concept, are handled by the scan itself. A zero is never broadcast, so its whole column is skipped for all N PEs in one decision, which is W x 0 = 0 made physical and what slide 60 highlights by boxing a0 = 0. In part 08 that scan is the Leading non-zero detection unit, and the word "logically" on slide 59 is a reminder that the tidy 8 x 4 grid is the logical view only. Physically PE0 holds a compressed slice with five entries and never sees the zeros that the figure draws.
- PE0rows 0, 4idle this broadcast5 stored0 MACs so far
- PE1rows 1, 5idle this broadcast2 stored0 MACs so far
- PE2rows 2, 6idle this broadcast3 stored0 MACs so far
- PE3rows 3, 7idle this broadcast1 stored0 MACs so far
Row i belongs to PE (i mod 4), so each output b_i is accumulated inside exactly one PE and no result ever crosses between PEs. The controller scans a for its next nonzero, broadcasts that value with its column index, and every PE multiplies it by the nonzero weights it holds in that column. A zero activation means the whole column is skipped for all four PEs at once, and a zero weight was never stored, so neither rule of thumb costs a cycle. The imbalance readout shows the price: whichever PE holds the most nonzeros in the broadcast column sets the pace.
Why interleave rather than block
The paper weighs three partitions (Section VII-A). Splitting by columns gives each a_j to one PE but needs a reduction across PEs and becomes unbalanced because a is 70 percent zero. 2D blocks need both a broadcast and a reduction. Splitting by rows keeps each b_i local and costs only one broadcast per column. Dealing rows out round-robin (rather than in contiguous blocks, a choice the paper does not justify explicitly) spreads each column's nonzeros across PEs. The small example already shows the residual problem: column 3 gives PE0 and PE2 two multiplications each while PE1 and PE3 get none, and over the whole product PE1 does nothing at all. The busiest PE sets the pace of every broadcast. This is the Load balance issue that the activation queue in part 08 softens by letting PEs run ahead, and that ESE later attacked at pruning time.
Quick check
In EIE, how are the rows of the weight matrix assigned to processing elements?
Quick check
The central control unit finds a nonzero activation a_j. What does EIE do with it?
Recall
In EIE with N PEs, which PE holds row i, and what happens when the controller finds a nonzero a_j?
Recall
Which layers did EIE accelerate, and which did it not?
Recap
If you remember nothing else
- Pruning alone leaves gains on paper: a 91 percent sparse AlexNet FC6 runs only 2.5x faster on a CPU and 4x on a Titan X at batch 1, and slower than dense at batch 64.
- Han's paradigm: train, compress (prune, quantize, Huffman), then run on an engine that computes directly on the compressed form (NeurIPS 2015, ICLR 2016, ISCA 2016, FPGA 2017).
- EIE was the first accelerator for sparse, compressed networks: 189x faster and 24,000x more energy efficient than a CPU, 13x and 3,400x versus a GPU, 102 GOPS on compressed work equal to 3 TOPS dense, 64 PEs at 800 MHz, 600 mW.
- Three savings: sparse weights (90 percent static) 10x compute and 5x memory; sparse activations (70 percent dynamic) 3x compute; weight sharing (4-bit) 8x memory. Rules of thumb 0 x A = 0 and W x 0 = 0.
- Static sparsity is fixed after training; dynamic sparsity is created by ReLU per input and must be detected at run time.
- Rows are interleaved, PE_k holds rows i with i mod N = k, so every output stays local; nonzero activations are broadcast with their index and zero activations skip whole columns.
- EIE targets matrix-vector products in FC and LSTM layers at batch size 1, not convolutions.
Sources
- EIE: Efficient Inference Engine on Compressed Deep Neural NetworkPaperISCA 2016, Han, Liu, Mao, Pu, Pedram, Horowitz, DallySavings factors, Table I energy, Table III densities, Table IV timings, Section III-C interleaving and broadcast, Section VII partitioning(opens in a new tab)
- Deep Compression: Compressing Deep Neural Networks with Pruning, Trained Quantization and Huffman CodingPaperICLR 2016 best paper, Han, Mao, Dally35x and 49x, k-means codebook, fitting the model in SRAM(opens in a new tab)
- Learning both Weights and Connections for Efficient Neural NetworksPaperNeurIPS 2015, Han, Pool, Tran, Dally9x AlexNet and 13x VGG-16 parameter reduction(opens in a new tab)
- ESE: Efficient Speech Recognition Engine with Sparse LSTM on FPGAPaperFPGA 2017 best paper, Han et al.The FPGA'17 box on slide 56; load-balance-aware pruning(opens in a new tab)
- DSD: Dense-Sparse-Dense Training for Deep Neural NetworksPaperICLR 2017, Han et al.The ICLR'17 label under Training on slide 56(opens in a new tab)
- Retrospective: EIE, Efficient Inference Engine on Sparse and Compressed Neural NetworkPaperHan et al., 2023FC-only limitation, 50 percent index overhead, structured successors(opens in a new tab)
- MIT 6.5940 Fall 2024, Lecture 4: Pruning and Sparsity Part IIDocsSong Han, MIT HAN LabThe source deck these slides copy, including the 8 x 4 figure(opens in a new tab)
- Lecture 4 video: Pruning and Sparsity Part IIVideoMIT 6.5940, Song HanWalk-through of the EIE slides(opens in a new tab)
- Accelerating Inference with Sparsity Using the NVIDIA Ampere Architecture and NVIDIA TensorRTDocsNVIDIA Developer Blog2:4 definition for the roadmap row(opens in a new tab)
- TorchSparse: Efficient Point Cloud Inference EnginePaperMLSys 2022, Tang et al.Roadmap row(opens in a new tab)
- PointAcc: Efficient Point Cloud AcceleratorPaperMICRO 2021, Lin et al.Roadmap row(opens in a new tab)
- Song HanDocsMIT HAN LabStanford PhD advised by Bill Dally, for the affiliation note on slide 56(opens in a new tab)
Part 08: Inside EIE: dataflow, the PE and its storage formats
How a nonzero activation walks through the PE array, what one processing element contains, how load is balanced, and how activation sparsity, CSC weight storage and 4-bit codebooks are realised in hardware.
3 concepts, slides 61-70
Why this part matters
Part 07 argued that a pruned, quantized network is only fast if the hardware never looks at a zero. This part is where that argument turns into wires and SRAM words. It follows one nonzero activation from the moment the controller finds it to the moment its products land in output registers, opens a single processing element to see the five stages inside, and then reads the storage format bit by bit.
Exam questions on EIE ask for exactly these three things: the dataflow, the PE stages in order, and the storage format with bit widths. Your research project on embedded inference needs the same reasoning whenever you choose a sparse format or an accelerator, because the questions never change: how much metadata does each nonzero cost, how do you keep parallel units equally busy, and how much of the model fits on chip. The running example is the same 8 x 4 matrix on four PEs that part 07 introduced.
By the end you can
- Trace a sparse matrix-vector product through EIE's broadcast-and-accumulate dataflow for a given input vector, listing which PEs work on each broadcast.
- Name the five PE stages in order and state what data crosses each boundary.
- Encode a column in EIE's relative-index CSC with 4-bit indices, including padding, and derive the pointer array.
- Explain how the activation FIFO, leading nonzero detection, even and odd pointer banks and the bypass path each remove a stall.
- Quote the key EIE numbers: 4-bit weights and indices, a 16-entry codebook, 16-bit fixed point, FIFO depth 8, 64 PEs and 162 KB of SRAM per PE.
Start with the picture from part 07. An 8 x 4 weight matrix is split across four processing elements by interleaving rows: PE0 owns rows 0 and 4, PE1 rows 1 and 5, PE2 rows 2 and 6, PE3 rows 3 and 7. In general, with N PEs, PE k holds every row i with i mod N = k, together with the output b_i it will produce and the input a_i of the same index (Han et al., 2016). The input vector for the layer is a = (0, a1, 0, a3): two of its four entries are zero, which is typical of what ReLU leaves behind.
The whole computation is a sequence of broadcasts. A central control unit scans a for its next nonzero, finds a1 at index 1, and sends the pair (a1, 1) to every PE at once. Each PE then does something entirely local: it looks up column 1 of its own rows in compressed form, multiplies each nonzero weight it finds there by a1, and adds the product into the output entry for that row. When every PE has finished (or, as the next concept shows, has at least queued the work), the controller finds the next nonzero, a3, and the same thing happens for column 3. Columns 0 and 2 are never visited, because the activations that would multiply them are zero, and W x 0 = 0. Inside each visited column, the zero weights are never visited either, because 0 x A = 0 and the compressed format simply does not store them.
Worked example
Two broadcasts finish the layer
Skip a0
The leading nonzero detector reports that the first nonzero of a is a1, not a0. Column 0 holds w00 (PE0) and w50 (PE1), and neither weight is ever read.Broadcast (a1, 1)
PE0 walks its column-1 slice and finds w01, so b0 += w01 a1. PE1 finds nothing in column 1. PE2 finds w21, so b2 += w21 a1. PE3 finds w71, so b7 += w71 a1. Multiplies this round: 1, 0, 1, 1.Skip a2
Column 2 holds w12 (PE1) and w42 (PE0). Both stay untouched.Broadcast (a3, 3)
PE0 finds w03 then w43: b0 += w03 a3 and b4 += w43 a3. PE2 finds w23 then w63: b2 += w23 a3 and b6 += w63 a3. PE1 and PE3 have nothing in column 3. Multiplies this round: 2, 0, 2, 0.Seven multiplies instead of thirty-two
A dense multiply would have done 8 x 4 = 32 multiply-adds. EIE did 3 + 4 = 7, about 22%, and touched only the weights whose activation and value were both nonzero. ReLU then runs over b: the slide draws b2, b4 and b7 as negative, so they become zero, and the next layer's detector will skip them in turn.Output Contributions Owner When b0 w01 a1 + w03 a3 PE0 Both broadcasts b2 w21 a1 + w23 a3 PE2 Both broadcasts b4 w43 a3 PE0 Second broadcast only b6 w63 a3 PE2 Second broadcast only b7 w71 a1 PE3 First broadcast only b1, b3, b5 no contribution PE1, PE3, PE1 Never touched What each output entry received
Written as a rule, each output is a sum over only the intersection of two index sets. X_i is the set of columns where row i has a nonzero weight, fixed once pruning is done, and Y is the set of nonzero activations, which changes with every input. That is the static versus dynamic distinction from part 07 written into the arithmetic: weight sparsity shrinks X_i before deployment, activation sparsity shrinks Y at run time, and the hardware only pays for pairs in both.
The S[I_ij] inside the sum is a reminder that the PE never stores the weight itself, only a 4-bit code into a shared table, which the third concept unpacks. Notice also what the four PEs did not do: they never exchanged a partial sum. Every product for row i is produced in the one PE that owns row i, so the only communication in the whole layer is the broadcast of (a_j, j) pairs, which the paper carries on an H-tree so that every PE receives it in the same cycle (Han et al., 2016).
Recall
What does the central control unit broadcast, and what does each PE do with it?
Recall
In the 8 x 4 example with a = (0, a1, 0, a3), which output entries receive a contribution, and how many multiplies happen in total?
Quick check
In EIE, how is the weight matrix divided among the processing elements?
Now stand inside PE0 while (a3, 3) arrives. The pair lands in a small queue at the front of the PE. The index 3 is used to look up where column 3 starts and ends in this PE's compressed storage. Those two addresses fetch the entries for the column, each an encoded weight plus a relative row index. The weight code is expanded to a real number, the relative index is turned into an absolute row, the multiply and add happen, and the result is written into the destination register for that row. When the layer is complete, ReLU and a leading nonzero detector turn the destination registers into the next layer's input. The slide draws this as the queue, then four dashed regions, then a ReLU and detector tail, and every EIE exam answer should be able to name the five stages in order.
Holds broadcast (a_j, j) pairs so this PE can lag or lead the others.
Reads p_j and p_(j+1), the start and end of column j, in one cycle.
Fetches 8-bit entries, one 4-bit code and one 4-bit relative index each.
Code becomes a 16-bit weight, relative index becomes an absolute address, product is added with a bypass for back-to-back hits.
Destination file collects this layer, source file feeds it; they swap roles at the next layer.
Clamps negatives to zero and finds the next nonzero to broadcast.
The same trace, with the paper's bit widths
The queue head is (a3, 3). The pointer unit reads two 16-bit pointers, p3 and p4. In PE0's arrays for the running example they are 3 and 5 (the third concept derives them), so column 3 occupies entries 3 and 4. The sparse matrix unit fetches those entries. Each is 8 bits: a 4-bit weight code and a 4-bit relative index. The SRAM is 64 bits wide, so a single read returns eight entries; the high 13 bits of a pointer select the SRAM row and the low 3 bits select the entry inside it, and the unit hands one entry per cycle to the arithmetic unit (Han et al., 2016). Why eight? With 64 PEs and about 10 percent density, a column of length 4096 leaves each PE about 6.4 nonzeros per column, so one 64-bit read usually covers a whole column.
The two entries for column 3 are (code of w03, x = 0) and (code of w43, x = 0). The weight decoder expands each 4-bit code through the layer's 16-entry table into a 16-bit fixed-point value. The address accumulator keeps a running sum of the relative indices plus one per entry, producing local rows 0 and 1, which are absolute rows 0 and 4 for PE0. The multiplier forms a3 x w03, the adder adds it to destination register 0, then a3 x w43 is added to destination register 1. Had two consecutive entries hit the same register, the adder's output would have been routed straight back to its input through the bypass path instead of waiting for the register write (Han et al., 2016).
The activation read and write unit is two register files, source and destination, each holding 64 activations of 16 bits, enough for a 4096-long vector across 64 PEs. The destination file collects this layer's outputs while the source file supplies this layer's inputs; when the layer is done they exchange roles, so no activation is ever copied between layers. Vectors longer than 4096 spill into a 2 KB activation SRAM and are processed in batches (Han et al., 2016).
The pointer read deserves one more sentence, because it is a favorite exam question. A single-ported SRAM serves one read per cycle, but every column needs two pointers. EIE stores the pointers in two banks and uses the least significant bit of the address to choose the bank. Since p_j and p_(j+1) are adjacent addresses, they always land in different banks, and both are read in the same cycle without paying for a dual-ported (larger, hotter) memory (Han et al., 2016).
What one PE holds
- Activation value
- 16-bit fixed point
- Column pointer
- 16 bits
- Sparse matrix entry
- 8 bits = 4-bit code v + 4-bit relative index x
- One SRAM read
- 64 bits = 8 entries
- Pointer split
- 13 high bits pick the SRAM row, 3 low bits pick the entry
- Activation register files
- 2 files x 64 entries x 16 bits (source and destination)
- Activation SRAM
- 2 KB
- Pointer SRAM
- 32 KB (two banks)
- Sparse matrix SRAM
- 128 KB
- SRAM per PE
- 162 KB (93% of PE area, 59% of PE power)
- Area and power per PE
- 0.638 mm², 9.157 mW at 800 MHz, TSMC 45 nm
The last two rows explain the shape of the whole chip. SRAM is 93 percent of a PE's area and 59 percent of its power, and 64 PEs fill about 40.8 mm² at 590 mW (Han et al., 2016). That is the point, not a flaw: the paper's energy argument starts from the fact that a 32-bit DRAM access costs 640 pJ against 5 pJ for SRAM, about 128 times, which the paper rounds to a 120x energy saving, so a compressed model that fits entirely on chip wins before any arithmetic trick is counted. Everything in this PE is arranged to keep the model small enough to stay there.
Recall
Why can p_j and p_(j+1) always be read in one cycle?
Quick check
What do the even and odd pointer SRAM banks make possible?
Go back to the worked example and count the multiplies per PE: 3, 0, 3, 1. That uneven count is the first of four problems the PE design must solve, and the slides walk through the solutions one dashed region at a time: a queue for load balance, a detector for activation sparsity, a compressed format for weight sparsity, a decoder for weight sharing, and finally the arithmetic and write-back that ties them together. The storage format is the thread through all of them, so this concept ends with its bit widths.
Load balance: let the fast PEs run ahead
Because rows are interleaved, each PE may hold a different number of nonzeros in any given column. In the example, the a3 broadcast gives PE0 and PE2 two multiplies each and PE1 and PE3 none. If the controller waited for every PE before broadcasting the next activation, PE1 and PE3 would idle for two cycles on every such column. The activation queue is the fix. Each PE holds a FIFO of broadcast (value, index) pairs, the controller keeps broadcasting as long as no queue is full, and a PE with little to do in one column simply moves on to the next pair in its queue while a busier PE catches up. The paper puts it plainly: the queue lets each PE build up a backlog of work to even out load imbalance, and the broadcast is disabled only if some PE's queue is full (Han et al., 2016).
The paper measured this. It swept the queue depth from 1 to 256 and defined load balance efficiency as one minus the starvation bubble cycles over the total. At depth 1, around half of all cycles are idle; efficiency climbs steeply to depth 8 and flattens afterwards, so 8 was chosen as the queue depth (Han et al., 2016, Figure 8). The visual above is illustrative and uses small integer loads, but the shape of the result is the paper's: a shallow queue wastes about half the machine.
Activation sparsity: never queue a zero
The queue only helps if what enters it is worth doing. Zero activations must be filtered out before the broadcast, and this is the job of leading nonzero detection. It is distributed, not central: each group of four PEs does a local detection over the activations it stores, the results feed up a quadtree of detector nodes, and the root of that tree is the central control unit, which selects the next nonzero and broadcasts it over an H-tree so that every PE receives it in the same cycle. For64 PEs that is 21 detector units (16 leaves, 4 intermediate, 1 root), each tiny at about 189 µm² and 0.023 mW (Han et al., 2016). Since about 70 percent of activations are zero after ReLU, this alone removes roughly two thirds of the potential broadcasts, which is the 3x factor in the paper's energy accounting.
Weight sparsity: CSC with a relative index
The pointer read and sparse matrix access regions implement the compressed format, a variation of compressed sparse column. Standard CSC, as in SciPy's csc_matrix, stores three arrays: the nonzero values, the row index of each, and a pointer array such that column j occupies positions p_j to p_(j+1) - 1 (SciPy). EIE keeps the values and the pointers but replaces the absolute row index with a relative one: for each nonzero, the number of zeros since the previous nonzero in that PE's slice of the column. Both the value and the relative index are 4 bits. When more than 15 zeros precede a nonzero, the encoder inserts a padding entry with value 0 and index 15 and continues counting from there (Han et al., 2016).
Worked example
Encode PE0's slice of the 8 x 4 example
Write PE0's two rows
PE0 owns absolute rows 0 and 4, which are local rows 0 and 1. Its slice of the matrix is [w00, w01, 0, w03] over [0, 0, w42, w43].Walk the columns
Column 0: w00 at local row 0, no zeros before it, relative index 0. Column 1: w01, index 0. Column 2: local row 0 is zero, then w42 at local row 1, so index 1. Column 3: w03 with index 0, then w43 immediately after with index 0.Build the pointers
Column lengths are 1, 1, 1, 2, so the pointer array is the running sum with a final end marker: p = [0, 1, 2, 3, 5]. That is where the p3 = 3 and p4 = 5 of the previous concept came from.PE0's three arrays
v = [w00, w01, w42, w03, w43], x = [0, 0, 1, 0, 0], p = [0, 1, 2, 3, 5]. Five 8-bit entries and five 16-bit pointers for a slice that would take eight 16-bit weights dense.Read the last column across the rows and you are looking at load imbalance in the data: for column 3, PE0 and PE2 have two entries while PE1 and PE3 have none. The pointer arrays are where the queue's job is written down.PE Pointer array p Entries per column (p(j+1) minus p(j)) PE0 (rows 0, 4) [0, 1, 2, 3, 5] 1, 1, 1, 2 PE1 (rows 1, 5) [0, 1, 1, 2, 2] 1, 0, 1, 0 PE2 (rows 2, 6) [0, 0, 1, 1, 3] 0, 1, 0, 2 PE3 (rows 3, 7) [0, 0, 1, 1, 1] 0, 1, 0, 0 All four PEs: pointers and the per-column entry counts they imply
- pos 2v70111z20010
- pos 7v30011z40100
- p00
- end2
Each nonzero becomes one 8-bit entry: a 4-bit code v and a 4-bit relative index z counting the zeros since the previous entry. Whenever that count would pass 15, the encoder inserts a padding entry (teal) with v = 0 and z = 15, exactly as the EIE paper describes, and the padding entry is multiplied like any other. The pointer array holds one 16-bit start address per column plus one end marker, so p[j+1] minus p[j] is the number of entries the PE walks for column j. At low density the compressed bits fall well below the dense 4-bit total; at high density the index overhead makes compression a loss, which is why EIE only pays off on pruned layers.
Why a relative index at all? For a layer with 4096 rows split across 64 PEs, each PE-local row still needs 6 bits to name absolutely, and the absolute row across the whole matrix needs 12. A 4-bit relative index cuts even the local figure by a third, and, more importantly, matches the 4-bit weight code so that one 8-bit entry carries both. The price is the occasional padding entry, and the paper notes that padding zeros are treated as nonzeros and lead to wasted computation; its Figure 12 shows that more PEs mean fewer padding zeros, because each PE's slice of a column is shorter and long gaps become rarer (Han et al., 2016).
Weight sharing: 4-bit codes, 16-bit arithmetic
The value stored in each entry is not a weight. It is a 4-bit index into a per-layer table of 16 shared weights, the codebook produced by the k-means quantization of Deep Compression (Han, Mao and Dally, 2016). The weight decoder reads the code out of the sparse matrix entry and looks up the 16-bit fixed-point value it stands for, every cycle, on the way to the multiplier. This is the 8x memory factor in the paper's accounting: the SRAM holds 4-bit codes, the multiplier sees 16-bit numbers, and the layer's whole set of distinct weight values is 16 entries long.
| Precision | Prediction accuracy | Reading |
|---|---|---|
| 32-bit floating point | 80.3% | Reference |
| 16-bit fixed point | 79.8% | EIE's choice, half a point lost |
| 8-bit fixed point | 53.0% | Collapses, unusable at this width |
The 16-bit choice is not arbitrary. The paper reports that 16-bit fixed point costs half a percentage point against 32-bit floating point, while 8-bit fixed point collapses to 53 percent, and that a 16-bit fixed multiply uses about 5 times less energy than a 32-bit fixed multiply and 6.2 times less than a 32-bit floating point one (Han et al., 2016). Four bits of storage and sixteen bits of arithmetic is the compromise that keeps both the SRAM and the accuracy where they need to be.
Arithmetic and write-back
The last region closes the loop. The arithmetic unit computes b_x = b_x + v x a_j, where the address x comes from the address accumulator's running sum of relative indices and v from the decoder. The destination register selected by x is read, the product is added, and the sum is written back. If two adjacent cycles select the same accumulator, the bypass path forwards the adder output directly to its input so the second add does not wait on the register (Han et al., 2016). At the end of the layer the destination file becomes the source file, ReLU and the detector run over it, and the first nonzero of the next layer enters the queue.
Storage formats and bit widths
- Weight code v
- 4 bits, index into the layer's 16-entry codebook
- Relative index x (or z)
- 4 bits, zeros since the previous entry, at most 15
- Padding rule
- gap above 15: insert v = 0, x = 15, then continue counting
- Pointer p(j)
- 16 bits, start of column j; p(j+1) minus p(j) is the entry count
- Codebook
- 16 entries x 16-bit fixed point, one table per layer
- Activation
- 16-bit fixed point
- Activation queue
- depth 8, holds (value, index) pairs
Recall
Encode the column [0, 0, 5, 0, 0, 0, 0, 7] in EIE's relative format.
Recall
What did the paper measure at FIFO depth 1, and which depth did it choose?
Quick check
A column in one PE's slice has 18 zeros before its next nonzero weight. What does the encoder store?
Quick check
According to the paper, what happens to load balance at an activation FIFO depth of one?
Recap
If you remember nothing else
- The CCU broadcasts only nonzero activations with their index; every PE multiplies that value by the nonzeros in its own slice of that column and accumulates locally.
- Rows are interleaved across PEs (row i belongs to PE i mod N); activations are broadcast, never partitioned.
- The PE pipeline is Act Queue, Pointer Read, Sparse Matrix Access, Arithmetic Unit, Act R/W, then ReLU and leading nonzero detection.
- Weights live in relative-index CSC: a 4-bit code plus a 4-bit gap in one 8-bit entry, a padding zero whenever a gap exceeds 15, and 16-bit pointers with p(j+1) minus p(j) giving the column's entry count.
- Even and odd pointer banks read both bounds of a column in one cycle from single-ported SRAM.
- The 16-entry codebook decodes 4-bit codes to 16-bit fixed point at compute time; 16-bit fixed point costs about half a percentage point of AlexNet accuracy.
- Load imbalance comes from uneven nonzero counts per column per PE; a FIFO of depth 8 hides it, while depth 1 leaves about half of all cycles idle.
- The bypass path handles back-to-back updates to the same accumulator; source and destination register files swap roles between layers.
- SRAM is 93 percent of PE area; one PE is 0.638 mm² and 9.157 mW at 800 MHz in 45 nm.
Sources
- EIE: Efficient Inference Engine on Compressed Deep Neural NetworkPaperISCA 2016, Han, Liu, Mao, Pu, Pedram, Horowitz and DallySections III-B and III-C for the format and dataflow, IV for the PE, VI-C for the queue depth sweep; Figures 2, 3, 4, 8 and 12; Table II.(opens in a new tab)
- Deep Compression: Compressing Deep Neural Networks with Pruning, Trained Quantization and Huffman CodingPaperICLR 2016, Han, Mao and DallyThe pruning plus 4-bit codebook weight sharing pipeline whose output EIE executes.(opens in a new tab)
- MIT 6.5940 TinyML and Efficient Deep Learning Computing, Lecture 4: Pruning and Sparsity (Part II)DocsMIT HAN LabThe lecture the COE 592 deck follows; slides and video.(opens in a new tab)
- Lecture 4: Pruning and Sparsity (Part II), MIT 6.5940 Fall 2024VideoMIT HAN Lab on YouTubeSong Han walking through the EIE dataflow and PE.(opens in a new tab)
- scipy.sparse.csc_matrixDocsSciPy documentationStandard CSC with data, indices and indptr, for contrast with EIE's relative-index variant.(opens in a new tab)
Part 09: EIE results and what came after
Non-zero detection after ReLU, EIE's special design choices, its throughput and energy lead over CPU, GPU, FPGA and other ASICs, and the retrospective lessons that shaped later sparse hardware.
5 concepts, slides 71-77
Why this part matters
Your research on embedded machine learning lives or dies on the memory hierarchy. EIE is the canonical proof that eliminating DRAM traffic, not building faster multipliers, is the lever that moves energy by orders of magnitude.
The previous part built the processing element block by block. This part finishes the pipeline (ReLU and non-zero detection close the loop back to the next layer), then reads the results the way a reviewer would: nine benchmark layers, two log-scale charts, and the headline numbers you must be able to quote and qualify. It ends with the authors' own retrospective seven years later, which is a ready-made map from 2016 fine-grained sparsity to today's 2:4 tensor cores and W4A16 LLM inference. Exam questions on this lecture ask for the headline numbers, the energy breakdown and EIE's limits.
By the end you can
- Trace an output activation from the accumulator through ReLU and leading non-zero detection back into the next layer's broadcast.
- Explain each of the four energy factors (120x, 10x, 8x, 3x) and rank them using the Horowitz energy table.
- Quote and interpret 189x, 13x, 24,000x and 3,400x, including the batch size 1 caveat.
- Read a log-scale cross-platform chart critically, separating order-of-magnitude signal from process-node noise.
- List what EIE could not do and name the successor idea for each limitation, ending at 2:4 sparsity.
Follow one output row to the end. The accumulator for row i has just finished summing every product of a broadcast activation and a decoded weight from that row. The sum lands in a destination activation register. ReLU clamps it: a negative sum becomes zero, a positive one is kept. Now the leading non-zero detection logic scans the register file and reports the first non-zero it finds, as a pair "value v at index j". For the next layer, the central control unit broadcasts only those pairs. The output of this layer is already the sparse input of the next one, and no dense vector was ever written out.
That is the loop the slides close. Part 08 showed how a broadcast activation fans out to the processing elements and how each PE walks its CSC column; this part shows how the results become the next broadcast. The detection is hierarchical: each group of four PEs feeds a leading non-zero detection node, those nodes feed another, and the root of the tree sits inside the central control unit and drives the H-tree broadcast. Han et al. report 21 such nodes for 64 PEs (16 + 4 + 1), each about 0.023 mW and 189 µm², well under 0.3% of one PE. The machinery that keeps both ends of the datapath sparse is almost free.
Sum of activation times decoded weight per row
Negatives become zero; typical density falls to about 30%
Report the next non-zero and its index
Only non-zero (value, index) pairs are queued
The four special aspects, and the saving each one buys
The lecturer highlights four blocks on the PE diagram as EIE's special aspects. Each of them is a concrete piece of hardware, and each maps onto one of the four factors in the paper's energy breakdown. Reading them as pairs is what turns the block diagram into an argument.
Special aspect, hardware block, and the factor it enables
- Activation queue and LNZD
- Broadcast only non-zero activations, about 70% of them are zero after ReLU (the 3x factor); the FIFO of depth 8 adds load balance so PEs with more non-zeros do not stall the rest
- Sparse matrix SRAM per PE
- Every compressed weight lives in the PE's own SRAM, 131K weights per PE across 64 PEs, so no DRAM access happens during inference (120x, the largest factor)
- Weight decoder in the datapath
- A 4-bit codebook index is expanded to a 16-bit weight right before the multiplier, so memory holds indices and arithmetic sees real values (8x)
- Address accumulator
- Adds each 4-bit relative index to a running absolute row address, so only stored non-zeros are ever fetched or multiplied (10x from 10% weight density)
The FIFO deserves one extra sentence because it is easy to miss. Columns have different numbers of non-zeros, so PEs finish at different times. Han et al. swept the queue depth and found that at depth 1 some benchmarks lose about half their cycles to imbalance, while the gain flattens past depth 8, which is what they built. That is load balance bought with a few registers rather than with a different pruning pattern, and the retrospective will show why that trade did not scale.
Why on-chip SRAM is the whole story
The factors multiply, but they are far from equal. Table I of the EIE paper restates Horowitz's 45 nm energy table from ISSCC 2014, the same table lecture 04-1 opened with. A 32-bit integer add costs 0.1 pJ, a 32-bit integer multiply 3.1 pJ, a 32-bit SRAM cache read 5 pJ, and a 32-bit DRAM access 640 pJ. The caption says it plainly: DRAM uses three orders of magnitude more energy than simple arithmetic and 128x more than SRAM; the paper rounds this 128x table ratio to the 120x it uses in its energy breakdown. A multiplier that is twice as efficient saves picojoules. A weight that never leaves the chip saves hundreds of them, on every fetch, for every weight.
Pruning and weight sharing matter here for a reason that has nothing to do with arithmetic: they are what make the model small enough to fit. After compression, AlexNet's fully connected layers need about 131K weights per PE, and 64 PEs at 0.638 mm² each hold all of them. Memory takes 93% of a PE's area and 59% of its power, so EIE is, physically, an SRAM chip with a little arithmetic attached. The order of causes is the exam answer: compression makes the model fit on chip, fitting on chip removes DRAM, and removing DRAM is the 120x.
Worked example
From 28,800x on paper to 24,000x and 3,400x measured
Multiply the four factors
120 x 10 x 8 x 3 = 28,800x. Fetching from SRAM instead of DRAM is 120x; storing 10% of the weights is 10x; 4-bit indices instead of 32-bit weights is 8x; about 70% of activations are zero after ReLU, which the paper measures as 65% energy saved, roughly 3x.Compare with the measurements
On the nine compressed layers EIE measures 24,000x better energy efficiency than the Core-i7 and 3,400x better than the Titan X (2,700x better than the Tegra K1).Explain the gap
Han et al. say the saving against the GPUs is about 10x below theory (3,400x and 2,700x against 28,800x) for two reasons: index overhead (every 4-bit weight carries a 4-bit index, plus pointers) and process node, since EIE is 45 nm while the GPUs are 28 nm.Where the win comes from
Removing the SRAM factor collapses the product by two decades; removing any other factor leaves it in the thousands. DRAM elimination is most of the result.Factor removed Product SRAM instead of DRAM (120x) 10 x 8 x 3 = 240x Weight sparsity (10x) 120 x 8 x 3 = 2,880x Weight sharing (8x) 120 x 10 x 3 = 3,600x Activation skipping (3x) 120 x 10 x 8 = 9,600x Drop one factor from 28,800x and see what remains
The four factors and the measured 24,000x and 3,400x come from Han et al. (ISCA 2016), who attribute the gap to index overhead and to EIE's 45 nm process against the GPUs' 28 nm. The 1.6x node penalty is a rough teaching figure, not a number from the paper. Untick the SRAM factor and watch the product fall from 28,800x to 240x.
Quick check
In EIE, which unit decides which activations are broadcast to the PEs for the next layer?
Quick check
Which factor is the largest in EIE's 120 x 10 x 8 x 3 energy breakdown?
Recall
After the accumulators finish, what two steps make the layer output ready for the next layer?
Recall
Which single design choice gives EIE most of its energy saving, and how large is that factor?
Take AlexNet's FC6 layer: a 4096 x 9216 matrix, 37.7 million weights. After pruning only 9% of the weights survive, and after ReLU only 35% of the input activations are non-zero. A multiply is needed only where a surviving weight meets a non-zero activation, which is 0.09 x 0.35, about 3.2% of the dense count. That is where the 33x FLOP reduction on the slide comes from.
The general rule is that the two sparsities multiply. Every layer in the benchmark set is a fully connected layer of a real model, and each one has its own pair of densities. Han et al. chose nine of them: three from AlexNet, three from VGG-16, and three from NeuralTalk, an RNN and LSTM image captioning model. The last three are the interesting outliers.
| Layer | Size | Weight density | Activation density | FLOP reduction | Model |
|---|---|---|---|---|---|
| AlexNet-6 | 4096 x 9216 | 9% | 35% | 33x | Image classification |
| AlexNet-7 | 4096 x 4096 | 9% | 35% | 33x | Image classification |
| AlexNet-8 | 1000 x 4096 | 25% | 38% | 10x | Image classification |
| VGG-6 | 4096 x 25088 | 4% | 18% | 100x | Image classification |
| VGG-7 | 4096 x 4096 | 4% | 37% | 50x | Image classification |
| VGG-8 | 1000 x 4096 | 23% | 41% | 10x | Image classification |
| NeuralTalk-We | 600 x 4096 | 10% | 100% | 10x | RNN and LSTM captioning |
| NeuralTalk-Wd | 8791 x 600 | 11% | 100% | 10x | RNN and LSTM captioning |
| NeuralTalk-LSTM | 2400 x 1201 | 10% | 100% | 10x | RNN and LSTM captioning |
Worked example
Checking the FLOP reduction column
AlexNet-6
1 / (0.09 x 0.35) = 31.7, reported as 33x. The paper first rounds the product of the densities to a whole percent (0.09 x 0.35 = 3.15%, listed as 3% in its FLOP column) and the slide reports 1 over that: 1 / 0.03 = 33x.VGG-6
1 / (0.04 x 0.18) = 139, reported as 100x by the same route: 0.72% rounds to 1%, and 1 / 0.01 = 100x. VGG's first FC layer is the sparsest in both dimensions, and its 25088-wide input still fits the 64 PE design. The slide column is loosely rounded elsewhere too: VGG-8 (9%, so 11x) and the two 11% NeuralTalk rows (9x) all appear as 10x.NeuralTalk-We
1 / (0.10 x 1.00) = 10x exactly. Activation density is 100% because LSTM gates use sigmoid and tanh, which never output exact zeros, so only weight sparsity helps.Result
Activation sparsity is a free multiplier only for ReLU networks. For recurrent models the whole saving must come from pruning, which is why their reductions all sit at 10x.
What EIE was measured against
The comparison platforms were a desktop CPU (Intel Core-i7 5930k, running Intel MKL: CSRMV for the sparse model and GEMV for the dense one), a desktop GPU (NVIDIA Titan X, cuSPARSE CSRMV and cuBLAS GEMV), and a mobile GPU (the Tegra K1, measured on a Jetson TK1 developer board, which is the same silicon the slide names differently). Each baseline was given the best library available for its case, dense or sparse, so the comparison is against optimized software rather than naive loops.
On those nine layers EIE is 189x faster than the CPU and 13x faster than the GPU, while using 24,000x and 3,400x less energy respectively. The paper adds a number that is easy to forget and worth remembering: the same compressed model, run on the CPU or GPU with sparse libraries, gives only about 3x speedup over dense. Compression alone is not the win. Compression plus hardware built for it is.
Quick check
A NeuralTalk LSTM layer has 10% weight density and 100% activation density. What FLOP reduction does EIE see on it?
Recall
State the four headline numbers and what they compare.
Look at the two right-most bars first. The fabricated EIE, 64 PEs at 45 nm, pushes 81,967 matrix-vector products per second through AlexNet FC7 at 0.59 W. DaDianNao, the strongest rival ASIC, reaches 147,938 per second but draws 15.97 W. Divide, and the picture flips: 138,927 frames per joule for EIE against 9,263 for DaDianNao, a 15x gap in EIE's favor at an older process node. The projected 256 PE version at 28 nm would reach 426,230 per second and 180,606 per joule.
| Platform | Node | Class | Weight memory | Power | Throughput (frames/s) | Frames/J |
|---|---|---|---|---|---|---|
| Core-i7 5930K | 22 nm | CPU | DRAM | 73 W | 162 | 2.22 |
| GeForce Titan X | 28 nm | GPU | DRAM | 159 W | 4,115 | 25.9 |
| Tegra K1 | 28 nm | Mobile GPU | DRAM | 5.1 W | 173 | 33.9 |
| A-Eye | 28 nm | FPGA | DRAM | 9.63 W | 33 | 3.43 |
| DaDianNao | 28 nm | ASIC | eDRAM | 15.97 W | 147,938 | 9,263 |
| TrueNorth | 28 nm | ASIC | SRAM | 0.18 W | 1,989 | 10,839 |
| EIE, 64 PEs | 45 nm | ASIC | SRAM | 0.59 W | 81,967 | 138,927 |
| EIE, 256 PEs (projected) | 28 nm | ASIC | SRAM | 2.36 W | 426,230 | 180,606 |
Worked example
Frames per joule from the table
EIE, 64 PEs
81,967 frames/s / 0.59 W = 138,927 frames/J.DaDianNao
147,938 frames/s / 15.97 W = 9,263 frames/J, of which 6.12 W is eDRAM power alone.Same node, same PE count
Han et al. also compare the projected 28 nm, 256 PE EIE with DaDianNao at its own node: 2.9x throughput, 19x energy efficiency and 3x area efficiency.Result
In throughput EIE is competitive with the best ASIC; in energy it dominates every platform in the table, including the ASICs, and that is the column to argue from.
The reason energy is where EIE separates from the pack is the one from the previous concept, now visible across platforms. A matrix-vector product at batch size 1 is completely memory bound: every weight is used once, so throughput is set by how fast weights can be delivered, and energy by where they come from. DaDianNao's rate in the table is in fact a bandwidth estimate from its eDRAM (Han et al. compute 16 x 4 x 1024 bit / 8 x 606 MHz = 4,964 GB/s), A-Eye pulls every parameter from DDR3, and the CPU and GPUs all stream from DRAM. Only TrueNorth and EIE keep weights in SRAM, and TrueNorth pays for it with 1-bit weights and an asynchronous design measured on a different task.
Quick check
How much faster and more energy efficient than a desktop GPU did EIE report on compressed FC layers?
Recall
Why is the slide 74 chart not a like-for-like benchmark? Give at least three reasons.
Consider what a large language model does when it generates one token: it multiplies a single activation vector by weight matrices holding billions of parameters, reads every weight once, and does it again for the next token. That is a matrix-vector product at batch size 1, memory bound on weights, which is exactly the workload EIE was built for in 2016. So EIE's storage trick came back: keep weights in 4 bits, decode to 16, compute in 16. Han et al. call it W4A16 and point at GPTQ, AWQ, llama.cpp and MLC LLM, with one difference: today's engines use linear integer weights rather than a K-means codebook.
In 2023, for ISCA's 50th anniversary retrospective collection, the authors wrote down what they think held up and what did not. The slide condenses it to four pros and four cons. The tables below expand each line with the evidence the retrospective gives and the design that replaced or extended the idea.
| Pro | Evidence | Where it lives now |
|---|---|---|
| Special-purpose hardware pays off early | Sparse operations stay cost-effective up to 50% density on EIE; sparse software libraries only win well below 1% | Every commercial sparse NPU since |
| Both sparsities, cycles and energy | Skipping a zero weight saves the fetch; skipping a zero activation also saves the cycle that would have computed it | NVDLA gates pruned weights, the Samsung NPU skips zero activations, Ambarella CV22 supports weight sparsity |
| Fine-grained sparsity | Individual weights can be removed, so pruning reaches higher ratios than any structured pattern | Still the highest-ratio option when hardware can afford it |
| W4A16 | Store 4-bit weights, decode to 16-bit and compute in 16-bit to keep accuracy | GPTQ, AWQ, llama.cpp and MLC LLM for single-batch LLM decoding |
| Con | Why it hurt | What replaced it |
|---|---|---|
| Hard on arrays of vector processors | Irregular non-zero positions cannot be fed to wide SIMD lanes or tensor cores | Structured N:M sparsity in the Sparse Tensor Core (2:4), load-balance-aware pruning in ESE |
| Control and storage overhead | Pointer reads, CSC traversal and LNZD around a single MAC; a 4-bit index per 4-bit weight is 50% overhead | Coarse-grained block sparsity |
| Fully connected layers only | One matrix-vector product at batch size 1; convolutions were out of scope | SCNN, Cambricon-X and Eyeriss v2 for sparse convolution; the M x V pattern itself returned in LLM decoding |
| Everything in SRAM | Fine for TinyML and vision models; 10 to 100 billion parameter LLMs do not fit (Cerebras tried this path) | None named; the retrospective only notes that 10 to 100 billion parameter LLMs do not fit |
The con that matters most for the rest of this lecture
The first con is the one that shaped GPUs. A vector processor or a tensor core executes the same instruction on many lanes at once, so it needs each lane to have work at the same time. With irregular fine-grained sparsity, one lane may hold a non-zero and its neighbor a zero, and there is no way to line them up. EIE solved this with a private index stream per PE and a FIFO for load balance; ESE (FPGA 2017) went further with load-balance-aware pruning. NVIDIA instead changed the pattern itself: prune so that in every block of four consecutive weights exactly two are zero, a constraint called 2:4 sparsity. The Sparse Tensor Core then reads a 2-bit index per kept weight, selects the matching activations, and doubles math throughput with metadata overhead far below EIE's 50%. NVIDIA's recipe is to train dense, prune to 2:4 by magnitude, and retrain with the original hyperparameters. The next part takes this up in full.
The second con is the index overhead you met in the energy gap: EIE stores a 4-bit index next to every 4-bit weight, and surrounds a single MAC with pointer reads, CSC traversal and the detector. Coarser granularity, whether 2:4 or whole blocks, amortizes that overhead. The third con, FC layers only, was answered by SCNN, Cambricon-X and Eyeriss v2 for sparse convolution. The fourth is a matter of scale: everything in SRAM is right for TinyML and vision models, and Cerebras pursued it commercially, but a model of 10 to 100 billion parameters does not fit.
Quick check
According to the retrospective, why did structured 2:4 sparsity replace EIE-style fine-grained sparsity on GPUs?
Recall
Name two things EIE could not accelerate and the designs that fixed them.
Edit one corner of a generated image and ask the model to redraw it. A dense pipeline recomputes every pixel. SIGE (NeurIPS 2022) computes only the edited region and reuses the rest. Nothing about this is specific to pruned weights, yet it is the same move EIE made: do not spend energy where the answer is already known to be zero or unchanged.
The retrospective states the move as a principle. The first principle of efficient AI computing is to be lazy: avoid redundant computation, quickly reject the work, or delay the work. Each of the four bullets on the slide is one of those three verbs applied to a different axis of the data, and reading them that way is more useful than memorizing four paper names.
| Workload | Kind of sparsity | System | The lazy move |
|---|---|---|---|
| Generative image editing | Spatial sparsity | SIGE (NeurIPS 2022) | Recompute only the edited region |
| Transformers | Token sparsity and progressive quantization | SpAtten (HPCA 2021) | Prune unimportant tokens; fetch MSBs first, LSBs only if confidence is low |
| Video | Temporal sparsity | TSM (ICCV 2019) | Shift features across frames at zero FLOPs instead of 3D convolution |
| Point clouds | Spatial sparsity | TorchSparse (MLSys 2022) and PointAcc (MICRO 2021) | Compute only where points exist |
- Avoid redundant computation: SIGE skips unedited pixels; TSM replaces a 3D convolution over time with a shift that costs zero FLOPs.
- Quickly reject the work: SpAtten prunes tokens and attention heads that contribute little, before they reach the expensive layers.
- Delay the work: SpAtten's progressive quantization fetches the most significant bits first and only fetches the least significant bits when the attention scores are not yet confident.
The point-cloud line is the bridge to the last parts of this lecture. A LiDAR scan occupies a tiny fraction of its bounding volume, so sparse convolution computes only where points exist. TorchSparse makes that fast on a GPU and PointAcc builds the map generation into hardware. Notice that this is dynamic sparsity of the input, not static sparsity of the weights, which is the static versus dynamic split again: the hardware has to discover the sparsity on the fly, exactly as EIE's leading non-zero detector did for activations.
Recall
State the be-lazy principle and map each of its three verbs to one system from the slide.
Recap
If you remember nothing else
- After accumulation, ReLU and the LNZD network make the output sparse and broadcast only non-zero (value, index) pairs; the loop closes on chip.
- All compressed weights sit in per-PE SRAM; SRAM at 5 pJ against DRAM at 640 pJ per 32-bit access (128x, which the paper rounds to 120x) is the biggest lever.
- Theoretical saving 120 x 10 x 8 x 3 = 28,800x; measured 24,000x vs CPU and 3,400x vs GPU; speed 189x and 13x; batch size 1.
- FLOP reduction equals 1 over (weight density times activation density); LSTM layers have 100 percent activation density.
- The throughput chart mixes 22, 28 and 45 nm, a projection and a bandwidth estimate; read it as decades, not ratios.
- What held up: co-design, both sparsities, on-chip weights and W4A16, which was reborn in LLM decoding.
- What did not: FC only, batch 1, 50 percent index overhead, 16-bit datapath and irregular sparsity on SIMD; successors are SCNN, Cambricon-X, Eyeriss v2, ESE and 2:4 Sparse Tensor Cores.
- The first principle is to be lazy: spatial, token, temporal and point-cloud sparsity all apply it.
Sources
- EIE: Efficient Inference Engine on Compressed Deep Neural NetworkPaperISCA 2016, Han, Liu, Mao, Pu, Pedram, Horowitz and DallyTable I (energy costs), Table III (benchmarks), Table V (cross-platform), Section VI (LNZD, FIFO depth) and Section VIII (energy breakdown, batch size).(opens in a new tab)
- Retrospective: EIE: Efficient Inference Engine on Sparse and Compressed Neural NetworkPaperISCA@50 25-Year Retrospective, June 2023, Han et al.Pros and cons, W4A16 in LLM inference, the be-lazy principle and the successor systems named in this part.(opens in a new tab)
- Computing's Energy Problem (and what we can do about it)PaperISSCC 2014, Mark HorowitzOrigin of the 45 nm per-operation energy table; EIE's Table I restates it per 32-bit word.(opens in a new tab)
- Accelerating Inference with Sparsity Using the NVIDIA Ampere Architecture and NVIDIA TensorRTDocsNVIDIA Developer Blog2:4 definition, 2x math throughput, low metadata overhead, and the prune-then-retrain recipe.(opens in a new tab)
- MIT 6.5940 TinyML and Efficient Deep Learning Computing, Fall 2023, Lecture 4: Pruning and Sparsity Part IIVideoMIT HAN LabThe deck these slides follow; lecture video at youtu.be/3t9aGLLaCqs.(opens in a new tab)
Part 10: M:N sparsity on NVIDIA tensor cores
Fine-grained structured sparsity keeps exactly N nonzeros in every block of M weights, compresses the matrix to half plus two-bit indices, and lets Ampere sparse tensor cores double GEMM throughput with no accuracy loss.
4 concepts, slides 78-83
Why this part matters
EIE proved that a sparse network can run faster and cooler than a dense one, but only on a chip nobody could buy. This part is the version you can run today. The same GPUs that train the models in your research project will accept a weight matrix in a fixed 2:4 pattern and double their matrix math, and NVIDIA ships the pruning recipe, the storage format and the library that does it.
Three things are worth taking from it. The exam will ask you to compute the storage of a 2:4 matrix, to explain how the tensor core uses two-bit indices to skip half its multiplies, and to justify why the accuracy tables show no loss. Beyond the exam, 2:4 is the reference point for every future claim you will read about a sparse accelerator: it is what a fixed, mild, hardware-friendly pattern buys, and where it stops.
By the end you can
- Define an a:b fine-grained structured pattern, state that 2:4 is 50 percent sparsity, and explain why a fixed count per block is what makes it hardware friendly.
- Compute the storage of a 2:4 compressed matrix (values plus 2-bit metadata) and the resulting saving for FP16 and INT8 weights.
- Trace how a sparse tensor core uses the 2-bit indices to select K/2 activations from a dense operand and halve the multiplies.
- Reproduce NVIDIA's train, prune, retrain recipe and explain why it recovers accuracy without a hyper-parameter search.
- Explain why GEMM speedup grows with K toward a 2x ceiling and why end-to-end inference gains are smaller.
Look at the first row of the structured-sparse matrix on the slide. Read it four cells at a time. The first four hold a value, a zero, a zero, a value. The next four hold a zero, a value, a value, a zero. Every group of four consecutive weights along the row has exactly two survivors, and the survivors can sit anywhere inside the group. Mishra et al. write the metadata for that row as [[0, 3], [1, 2]]: the positions of the survivors, group by group.
That is the whole definition of 2:4 sparsity: for each group of four values along a row, at least two must be zero. The general form keeps the same shape. Write a pattern as a:b, where the first number is how many weights survive and the second is the block size. Sparsity is then fixed by the pattern, not by the data.
2:4 is the instance that ships. Ampere sparse tensor cores accept it for FP16, BF16 and INT8 weights, and for TF32 the block halves to 1:2, still 50 percent (Mishra et al., section 3.2). NVIDIA describes the pattern as "two non-zero values in every four-entry vector" and calls it fine-grained structured sparsity (NVIDIA Ampere in-depth blog). The A100 whitepaper is explicit that the pattern is enforced along rows.
Fine-grained in what it removes, structured in how many
Lecture 04-1 laid out pruning granularities on a line from irregular fine-grained pruning, which may zero any single weight, to channel pruning, which removes whole filters. 2:4 sits between them and borrows the best of each. It is fine-grained because the unit removed is a single weight, so the pruning criterion still gets to pick within every block, which is why accuracy survives. It is structured because the count per block is constant, so the hardware knows in advance that every four weights hide exactly two multiplies.
That constancy is the entire engineering payoff. Unstructured sparsity, the kind EIE handles, needs a data-dependent index for every nonzero and a pointer to the start of every column, and the paper notes it leads to poor utilization of cache lines because the survivors land anywhere. With 2:4, the paper points out, the sparsity is constant across the matrix, so no indirection is required: a nonzero's position in memory can be computed directly from the compression rate. Two bits per survivor say which of the four slots it came from, and nothing else needs to be stored.
| Pattern | What can be removed | Metadata | Hardware that benefits | Flexibility for accuracy |
|---|---|---|---|---|
| Unstructured (EIE) | Any weight, anywhere | Index per nonzero, pointers, padding | Custom accelerator or slow CPU kernels | Highest, chosen per weight |
| 2:4 fine-grained structured | Any two of every four in a row | 2 bits per stored value, no pointers | Every Ampere and later GPU | High, chosen per block |
| Channel pruning | Whole output channels | None, matrix just shrinks | Any dense hardware | Lowest, chosen per channel |
One more fact will matter in the next two concepts: the groups of four run along the row of the weight matrix W. In the GEMM that a layer becomes, that row is the reduction dimension, the axis along which products are summed. The pattern has to live there, because that is the only axis on which skipping a weight also skips a multiply.
Where this sits among the three case studies
The divider slide that opens this section lists three sparse-hardware case studies. EIE (Efficient Inference Engine) came first: a custom accelerator exploiting Weight sparsity and Activation sparsity at once. This part is the middle one, and it takes the opposite bet. It exploits weight sparsity only, at a fixed and modest 50 percent, in exchange for running on a GPU that already sits in every data center. TorchSparse and PointAcc, which follow, go back to activation sparsity in point clouds. Keeping the three apart by which sparsity they exploit and what hardware they need is the fastest way to remember them.
Recall
Why is 2:4 called fine-grained structured sparsity?
Take one group of four FP16 weights. Dense, it costs 4 x 16 = 64 bits. Under 2:4, only two values are stored, 2 x 16 = 32 bits, plus a 2-bit index for each, 2 x 2 = 4 bits. The group now costs 36 bits, a saving of about 44 percent (Mishra et al., section 3.1). Not 50 percent: the indices are small but they are not free.
Scale that to a whole matrix and you get the format on the slide. A structured-sparse W of size R x C is stored as an R x C/2 block of nonzero values and an R x C/2 block of two-bit indices. The slide's instruction is to push all the nonzero elements to the left in memory. The survivors of each row are packed contiguously at half the original width, and the index block, drawn beside them, records where each came from.
Worked example
An FP16 layer of 1024 x 1024 weights
Dense storage
1024 x 1024 x 16 = 16,777,216 bits, which is 2 MiB.Stored values
Half the columns survive: 1024 x 512 = 524,288 values at 16 bits each, 8,388,608 bits = 1 MiB.Metadata
One 2-bit index per stored value: 524,288 x 2 = 1,048,576 bits = 128 KiB.Total and saving
8,388,608 + 1,048,576 = 9,437,184 bits = 1.125 MiB. The ratio to dense is 9,437,184 / 16,777,216 = 0.5625.Result
43.75% saved. The value array halves; the indices add back an eighth of what remains.
| Case | Dense | Values | Metadata | Total | Saving |
|---|---|---|---|---|---|
| FP16, R = C = 1024 | 16,777,216 (2 MiB) | 8,388,608 (1 MiB) | 1,048,576 (128 KiB) | 9,437,184 (1.125 MiB) | 43.75% |
| INT8, R = C = 4096 | 134,217,728 (16 MiB) | 67,108,864 (8 MiB) | 16,777,216 (2 MiB) | 83,886,080 (10 MiB) | 37.5% |
The index cost is a fixed 2 bits per stored value, so its weight relative to the values depends on the value width: 2 / 16 = 12.5% overhead for FP16 and 2 / 8 = 25% for INT8, which is why the INT8 saving is the smaller 37.5 percent (Mishra et al., section 3.1). Compare that with the format EIE relied on. CSC stores a 4-bit relative index and a 4-bit weight-sharing code per nonzero, a 16-bit pointer per column, and a padding entry whenever a run of zeros exceeds fifteen (Han et al., EIE, section III). Mishra et al. note that a plain CSR with 8-bit weights and 16-bit column indices can spend up to 200 percent of the value bits on metadata. 2:4 spends 12.5 or 25 percent, with no pointers and no padding, because the pattern itself carries most of the position information.
One group of four weights under 2:4
- FP16 dense
- 4 x 16 = 64 bits
- FP16 compressed
- 2 x 16 + 2 x 2 = 36 bits, about 44% saved
- INT8 dense
- 4 x 8 = 32 bits
- INT8 compressed
- 2 x 8 + 2 x 2 = 20 bits, about 38% saved
Why insist on pushing everything to the left rather than leaving zeros in place and skipping them? Because memory is read in wide lines. With the survivors contiguous at half width, every byte a memory read brings in is a value the tensor core will use, which the paper describes as letting hardware fully utilize large memory reads. The A100 whitepaper puts the same point as a reduction of memory storage and bandwidth by almost 2x. Zeros left in place would fill half of every line with nothing.
Check against Mishra et al.: 43.75 percent, the paper's about 44 percent for FP16.
The value array always halves under 2:4, but every stored value drags a 2-bit index with it, so the saving lands at 43.75 percent for 16-bit weights and 37.5 percent for 8-bit weights, never at 50. The MAC count halves exactly, which is the 2x the sparse tensor core can deliver on the matrix math alone. The last readout applies Amdahl to the whole network: with 70 percent of inference time inside GEMMs and a measured 1.8x on those GEMMs, the model runs about 1.45x faster. Drag the GEMM share down to see why memory-bound layers and small batches hide most of the gain.
Quick check
A 2:4 sparse FP16 weight matrix has R = 512 rows and C = 1024 columns. How many metadata bits does the compressed format hold?
Recall
For an R x C weight matrix in 2:4 format, how many values and how many metadata bits are stored?
Follow one output element through a small GEMM with K = 8. Dense, the tensor core takes a row of A with eight values, a column of B with eight values, multiplies them pairwise and accumulates eight products. Now store that row of A in 2:4 form: four values and four 2-bit indices. The core reads the indices, pulls exactly the four elements of the B column that sit at those positions, multiplies four pairs, and accumulates. The slide's caption says it in one line: the indices are used to mask out the inputs, and only two multiplications will be done out of four.
The rule behind the example is worth stating precisely, because exam questions turn on it. A Sparse tensor core performs sparse matrix times dense matrix equals dense matrix. Only the first operand, A of size M x K, is compressed, to M x K/2 values plus indices. The second operand B (K x N) and the output C (M x N) stay dense (Mishra et al., section 3.2). NVIDIA's TensorRT blog describes the mechanism as using the metadata to pull only the necessary values from the other, uncompressed operand. The metadata belongs to the weights, but it is applied to the activations.
The weight row, already packed left.
A multiplexer over the dense B column.
Writes a dense element of C.
Halving the pairs halves the work, and the hardware is built so that the saving shows up as time. The A100 whitepaper states that a standard MMA on a 16 x 8 x 16 tile takes some number of cycles N, and the sparse MMA on the same tile takes N/2, a 2x speedup. The paper's Table 1 reports the resulting peak rates.
A100 peak dense versus sparse tensor throughput, in TOPS (Mishra et al., Table 1)
- TF32 (1:2 pattern)
- 156 dense, 312 sparse
- FP16 / BF16
- 312 dense, 624 sparse
- INT8
- 624 dense, 1248 sparse
Why must the pattern run along K? Because K is the axis the selector walks. Each output element is a dot product over K, and a zero weight at position k means the product with B[k, n] can be dropped for every n. Zeros arranged along M or N would zero entire rows or columns of the output, which is a smaller network, not a faster GEMM. This is also why the library has shape rules: the reduction dimension must be a multiple of 16 for 16-bit formats and 32 for INT8, and layers that fail the rule, such as the first convolution of an image network with K = 3 x 7 x 7 = 147, are simply left dense (Mishra et al., sections 3.2 and 5.1). cuSPARSELt exposes the compression and the sparse GEMM to programmers, and TensorRT 8 applies them automatically to a network whose weights already follow the pattern.
What changed since EIE
Set the two designs beside each other and the trade becomes visible. EIE (Efficient Inference Engine) reaches for every zero it can find: about 90 percent in the weights and about 70 percent in the activations, both exploited at once. To do that it needs Leading non-zero detection to find the next live activation, a FIFO in front of each Processing element (PE) to keep Load balance across uneven columns, and a custom chip to hold all of it. The sparse tensor core asks for far less sparsity, exactly 50 percent in the weights alone, which is static and known before the run. That is what lets the whole mechanism collapse into a multiplexer driven by 2-bit tags, small enough to add to a tensor core that every GPU already has.
| Aspect | EIE (ISCA 2016) | 2:4 sparse tensor core (2020) |
|---|---|---|
| Sparsity exploited | Weights (about 90 percent) and activations (about 70 percent) | Weights only, exactly 50 percent |
| Weight format | CSC: 4-bit relative index plus 4-bit code per nonzero, column pointers, padding | Contiguous values plus one 2-bit index per stored value |
| Finding work | Leading nonzero detection, activation FIFO for load balance | Multiplexer driven by the 2-bit indices, no search |
| Hardware | Custom 45 nm ASIC, never sold | Every Ampere or later GPU, cuSPARSELt and TensorRT |
| Ceiling on math | Proportional to combined sparsity | 2x, fixed by the pattern |
Quick check
Which statement about 2:4 sparse GEMMs on Ampere sparse tensor cores is correct?
Quick check
Compared with EIE, what makes 2:4 sparsity easy to deploy on commodity hardware?
Recall
Which GEMM operand is stored sparse, which is dense, and along which dimension must the 2:4 pattern run?
ResNet-50 on ImageNet scores 76.1 top-1 dense in FP16. After 2:4 pruning and retraining it scores 76.2 in FP16 and 76.2 in INT8 (Mishra et al., Table 2). Half the weights are gone from almost every layer, the GEMMs can run on the sparse path, and the accuracy did not move. The slide's takeaway is the plain version of this: pruning CNNs with 2:4 sparsity brings a large speedup for GEMM workloads and does not incur a performance drop for the models. The rest of this concept explains how that is achieved, how large the speedup really is, and where both claims stop.
The recipe: one prune, one retrain, no search
The deck does not show the procedure itself, so take it from the paper (Mishra et al., section 4) and from the A100 whitepaper, which calls it a simple and universal recipe. It has three steps.
- Train the model without sparsity, exactly as you normally would.
- Prune it to 2:4 by magnitude: in every group of four weights along the row, zero the two with the smallest absolute value.
- Retrain from those weights using the same optimizer, learning-rate schedule and number of epochs as step 1, with the zeros held fixed so the pattern survives. Optimizer state such as momentum is reset.
Two things distinguish this from the Fine-tuning and Iterative pruning you met earlier in this lecture. It is one-shot: a single prune straight to the target, then a full second training run rather than a short low-learning-rate touch-up. And it needs no hyper-parameter search, because step 3 reuses step 1 wholesale. The paper is candid about the cost, a second full training, and argues it is worth paying once for a workflow with nothing to tune, since deployment amortizes it. NVIDIA packages the procedure as the ASP library for PyTorch.
How much faster: a staircase toward 2x
The chart on the slide compares INT8 GEMMs from cuSPARSELt, with one operand in 2:4 form, against dense cuBLAS GEMMs on an A100, at M = N = 10240 and K sweeping from 1280 to 20480. The bars start near 1.2x and climb toward 2x without reaching it. Mishra et al. read it the same way: larger GEMMs achieve nearly a 2x speedup with sparse tensor cores.
| GEMM-K | Speedup |
|---|---|
| 1280 | about 1.2x |
| 2560 | about 1.5x |
| 3840 | about 1.7x |
| 7680 | about 1.8x |
| 12800 | about 1.9x |
| 20480 | about 1.95x |
Why does the speedup depend on K at all, when the pattern halves the multiplies at every size? Because the sparse tensor core halves only the arithmetic. A GEMM also has to move its operands in and its result out, and it pays fixed launch and scheduling costs. A small GEMM has low arithmetic intensity: few operations per byte moved, so its time is dominated by memory traffic and overheads that 2:4 does not touch. As K grows, the operations per output element grow while the output traffic does not, the GEMM becomes math bound, and halving the math approaches halving the time. The paper says exactly this: larger GEMMs tend to have higher arithmetic intensity, so they get closer to the 2x speedup.
Worked example
From GEMM speedup to model speedup with Amdahl
Name the fraction that improves
Suppose GEMMs take 70% of inference time (f = 0.7) and the sparse path makes them 1.8x faster (k = 1.8), a typical large-K reading from the chart.Apply Amdahl's law
S = 1 / ((1 - 0.7) + 0.7 / 1.8) = 1 / (0.3 + 0.389) = 1 / 0.689.Repeat for a small-K layer
With k = 1.2 the GEMM term is 0.7 / 1.2 = 0.583, so S = 1 / 0.883 = 1.13x.Result
About 1.45x end to end at 1.8x on the GEMMs, and only 1.13x when the GEMMs are small. The pattern is doing its job on the math either way; the rest of the network decides what the user sees.
Accuracy: the table that justifies the claim
The right half of the slide is the paper's Table 2: twenty ImageNet classifiers, each in dense FP16, sparse FP16 and sparse INT8. Read down any row and the three numbers agree to within a few tenths of a point; the widest spread is SUNet-128 at 75.6, 76.0 and 75.4. The paper states that the differences are within run-to-run variation, which is the honest way to say zero loss.
| Network | Dense FP16 | Sparse FP16 | Sparse INT8 |
|---|---|---|---|
| ResNet-34 | 73.7 | 73.9 | 73.7 |
| ResNet-50 | 76.1 | 76.2 | 76.2 |
| ResNet-101 | 77.7 | 78.0 | 77.9 |
| ResNeXt-101-32x16 (WSL) | 84.2 | 84.0 | 84.2 |
| DenseNet-121 | 75.5 | 75.3 | 75.3 |
| Inception v3 | 77.1 | 77.1 | 77.1 |
| VGG-16 | 74.0 | 74.1 | 74.1 |
| DRN-105 | 79.4 | 79.5 | 79.4 |
Two details in that table repay attention. Sparse INT8 matches sparse FP16, so the pruning and INT8 quantization, which this course turns to after pruning, compose without compounding their losses, at least on these networks. And the largest model, ResNeXt-101-32x16 trained with weak supervision, loses 0.2 in FP16 and nothing in INT8, so the pattern is not exploiting a weakness of small or old architectures. VGG, DenseNet, Inception, Xception and the dilated residual networks all behave the same way.
| Network | Dense | 2:4, plain recipe | 2:4 with permutation |
|---|---|---|---|
| MobileNet v2 | 71.55 | 69.56 | 71.56 |
| EfficientNet B0 | 77.25 | 75.98 | 77.29 |
Quick check
On the A100 chart, why does the sparse versus dense INT8 GEMM speedup climb toward 2x only as GEMM-K grows?
Recall
State the three steps of NVIDIA's 2:4 recipe and the one hyper-parameter search it needs.
Recall
Why is the INT8 speedup only about 1.2x at K = 1280 but about 1.95x at K = 20480?
Recap
If you remember nothing else
- 2:4 keeps at most two nonzeros in every four consecutive weights along a row: 50 percent sparsity, fine-grained in what it removes, structured in how many it removes.
- Compressed W = R x C/2 values plus R x C/2 two-bit indices. Per group of four, 64 bits become 36 (FP16, about 44 percent saving) and 32 become 20 (INT8, about 38 percent).
- The pattern runs along GEMM-K. The sparse tensor core uses the indices to pick K/2 matching elements of the dense B operand, so only half the multiplies run.
- Peak A100 throughput doubles: FP16 312 to 624 TOPS, INT8 624 to 1248 TOPS.
- Recipe: train dense, prune the two smallest of every four, retrain with the identical schedule keeping the zeros fixed. No hyper-parameter search.
- Sparse FP16 and INT8 match dense FP16 within run-to-run noise on 20 ImageNet CNNs (ResNet-50 76.1 versus 76.2). Small nets like MobileNet v2 need channel permutation to recover.
- INT8 GEMM speedup rises from about 1.2x at K = 1280 to about 1.95x at K = 20480. The 2x caps the math only; end-to-end gains are smaller (about 1.2x for ResNeXt-101 in NVIDIA's blog).
- Versus EIE: a fixed pattern and 2-bit tags on a commodity GPU instead of per-value indices, load balancing and a custom ASIC.
Sources
- Accelerating Sparse Deep Neural NetworksPaperMishra, Albericio Latorre, Pool, Stosic, Stosic, Venkatesh, Yu and Micikevicius, arXiv 20212:4 definition and Fig. 1 format, 36 versus 64 bits, Fig. 2 mapping onto tensor cores, Table 1 TOPS, Fig. 3 speedups, Section 4 recipe, Table 2 accuracy, Table 3 permutation.(opens in a new tab)
- Accelerating Inference with Sparsity Using the NVIDIA Ampere Architecture and NVIDIA TensorRTArticleNVIDIA Technical BlogThree-step recipe, pulling only the necessary values from the uncompressed operand, 1248 versus 624 INT8 TOPS, ResNeXt-101_32x8d up to 20 percent end to end and 36 percent performance per watt.(opens in a new tab)
- NVIDIA Ampere Architecture In-DepthArticleNVIDIA Technical BlogFine-grained structured sparsity, two nonzero values in every four-entry vector, almost 2x memory reduction and doubled tensor core throughput.(opens in a new tab)
- NVIDIA A100 Tensor Core GPU Architecture whitepaperDocsNVIDIASparse MMA on a 16 x 8 x 16 tile in N/2 cycles, 2:4 structured sparsity on rows, the simple and universal recipe.(opens in a new tab)
- cuSPARSELt documentationDocsNVIDIALibrary for GEMMs where one operand is 50 percent structured sparse; FP16, BF16, INT8 and TF32 on SM 8.0 and later, FP8 from SM 9.0.(opens in a new tab)
- EIE: Efficient Inference Engine on Compressed Deep Neural NetworkPaperHan, Liu, Mao, Pu, Pedram, Horowitz and Dally, ISCA 2016CSC with 4-bit relative index and 4-bit weight-sharing code, activation queue for load balance, custom 45 nm ASIC, used for the contrast.(opens in a new tab)
- MIT 6.5940 TinyML and Efficient Deep Learning Computing, Fall 2024, Lecture 4: Pruning and Sparsity (Part II)DocsMIT HAN LabThe course these slides follow.(opens in a new tab)
- Validity of the Single Processor Approach to Achieving Large Scale Computing CapabilitiesPaperAFIPS Conference Proceedings, Vol. 30, 1967The argument behind the end-to-end speedup worked example.(opens in a new tab)
Part 11: Sparse inputs and sparse convolution
Point clouds are mostly empty space, so convolution should compute only where inputs exist: sparse convolution keeps output sparsity equal to input sparsity and is a sparse set of dense matrix multiplies driven by an input, output and weight map.
3 concepts, slides 84-96
Why this part matters
The sparsity in this part is not something you create by pruning or by passing activations through ReLU. It is handed to you by the physical world. A LiDAR scanner on a car returns a few hundred thousand points inside a volume of billions of voxels, and the winning entries on SemanticKITTI, nuScenes and Waymo all process those points with sparse convolution (Tang et al., 2022). If your research project puts 3D perception on an embedded board, this is the operator you will be optimizing.
The part has one story with three turns. First, why an ordinary convolution is the wrong tool for a point cloud: it dilates the empty space into a dense blur within a few layers. Second, the fix, which computes outputs only where inputs exist, and the small bookkeeping structure that describes exactly which multiplications remain. Third, how a GPU actually runs that bookkeeping as a handful of dense matrix multiplies, which is where parts 12 and 13 pick up with TorchSparse and PointAcc. Every idea rests on one list of tuples, so by the end you should be able to write that list for a small grid by hand.
By the end you can
- Explain the submanifold dilation problem with the 1, then 3^d, then 5^d rule and the 17-of-20 example from the slides.
- Define submanifold sparse convolution and state why the output point set equals the input point set.
- Write the update rule f_out = f_out + f_in x W_(dx,dy) and build the (In, Out, Wgt) map for a small grid by hand.
- Group a map by weight offset and cost the resulting gather, matmul, scatter pipeline in MACs.
- Distinguish point-cloud sparsity from ReLU activation sparsity and from pruned weight sparsity.
Start with a number. Voxelize an outdoor LiDAR frame into a regular 3D grid and count how many cells hold at least one point. PointAcc (Lin et al., MICRO 2021) reports that outdoor point clouds usually have a density below 0.01 percent, while a conventional CNN takes in a 100 percent dense image. That is the ~0.01% written above the sparse column of the slide. Indoor scans and single objects sit below 1 percent. Even after ReLU, an ImageNet network still keeps about half of its activations nonzero, so an image is up to four orders of magnitude denser than a LiDAR scan.
How dense the input really is (Lin et al., 2021)
- ImageNet image at the input
- 100 percent of pixels carry a value
- Same network after ReLU
- about 50 percent nonzero on average
- Indoor scene or single object, voxelized
- below 1 percent of voxels occupied
- Outdoor LiDAR frame, voxelized
- below 0.01 percent of voxels occupied
The roadmap places this under activation sparsity, next to EIE and the M:N tensor cores, and that is correct as far as it goes: the zeros are in the data, not the weights. But the source is different in a way that changes everything downstream. ReLU zeros and pruned weight zeros land wherever the arithmetic puts them. Point-cloud zeros are the empty air between surfaces. PointAcc calls this sparsity "fundamentally different" because "the sparsity pattern is constrained by the physical objects in the real world", and draws the consequence that matters here: the nonzero points should never dilate during computation. In the vocabulary of part 07 it is still dynamic, since every frame has a new pattern, but it is a pattern with geometric meaning.
What a dense convolution does to empty space
Now apply an ordinary 3 x 3 convolution to a grid with a single active cell. The kernel window touches that cell from nine different positions, so nine outputs become nonzero. Apply a second layer and the nine become twenty-five. Graham, Engelcke and van der Maaten (CVPR 2018) state the rule in d dimensions: a single active site becomes 3^d active sites after one convolution and 5^d after two. In 3D that is 1, then 27, then 125. They name it the submanifold dilation problem, because a surface (a 2D submanifold in 3D space) thickens into a slab and the sparsity that made the input cheap is gone within a few layers.
The slide shows the same effect on a small grid you can check by eye. The input is 4 rows by 5 columns with four active cells at rows and columns (1, 1), (2, 2), (2, 4) and (3, 3). Each active cell activates every output its 3 x 3 window touches, clipped to the grid: nine for the first two points, six each for the two that sit against an edge. The union of those windows is 17 of 20 cells, exactly the orange region drawn on the conventional side. Only (0, 3), (0, 4) and (3, 0) stay empty, and a second layer would fill those too.
| Stage | Active cells | Density | Why |
|---|---|---|---|
| Input | 4 of 20 | 20 percent | The four teal cells |
| After one dense 3 by 3 layer | 17 of 20 | 85 percent | Union of the four 3 by 3 windows, clipped to the grid |
| After one submanifold 3 by 3 layer | 4 of 20 | 20 percent | Only the four input positions |
| After a second dense layer | 20 of 20 | 100 percent | Every cell now sits within one step of an active cell |
The fix: compute only where an input exists
Sparse convolution, in the submanifold form the deck uses, changes one rule. An output site is computed if and only if the input site at the same coordinate is active. Graham et al. define it exactly that way: the filter size is odd, the input is padded so the output keeps the input's size, and an output is active only when the central site of its receptive field is active. TorchSparse writes the same fact as a set equation, P_in = P_out, against the dense case where P_in is only a subset of P_out. On the slide grid the sparse side stays at four orange cells, and after a hundred layers it would still be four.
The pair of ring images at the bottom of the slide comes from two different figures of the Graham papers. The left ring is Figure 2 of the CVPR 2018 paper (Figure 1 of the 2017 arXiv version): a thin curve pushed through two ordinary 3 x 3 convolutions has smeared into a grey band. The right ring is Figure 3 of the CVPR 2018 paper: the submanifold receptive field centred on one active site, drawn in green, with the empty sites it ignores in red, so the ring stays a ring. That is the whole motivation in one picture: the operator must respect the geometry, or the geometry disappears.
Why a whole part on one operator? TorchSparse's introduction lists the stakes. All top five segmentation submissions on SemanticKITTI and nine of the top ten on nuScenes are built on sparse convolution, yet the operator is not supported by TensorRT or TVM, and the best library of the day ran MinkowskiNet at 8 FPS on a GTX 1080Ti, a desktop GPU far above anything on an embedded board. The gap between what the algorithm avoids and what the hardware delivers is the research territory of parts 12 and 13.
Recall
Why is the output of a submanifold sparse convolution exactly as sparse as its input, and what happens to one active site under two dense 3 by 3 layers instead?
Quick check
A 3 by 3 submanifold sparse convolution runs over four active cells of a 4 by 5 grid. How many output cells are nonzero?
Follow the boxed point P0 at row 1, column 1 through a 3 x 3 convolution. A 3 x 3 kernel is not one weight; it is nine weight matrices, one per tap, each of shape C_in x C_out. TorchSparse writes them as W_δ for each offset δ in {-1, 0, 1}^2. The deck names them W_(dx,dy), with dx the row offset and dy the column offset, and the visual and simulator below use the same labels. Every time P0 lands in an output's window, exactly one of those nine matrices multiplies its feature vector, and which one depends only on where the output sits relative to P0.
The deck's convention, consistent across all nine slides, is that the input P sits at the output Q shifted by the offset: P = Q + (dx, dy) in (row, column). The first entry on the slide makes it concrete. Output Q0 is the top-left corner of P0's window at (0, 0), so P0 = Q0 + (1, 1) and the weight is W_(1,1). The centre entry, where Q4 is P0's own position, uses W_(0,0). The bottom-right corner at (2, 2) uses W_(-1,-1).
The map is the computation
Each such relation is one tuple, and the list of all of them is what the slides call the maps, written (In, Out, Wgt). TorchSparse defines the map for a layer as the set M = {(p_j, q_k, W_δ)} and describes the whole layer as one loop: iterate over the map and, for each entry, accumulate the input feature vector times the entry's weight matrix into the output feature vector. That is the update rule printed at the bottom-left of every slide in this run.
Read the indicator as the map-building test. For each output q_k and each offset δ, look up the coordinate s·q_k + δ. If an input point p_j sits there, the triple (p_j, q_k, W_δ) joins the map; if not, nothing is added and nothing is computed. TorchSparse's Algorithm 1 is exactly this double loop with a hash-table lookup on coordinates. The heading of the slides now reads correctly: a sparse convolution is a sparse set of dense matrix multiply-accumulates, and the sparsity lives entirely in which tuples exist.
Nine entries become two
Now compare the two columns of the slide for P0. The conventional column lists one entry per tap, nine in all, because every cell of P0's window is an output that a dense layer computes. The sparse column applies the submanifold rule from the previous concept: an output must itself be an input position. Inside P0's window only two cells qualify, P0's own position and (2, 2), where P1 sits. So the map keeps exactly two tuples and marks the other seven "No compute".
| Conventional entry | Output position | Conventional | Submanifold sparse |
|---|---|---|---|
| (P0, Q0, W1,1) | (0, 0) | computed | no compute |
| (P0, Q1, W1,0) | (0, 1) | computed | no compute |
| (P0, Q2, W1,-1) | (0, 2) | computed | no compute |
| (P0, Q3, W0,1) | (1, 0) | computed | no compute |
| (P0, Q4, W0,0) | (1, 1) | computed | kept as (P0, Q0, W0,0) |
| (P0, Q5, W0,-1) | (1, 2) | computed | no compute |
| (P0, Q8, W-1,1) | (2, 0) | computed | no compute |
| (P0, Q9, W-1,0) | (2, 1) | computed | no compute |
| (P0, Q10, W-1,-1) | (2, 2) | computed | kept as (P0, Q1, W-1,-1) |
Costing the whole grid, not just P0
The slide follows one point, so extend it to all four. Conventionally each point contributes one entry per in-grid tap: 9 for P0, 9 for the point at (2, 2), 6 for (2, 4) against the right edge and 6 for (3, 3) against the bottom, 30 in total. The submanifold map has one centre entry per point plus one entry for every ordered pair of points within one step of each other. Three such pairs exist, (1, 1) with (2, 2), (2, 2) with (3, 3) and (2, 4) with (3, 3), each counted in both directions, giving 4 + 6 = 10 entries. Each entry is a (1 x C_in)(C_in x C_out) product, so with C_in = C_out = 64 an entry costs 4,096 MACs.
| Method | Entries | MACs | What is counted |
|---|---|---|---|
| Fully dense 3 by 3 over 20 outputs | 20 x 9 = 180 | 737,280 | Every output visits every tap, zeros included |
| Conventional, skipping zero inputs | 9 + 9 + 6 + 6 = 30 | 122,880 | Each point feeds every in-grid output its window touches |
| Submanifold sparse | 4 + 3 x 2 = 10 | 40,960 | Four centre entries plus three neighbouring pairs in both directions |
Two lessons hide in that table. Zero-skipping alone, the trick EIE relied on, already removes most of the work on this grid, but it still writes the dilated 17-cell output and so the next layer starts from 17 points instead of 4. The submanifold map is the only row whose cost stays proportional to the number of points layer after layer. On a real LiDAR frame with hundreds of thousands of points in a grid of billions of voxels, the fully dense row is not merely slow; it does not fit in memory.
Symmetry check: W-1,-1 has 2 entries and W1,1 has 2.
Click cells to place or remove points, then pick a kernel offset. The list shows every map entry for that weight using the deck's convention: input P sits at output Q shifted by the row and column offset (dx, dy), and the output must itself be an input position. The counts in the offset picker are the row counts of the gathered matrices on slide 96, so the number of non-empty offsets is the number of separate matmuls the existing GPU implementation launches. Compare the three MAC readouts: fully dense visits every cell, conventional zero-skipping still fills the dilated set, and submanifold pays only for entries whose output is a real point.
Recall
Write the sparse convolution update rule and name every symbol in it.
Recall
On slide 95, how many map entries does P0 have conventionally and sparsely, and why?
Quick check
In the entry (P0, Q1, W-1,-1) with the deck's convention P = Q + (dx, dy), where is Q1 relative to P0?
Quick check
Which statement about submanifold sparse convolution is correct?
Slide 95 closes the P0 story with a count, nine matrix multiplications against two, and slide 96 asks the practical question: how does a GPU run a list of tuples? Take its workload, a 5 x 5 grid with five points P0 at (1, 1), P1 at (2, 2), P2 at (2, 4), P3 at (3, 2) and P4 at (4, 3). Its map has eleven entries, and the box on the slide lists them not in point order but sorted by weight offset. That ordering is the whole idea.
Running the update rule one entry at a time means eleven vector-matrix products, each a single row of C_in values against a C_in x C_out matrix. TorchSparse notes that the utilization of matrix-vector multiplication is rather low on a GPU, whose tensor cores want tall matrices on both sides. The escape is to notice that entries sharing the same offset share the same matrix. Stack their input rows into one contiguous matrix, multiply it by that one W_δ, and you have turned several vector-matrix products into one matrix-matrix product. Grouping by output or by input would not work: entries with the same output use different weights, and so do entries with the same input.
| Weight | Entries (In, Out) | Rows gathered | Note |
|---|---|---|---|
| W-1,-1 | (P0, Q1), (P3, Q4) | 2 | highlighted on the slide |
| W-1,0 | (P1, Q3) | 1 | mirror of W1,0 |
| W0,0 | (P0, Q0), (P1, Q1), (P2, Q2), (P3, Q3), (P4, Q4) | 5 | one entry per point, no data movement |
| W1,0 | (P3, Q1) | 1 | mirror of W-1,0 |
| W1,1 | (P1, Q0), (P4, Q3) | 2 | mirror of W-1,-1 |
| W-1,1, W0,1, W0,-1, W1,-1 | none | 0 | no kernel launch at all |
Five of the nine offsets have entries, so this layer launches five matmuls with 2, 1, 5, 1 and 2 rows. The other four offsets have empty maps and launch nothing. Notice too that P2 at (2, 4) has no neighbour within one step, so it appears only in the W_(0,0) group: an isolated point costs exactly one entry.
Gather, matmul, scatter
The pipeline on slide 96 is the gather, matmul, scatter flow that every existing GPU implementation follows, written out for the highlighted offset W_(-1,-1). Its two entries are (P0, Q1) and (P3, Q4). Gather copies rows P0 and P3 out of the 5 x C_in input feature matrix into a 2 x C_in buffer. Matmul multiplies that buffer by the C_in x C_out weight to produce a 2 x C_out partial sum. Scatter adds row one into output Q1 and row two into Q4, which is the pair of equations under the figure: f1 = f1 + f0 x W_(-1,-1) and f4 = f4 + f3 x W_(-1,-1). Then the next offset takes its turn with its own rows.
Worked example
Costing the W(-1,-1) group with C_in = C_out = 64
Gather
Read rows P0 and P3 of the 5 x 64 input matrix into a 2 x 64 buffer: 128 values moved, no arithmetic.Matmul
Multiply the 2 x 64 buffer by the 64 x 64 matrix W_(-1,-1): 2 x 64 x 64 = 8,192 MACs, producing a 2 x 64 partial sum.Scatter-add
Add partial-sum row one into f1 and row two into f4: 128 additions into the 5 x 64 output matrix.Repeat for the other four non-empty offsets
Rows gathered are 1, 5, 1 and 2, so the layer does 11 row-matrix products in five kernel launches.Layer cost
11 x 4,096 = 45,056 MACs, against 159,744 for a zero-skipping conventional convolution on the same five points and 921,600 for a fully dense 3 x 3 over all 25 cells.
| Method | Entries | MACs |
|---|---|---|
| Fully dense 3 by 3 over 25 outputs | 25 x 9 = 225 | 921,600 |
| Conventional, skipping zero inputs | 9 + 9 + 6 + 9 + 6 = 39 | 159,744 |
| Submanifold sparse, 5 matmuls | 2 + 1 + 5 + 1 + 2 = 11 | 45,056 |
The slide's heading calls this weight-stationary: the weight matrix for one offset stays put while the gathered rows stream through it, and a separate matmul runs for each different weight. TorchSparse's Algorithm 2 is literally a loop over offsets that performs gather, matmul and scatter for each. The rule book in Graham et al. is the same design described from the sparse-convolution side: for each row (j, k) in the rule for offset i, multiply row j of the input matrix by W^i and add it to row k of the output, which they note runs efficiently on a GPU precisely because it is a matrix-matrix multiply-add. SECOND (Yan et al., 2018) moved the rule generation itself from a CPU hash table to the GPU, since the CPU version was slow and required data transfer between CPU and GPU on every layer.
A symmetry you can check on the slide
Look at the row counts again: W_(-1,-1) and W_(1,1) both have two rows, W_(-1,0) and W_(1,0) both have one. That is not luck. If (P, Q, W_δ) is an entry, then P and Q are both points and Q = P + (-δ), so (Q, P, W_(-δ)) is also an entry. TorchSparse section 4.2.1 proves this one-to-one correspondence for any odd kernel at stride 1, and the (0, 0) map is special for a second reason: every point maps to itself, so it needs no gather and no scatter at all. Part 12 builds its first optimization on exactly this pairing, and the simulator above reports the check on every grid you draw.
Recall
Name the three stages of the existing GPU implementation and explain why entries are grouped by weight offset.
Recall
From the slide 96 list, how many matmuls does the layer launch and with how many rows each?
Quick check
Why does the GPU implementation group map entries by weight offset before multiplying?
- Entries: for stride 1 with an odd kernel, count(δ) = count(-δ), and the (0, 0) map has exactly one entry per point.
- Matmuls per layer: the number of offsets whose map is non-empty, at most K^D.
- MACs per layer: total entries times C_in x C_out, independent of how the entries are grouped. Grouping changes utilization and data movement, never the arithmetic count.
Recap
If you remember nothing else
- Outdoor LiDAR voxel grids are below 0.01 percent dense; ImageNet inputs are 100 percent dense and about 50 percent after ReLU.
- Dense convolution dilates: one active site becomes 3^d, then 5^d; on the slide grid 4 of 20 cells become 17 of 20 after one 3 by 3 layer.
- Submanifold sparse convolution computes outputs only at input positions, so P_out = P_in and nothing dilates.
- The computation is a map of (In, Out, Wgt) entries with P = Q + (dx, dy); each entry does f_out = f_out + f_in x W_(dx,dy).
- For P0 on slide 95: 9 conventional entries, 2 sparse entries. Whole 4 by 5 grid: 30 versus 10.
- Entries sharing W_(dx,dy) are gathered into one matrix, multiplied once, then scatter-added (weight-stationary). Slide 96: 11 entries, five matmuls with 2, 1, 5, 1, 2 rows.
- At stride 1 with an odd kernel, the maps for an offset and its mirror always have equal size.
- Per-offset matmuls are irregular and gather plus scatter can take up to 50 percent of runtime: the problems TorchSparse and PointAcc attack in parts 12 and 13.
Sources
- TorchSparse: Efficient Point Cloud Inference EnginePaperMLSys 2022, Tang, Liu, Li, Lin and HanEq. 1, the map definition, Algorithms 1 and 2, gather-matmul-scatter, symmetric offsets in section 4.2.1, the 8 FPS and 50 percent figures.(opens in a new tab)
- 3D Semantic Segmentation with Submanifold Sparse Convolutional NetworksPaperCVPR 2018, Graham, Engelcke and van der MaatenSubmanifold dilation problem, 3^d then 5^d, the SSC definition, the receptive-field figure on the right of slide 86 and the rule book.(opens in a new tab)
- Submanifold Sparse Convolutional NetworksPaperarXiv 2017, Graham and van der MaatenOrigin of the ring-dilation figure reproduced on the left of slide 86.(opens in a new tab)
- Sparse 3D convolutional neural networksPaperBMVC 2015, GrahamThe paper the slide credit actually points to; its convolutions still dilate.(opens in a new tab)
- PointAcc: Efficient Point Cloud AcceleratorPaperMICRO 2021, Lin, Zhang, Tang, Wang and HanDensity below 0.01 percent outdoors, sparsity constrained by physical objects, nonzero points never dilate.(opens in a new tab)
- SECOND: Sparsely Embedded Convolutional DetectionPaperSensors 2018, Yan, Mao and LiGPU rule generation replacing the CPU hash table, and the gather, GEMM, scatter flow.(opens in a new tab)
- 4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural NetworksPaperCVPR 2019, Choy, Gwak and SavareseGeneralized sparse convolution and the MinkowskiNet model that TorchSparse benchmarks at 8 FPS on a GTX 1080Ti.(opens in a new tab)
- SparseConvNetDocsFacebook Research, GitHubStates that the set of active sites is unchanged by submanifold convolution and that inactive sites carry no computational overhead.(opens in a new tab)
- TorchSparse repositoryDocsMIT HAN Lab, GitHubReference implementation of the maps and the gather-matmul-scatter pipeline.(opens in a new tab)
- MIT 6.5940 TinyML and Efficient Deep Learning Computing, Lecture 4DocsMIT HAN LabThe lecture whose slides 84 to 96 this deck mirrors, including the BMVC 2015 credit line.(opens in a new tab)
Part 12: TorchSparse: regular computation from irregular sparsity
The gather, matmul, scatter pipeline on GPUs, why separate small matmuls waste the GPU, and how TorchSparse trades a little padding for regularity with adaptive grouping, locality-aware access and, in TorchSparse++, overlapped memory and compute.
3 concepts, slides 97-109
Why this part matters
Your research on embedded machine learning will meet sparse, irregular workloads long before it meets a textbook dense matrix: LiDAR sweeps, radar returns, event cameras, pruned weights. This part is about a systems pattern rather than a library. Irregular work is made regular by paying a controlled amount of redundant computation, and the right amount is found by measurement, not by assuming zero.
Part 11 ended with the map: the list of (input, output, weight offset) tuples that turns sparse convolution into a sparse set of dense matrix multiplies. Here we follow how a GPU actually executes that list, why the obvious execution wastes most of the device, and how TorchSparse and its successor recover the loss. The same reasoning returns whenever you schedule uneven work on an edge GPU such as a Jetson Orin, and the exam angle is direct: name the phases, explain the waste, describe the fix.
By the end you can
- Trace one weight offset through gather, matmul and scatter using the map, giving the buffer and partial-sum shapes.
- Explain why 27 small matmuls and per-offset gathers underuse a GPU, quoting the paper's utilization figure.
- Place separate computation, dense convolution and adaptive grouping on the overhead versus regularity spectrum and compute pad rows for a small example.
- Read the matmul ablation and say why TFLOP/s and speedup can disagree.
- Describe what TorchSparse++ overlaps and name its two components.
Keep the small example from part 11 in view. Five input points P0 to P4, five output points Q0 to Q4, a 3 x 3 kernel, so nine weight offsets from W(-1,-1) to W(1,1). The map for this layer has eleven tuples. Two of them belong to W(-1,-1), one to W(-1,0), five to W(0,0), one to W(1,0), two to W(1,1), and the other four offsets have no entry at all in this tiny cloud.
The existing GPU implementation walks that list one weight at a time. It is weight-stationary: pick an offset, hold its C_in x C_out matrix still, and stream every map entry for that offset through it. Take W(-1,0). Its only entry is (P1, Q3), so the engine copies the single feature row f1 into a buffer of shape 1 x C_in, multiplies it by W(-1,0) to get one partial sum of shape 1 x C_out, and adds that row into Q3. Now take W(0,0). With stride 1 every input point sits on top of its own output, so the centre map contains all five entries. The buffer is the whole 5 x C_in input, the matmul is full height, and five partial sums land one to one in Q0 to Q4. Then W(1,0) with only (P3, Q1), then W(1,1) with (P1, Q0) and (P4, Q3), a 2 x C_in buffer whose two results go to two different output rows.
That is the whole rule, and it is the same three phases every time. The names are the ones the lecture and the paper use: gather, matmul, scatter. For each weight offset delta, gather the |M_delta| input rows named by the map into a contiguous buffer, run one dense matrix multiplication of the |M_delta| x C_in buffer by the C_in x C_out weight, and scatter-accumulate the |M_delta| x C_out partial sums into the output rows named by the map. Written as an update rule over the whole map:
The three phases and what bounds each one
- Gather
- Read the |M_delta| input rows named by the map into a contiguous buffer. Random reads, bound by memory bandwidth.
- Matmul
- Multiply the |M_delta| x C_in buffer by the C_in x C_out weight. Dense FLOPs, but small and uneven per offset.
- Scatter-accumulate
- Add the |M_delta| x C_out partial sums into the output rows named by the map. Random writes with accumulation, bound by memory bandwidth.
In three dimensions the loop is longer. A 3 x 3 x 3 kernel has 27 offsets, and slide 105 notes that the centre (0,0,0) is usually computed separately because, at stride 1, its map is simply the identity over all points, leaving 26 irregular offsets. Because point-cloud occupancy is dynamic sparsity, the maps are built at run time for every scan, so the engine cannot precompute a fixed schedule the way it could for pruned weights.
Why this wastes most of the GPU
The baseline is correct and simple, and Tang et al. measured exactly where it loses. Two bottlenecks share the blame. First, the matmuls are non-uniform. The paper reports that map sizes for different weights can differ by an order of magnitude and that most map sizes are small, so each launch is a short, narrow matrix that cannot fill the device: MinkUNet 0.5x on an RTX 2080 Ti in FP16 reaches 8.1 TFLOP/s, only about 30 percent device utilization, with the matmul phase taking 20 to 50 percent of runtime (Tang et al., MLSys 2022, section 3). NVIDIA's own cuBLAS guidance says the same thing from the other side: when the matrices are small, the small matrix size prevents the GPU from being fully utilized, and launching them one after another produces many kernels launched in sequence (NVIDIA Developer Blog).
Second, and larger, gather and scatter are memory-bound. Each one is a random access pattern over the feature tensor, bottlenecked by GPU memory bandwidth rather than by computation resources, and together they take 40 to 50 percent of runtime. Worse, because every offset gathers and scatters on its own, the data movement is completely separated from one offset to the next: a row like f1 that appears in the maps of W(-1,0), W(0,0) and W(1,1) is fetched three times from off-chip memory with nothing reused (Tang et al., MLSys 2022, section 3).
Worked example
Nine offsets, eleven map entries
Group the map by offset
W(-1,-1): (P0, Q1), (P3, Q4). W(-1,0): (P1, Q3). W(0,0): all five. W(1,0): (P3, Q1). W(1,1): (P1, Q0), (P4, Q3). Four offsets are empty.Shape each launch
Buffers are 2 x C_in, 1 x C_in, 5 x C_in, 1 x C_in and 2 x C_in. Each matmul has the same C_in x C_out weight but a different row count, and each writes exactly as many partial-sum rows as it read.Count the kernels
Five non-empty offsets means five gathers, five matmuls and five scatters, fifteen launches for eleven accumulations. In a real layer with 26 non-centre offsets and maps of thousands of rows the count is 78 launches per layer, most of them short.Where the time goes
Roughly half of it in gather and scatter, memory-bound and unshared between offsets, and the rest in matmuls that run the tensor cores at a fraction of capacity because the rows per launch are few and uneven.
Recall
Name the three phases of the baseline GPU sparse convolution and say which two are memory-bound.
Recall
In a 3D 3x3x3 layer, how many separate matmuls does the baseline launch, and why do they underuse the GPU?
Quick check
Why does the baseline gather-matmul-scatter pipeline underuse a GPU?
Look at the same five features one more time, now the way TorchSparse runs them. The gather step still builds one buffer per offset, but adaptive grouping pads those buffers to a shared height, so the four small offsets become four buffers of exactly two rows each: {F0, F3} for W(-1,-1), {F1, pad} for W(-1,0), {F3, pad} for W(1,0) and {F1, F4} for W(1,1). Two of those rows are dashed: a pad, a row of zeros inserted so that every buffer has the same height. Because the four buffers now share a shape, one batched matrix multiplication (bmm, batch 4) runs all four at once. The centre weight W(0,0), whose buffer holds all five rows, runs as an ordinary matrix multiplication (mm). Partial sums PSUM 0 to PSUM 4 are scattered back with the same locality-aware access, and the two pad rows produce two blank partial-sum slots that nobody reads.
Those two dashed rows are the price. Two zero rows were multiplied for nothing so that five matmul launches became two. That is the entire idea of this concept, and the paper names it in the slide title: trading computation for regularity. The overview on slide 101 lists three techniques, locality-aware gather, adaptive grouping of the matmuls, and locality-aware scatter-accumulate. The first and last attack the memory-bound half of the runtime by reading and writing feature rows in an order that keeps neighbouring accesses close and by fusing and vectorizing them; the paper reports the cost of memory movement cut by 2.7x that way (Tang et al., MLSys 2022, abstract). The middle technique, grouping, is what the rest of this concept builds up.
The spectrum: separate, dense, grouped
Slides 102 to 104 draw seven weight offsets as seven columns of unequal height, one row per map entry, and put each execution strategy on two sliders: computation overhead and computation regularity. Separate computation, the baseline of the previous concept, launches one mm per column. Nothing is padded, so its overhead slider sits at best, but seven uneven kernels put its regularity at worst: many kernel calls, low device utilization. Dense convolution goes to the other end. Pad every column up to the tallest and run a single bmm with batch 7. Regularity is perfect, one launch, but the dashed rows now outnumber the real ones in the short columns, and overhead sits at worst. Computation with grouping refuses both extremes. The tallest column keeps its own mm. The four columns of similar height are padded by a total of two rows and run as one bmm with batch 4. The two shortest, equal already, form a bmm with batch 2. Slide 104 counts the cost: extra computation of 2 / 28, about 7 percent, for cutting seven launches to three.
| Strategy | Kernel launches | Padded rows | Computation overhead | Computation regularity |
|---|---|---|---|---|
| Separate computation | 7 | 0 | Best (none) | Worst (many tiny kernels) |
| Dense convolution | 1 | Every column padded to the tallest | Worst | Best (one bmm, batch 7) |
| Computation with grouping | 3 | 2 pad rows in the batch-4 group (2 / 28) | Small | High (mm, bmm x4, bmm x2) |
How the groups are chosen
Grouping only pays when the columns in a group really are similar, so the question becomes how similar is similar enough. TorchSparse answers with two auto-tuned parameters. The first, epsilon, is the tolerance of redundant computation. Walk the offsets in kernel order and scan them once with two pointers, extending the current group while the redundant computation ratio stays at or below epsilon and starting a new group the moment adding the next offset would exceed it (Tang et al., MLSys 2022, section 4.2.3). The groups are therefore contiguous runs of weight indices, which is why the red boxes on slide 105 sit side by side along the weight axis; the tuner below and the slide 104 figure instead order the offsets by map size first, a simplification that makes the pad rows easier to see.
The second parameter, S, is a workload threshold. A group runs as bmm only if its largest map is below S; otherwise it runs as mm, because bmm improves device utilization for small workloads but has little benefit once a single matmul is already large enough to fill the GPU. The two knobs contain the whole spectrum as special cases: epsilon = 1 with S unbounded is dense convolution, S = 0 is separate computation, and epsilon = 0 with S unbounded is what the paper calls symmetric grouping. That last case is free: for an odd kernel size at stride 1 the map for offset (a, b, c) has exactly the same size as the map for (-a, -b, -c), since every pair of neighbours appears once in each direction, so 26 offsets collapse into 13 groups of two with no padding at all, worth up to about 1.2x (Tang et al., MLSys 2022, section 4.2.2).
Worked example
Nine offsets on a 100-point cloud
Map sizes
N = 100 points, stride 1, so W(0,0) maps all 100. Symmetric pairs share sizes: W(-1,0) = W(1,0) = 40, W(0,-1) = W(0,1) = 38, W(-1,-1) = W(1,1) = 12, W(-1,1) = W(1,-1) = 11. Real rows: 100 + 2(40 + 38 + 12 + 11) = 302.Separate computation
Nine launches, 302 rows computed, zero pad rows, overhead 0 percent.Dense convolution
One bmm of batch 9 with every offset padded to 100: 900 rows computed, 598 of them pad, overhead 598 / 900 = 66.4 percent. The redundant ratio is 1 - 302 / 900, the same number.Adaptive grouping with epsilon 0.05 and S = 50
W(0,0) exceeds S, so it runs alone as mm: 100 rows. Group A {40, 40, 38, 38} padded to 40: 160 rows, 4 pad, ratio 1 - 156 / 160 = 0.025. Adding a 12 would push the ratio to 0.16, so a new group starts. Group B {12, 12, 11, 11} padded to 12: 48 rows, 2 pad, ratio 0.042.Three launches for two percent
3 launches, 308 rows computed, 6 pad rows, overhead 6 / 308 = 1.9 percent. Nine launches shrink to three at a cost that rounds to nothing.
| Strategy | Launches | Rows computed | Pad rows | Overhead |
|---|---|---|---|---|
| Separate (one mm per offset) | 9 | 302 | 0 | 0% |
| Dense (one bmm, batch 9, padded to 100) | 1 | 900 | 598 | 66.4% |
| Adaptive (epsilon 0.05, S = 50) | 3 | 308 | 6 | 1.9% |
Try the knobs yourself. The tuner below starts from exactly this example, and rerolling draws new map sizes so you can watch which groups form as epsilon and S move.
- mm100
- bmm x440, 40, 38, 38 +4 pad
- bmm x412, 12, 11, 11 +2 pad
The tuner sorts the offsets by map size for clarity; the paper's Algorithm 4 scans them in kernel order. Either way the scan is a single pass. A new group starts whenever adding the next offset would push the redundant computation ratio, 1 minus real rows over computed rows, above epsilon. Any offset whose map is larger than S runs alone as a plain mm, because batching only helps small workloads. Dashed teal blocks are pad rows: real multiplications on zero rows, bought to turn several launches into one. The time model is a teaching device, not a measurement; the shape it produces (zero padding is not the optimum, and neither is one group) is what slide 105 measured on a real GPU.
Measured: neither zero padding nor one group wins
Slide 105 is the experiment that settles the question. On the first sparse convolution layer of MinkUNet on SemanticKITTI, the paper sweeps the number of groups from 26 (no padding, the separate baseline at 1.0x) down to 1 (fully dense). Going from 26 to 13 groups gives about 1.2x, the symmetric pairing. At 6 groups the speedup peaks near 1.5x. Then it collapses: 3 groups fall below the baseline and 1 group runs at about 0.35x, worse than doing nothing. The slide annotates the two slopes as increasing regularity helps improve latency, then padding overhead hurts latency (Tang et al., MLSys 2022, Figure 7).
The two bar charts under the curve explain why the answer is adaptive rather than fixed. They plot map size against weight index 1 to 27 for a MinkUNet layer on two datasets, with red boxes marking the groups the tuner chose. SemanticKITTI maps are large, mostly in the thousands, and the boxes are narrow: 10 groups. nuScenes maps are an order of magnitude smaller, hundreds rather than thousands, so each launch is even less able to fill the GPU and the tuner groups more aggressively: 8 groups with wider boxes (Tang et al., MLSys 2022, Figure 12). The right amount of padding is a property of the data, which is why it is searched per model and per dataset instead of fixed in code.
Recall
What do epsilon and S control in adaptive grouping?
Quick check
In adaptive grouping, what happens when you raise the tolerance epsilon?
Slides 106 and 107 isolate the matmul phase and ask a sharp question: on an RTX 2080 Ti in FP16, how much did grouping actually buy? Three strategies are compared, the separate baseline, a fixed grouping with three hand-made groups per layer type padded to their maximum, and adaptive grouping. Each is reported twice, as throughput in TFLOP/s and as normalized speedup, and the two columns disagree in an instructive way.
| Dataset | Strategy | TFLOP/s | Normalized speedup |
|---|---|---|---|
| SemanticKITTI | Baseline (separate) | 8.1 | 1.00x |
| SemanticKITTI | Fixed grouping | 8.7 | 0.87x |
| SemanticKITTI | Adaptive grouping | 11.9 | 1.39x |
| nuScenes | Baseline (separate) | 10.4 | 1.00x |
| nuScenes | Fixed grouping | 21.1 | 1.50x |
| nuScenes | Adaptive grouping | 16.9 | 1.54x |
On SemanticKITTI (MinkUNet 0.5x) adaptive grouping lifts throughput from 8.1 to 11.9 TFLOP/s and finishes 1.39x faster. Fixed grouping is the trap: it posts a higher throughput than the baseline, 8.7 TFLOP/s, yet is slower, 0.87x. On nuScenes (MinkUNet, three frames) the trap is sharper still. Fixed grouping reaches the best throughput of the whole table, 21.1 TFLOP/s, and adaptive grouping only 16.9, yet adaptive is the faster of the two at 1.54x against 1.50x. Slide 107 gives the reason in one line: fixed grouping introduced a large amount of redundant computation. TFLOP/s counts every multiply the tensor cores performed, pad rows included. A strategy can therefore look excellent on throughput while spending that throughput on zeros. Latency counts only the clock, and the paper's caption puts it precisely: as we trade FLOPs for regularity, TFLOP/s and speedup are non-proportional (Tang et al., MLSys 2022, Table 2). Device utilization for the matmul phase rose from about 30 percent to 44.2 percent with adaptive grouping.
End to end, with locality-aware gather and scatter included, the paper reports 1.6x over MinkowskiEngine and 1.5x over SpConv across seven models and three datasets, measured on GTX 1080 Ti, RTX 2080 Ti and RTX 3090, with up to 2.16x on segmentation models over MinkowskiEngine on the RTX 3090 (Tang et al., MLSys 2022, abstract and section 5). These figures are not on the slides; the slides show only the matmul ablation, so quote them as the paper's, and note that the MLSys 2022 evaluation used desktop GPUs only. The edge numbers come with the successor.
Recall
Fixed grouping reached 21.1 TFLOP/s on nuScenes and adaptive grouping only 16.9. Which was faster, and why?
Quick check
On nuScenes, fixed grouping posted the highest TFLOP/s yet adaptive grouping finished faster. Why?
TorchSparse++: overlap memory with computation
Grouping fixed the matmul phase, but the baseline still has a structural flaw that no grouping removes: the three phases of gather, matmul and scatter run one after another. Gather must finish before the matmul starts, and the matmul must finish before scatter starts, three separate CUDA kernel calls in each iteration of the host loop. While the memory system is busy gathering, the tensor cores wait; while the tensor cores multiply, the memory system idles. The MICRO 2023 paper calls gather-GEMM-scatter fundamentally inefficient due to the lack of overlap between computation and memory access (Tang, Yang et al., MICRO 2023, section 2.2). The remedy in TorchSparse++ is to stop treating the phases as separate kernels.
Two fused dataflows already existed in other engines, and TorchSparse++ builds on both. Fetch-on-demand, used by MinkowskiEngine, merges gather, multiply and scatter into a single kernel that loads only the input rows it needs straight into shared memory, multiplies on chip and scatters results from registers, with zero redundant computation but heavy output write traffic, 4x to 10x more than the theoretical minimum of one write per output row, since each point has 4 to 10 neighbours and every partial sum is written back individually. Implicit GEMM, used by SpConv v2, is output-stationary: each thread block owns a tile of output rows, walks the nine (or 27) weights, and fetches the matching input rows on demand, the way im2col does for dense convolution. It writes each output once and hides memory latency by pipelining, so the loads for the next tile are already in flight while the tensor cores work on the current tile (Tang, Yang et al., MICRO 2023, section 2.2 and Figure 3). That in-kernel double buffering is the overlap the slide title refers to.
| Dataflow | Stationary | Kernel structure | Memory and compute | Redundant computation |
|---|---|---|---|---|
| Gather-GEMM-scatter | Weight | Three kernels per offset, vendor GEMM | No overlap between memory access and compute | Zero |
| Fetch-on-demand | Weight (fused per offset) | One fused kernel, rows fetched into shared memory | Loads overlap with on-chip multiply | Zero, but 4x to 10x more output writes |
| Implicit GEMM | Output | One fused kernel, im2col style, pipelined tiles | Loads for the next tile overlap the current one | Lockstep redundancy inside each warp |
The catch with implicit GEMM is a new kind of redundancy, and slide 109 shows it. Rows are output points B0 to B7, columns are the nine weights, and a grey cell is a real multiply because the input neighbour A_j exists. Threads in a warp execute in lockstep, so if any row in a thread block needs a weight, every row in that block runs it. The red cells are those wasted lockstep multiplies: 12 in the vanilla layout. Row reordering sorts the outputs by their neighbour bitmask so rows with similar patterns share a block, cutting the count to 10. Column splitting then divides the loop over the nine weights into three parts, each sorted on its own, so a row is grouped with different neighbours for different weight subsets: 8. The paper's own example runs 34 to 26 to 22 multiplies and reports that bitmask sorting can cut redundancy by up to 3x (Tang, Yang et al., MICRO 2023, Figures 5, 6 and 10). The fused kernel keeps its overlap; these two reorderings trim what it pays for it.
Writing such kernels by hand is expensive. SpConv v2 needed more than 40,000 lines re-implementing CUTLASS. TorchSparse++ therefore contributes two components, both drawn on slide 108. The Sparse Kernel Generator produces the fused, pipelined kernels automatically at under a tenth of that engineering cost, adapting dense GEMM templates to sparse gather (dense-to-sparse adaptation) and static shapes to run-time maps (static-to-dynamic adaptation). The Sparse Autotuner widens the design space (gather-GEMM-scatter with grouping, fetch-on-demand, implicit GEMM, and their tile and split parameters) and tunes a configuration per group of layers rather than per layer, so the search stays cheap (Tang, Yang et al., MICRO 2023, sections 3 and 4).
| GPU | MinkowskiEngine | SpConv 1.2.1 | TorchSparse | SpConv 2.3.5 | TorchSparse++ |
|---|---|---|---|---|---|
| A100 | 0.34 | 0.30 | 0.45 | 0.60 | 1.00 |
| Jetson Orin | 0.19 | 0.29 | 0.40 | 0.80 | 1.00 |
Reading the A100 column the other way round, TorchSparse++ is 2.9x faster than MinkowskiEngine, 3.3x faster than SpConv 1.2.1, 2.2x faster than TorchSparse and 1.7x faster than SpConv 2.3.5, the four numbers the paper's abstract reports. The Orin column is the one that matters for this course: on the Jetson Orin edge GPU, the strongest baseline, SpConv 2.3.5, sits at 0.80, so TorchSparse++ is 1.25x faster on average, with a consistent 1.3x to 1.4x on detection workloads (Tang, Yang et al., MICRO 2023, section 5). The chart also shows training columns and a TF32 column; the same engine covers all of them.
One more step remains beyond software. Every engine in this part still spends time building the maps themselves, a hashing or sorting problem the GPU is not shaped for. Part 13 moves that step into hardware with PointAcc, whose mapping unit produces the tuples with merge sort.
Recall
What does TorchSparse++ overlap, and with which two components?
Quick check
What does TorchSparse++ change about the three phases?
Recap
If you remember nothing else
- The baseline runs gather, matmul and scatter once per weight offset: 27 offsets in 3D, each a separate small kernel.
- Gather and scatter are memory-bandwidth bound (40 to 50 percent of runtime); the matmuls are dense but tiny and uneven (about 30 percent utilization).
- Padding offsets of similar size into one batched matmul trades FLOPs for regularity; dense batching pads everything and loses.
- Adaptive grouping scans map sizes with a tolerance epsilon and a threshold S; 6 groups beat both 26 and 1 on SemanticKITTI, about 1.5x.
- Matmul ablation: adaptive grouping 1.39x on SemanticKITTI and 1.54x on nuScenes; fixed grouping can post higher TFLOP/s and still be slower.
- TorchSparse end to end: 1.6x over MinkowskiEngine and 1.5x over SpConv, with 2.7x less memory movement cost.
- TorchSparse++ fuses the phases so memory access overlaps computation, generates the kernels automatically and autotunes the dataflow: 2.9x, 3.3x, 2.2x and 1.7x on A100, 1.25x over SpConv v2 on Jetson Orin.
- Row reordering and column splitting cut implicit-GEMM redundancy from 12 to 10 to 8 on the slide's example.
Sources
- TorchSparse: Efficient Point Cloud Inference EnginePaperProceedings of MLSys 2022, Tang, Liu, Li, Lin and HanSection 3 bottleneck analysis, section 4.2 adaptive grouping with epsilon and S, Table 2 ablation, Figures 7 and 12.(opens in a new tab)
- TorchSparse: Efficient Point Cloud Inference Engine (arXiv abstract)PaperarXiv1.4 to 1.5x matmul speedup, 2.7x lower memory movement cost, 1.6x and 1.5x end to end over MinkowskiEngine and SpConv.(opens in a new tab)
- TorchSparse++: Efficient Training and Inference Framework for Sparse Convolution on GPUsPaperMICRO 2023, Tang, Yang, Liu, Tang, Zhu, Lu, Ren, Wang, Xu, HanThree dataflows and their overlap (section 2.2, Figure 3), row reordering and column splitting (Figures 5, 6, 10), kernel generator and autotuner, 2.9x, 3.3x, 2.2x, 1.7x on A100 and 1.25x on Jetson Orin.(opens in a new tab)
- TorchSparse++ (ACM DL record)PaperACM, MICRO 2023Publisher's version of the MICRO 2023 paper.(opens in a new tab)
- TorchSparse repositoryDocsMIT HAN Lab, GitHubReference implementation of both engines.(opens in a new tab)
- MIT 6.5940 TinyML and Efficient Deep Learning Computing, Fall 2024, Lecture 4: Pruning and Sparsity Part IIDocsMIT HAN LabSource deck for slides 101 to 109, including the 12, 10, 8 redundancy example on slide 109.(opens in a new tab)
- MIT 6.5940 Lecture 4 recordingVideoMIT HAN Lab, YouTubeSong Han walks through the TorchSparse slides.(opens in a new tab)
- cuBLAS Strided Batched Matrix MultiplyArticleNVIDIA Developer BlogSmall GEMMs cannot fill the GPU, and sequential launches of many small kernels are slow; the motivation for batched matmul.(opens in a new tab)
- cuBLAS documentation: batched GEMMDocsNVIDIAThe bmm primitive that grouped offsets are executed with.(opens in a new tab)
- CUDA C++ Best Practices GuideDocsNVIDIACoalesced memory access and latency hiding, the principles behind locality-aware access and pipelined fused kernels.(opens in a new tab)
Part 13: PointAcc, the lecture summary and references
PointAcc builds the sparse convolution map in hardware with a merge-sort based mapping unit, then the lecture closes with what was covered and what quantization brings next.
4 concepts, slides 110-115
Why this part matters
Every accelerator in this lecture so far assumed the hard part was the multiply. PointAcc is the case where it is not. When the input is a point cloud, the network spends most of its time deciding which inputs multiply which weights, and that decision has to be remade for every frame because the sparsity is in the data. Your embedded work will hit the same wall the moment your inputs stop being dense grids.
This closing part does three things. It shows how PointAcc turns map construction into a sorting problem the hardware can stream, with the five-point example from slides 111 and 112 worked out to the last tuple. It reads the results slide the way the paper intends, with the right baselines. Then it folds the whole lecture into one table, so that the exam question "which system exploits which sparsity" has a single place to be answered from, and it checks the reference slide against what the deck actually cited.
By the end you can
- Explain why building the (In, Out, Wgt) map dominates point-cloud inference and why a hash table is a poor fit for silicon.
- Run the shift, merge sort, compare, emit procedure by hand on a five-point cloud and recover the tuples on slides 111 and 112.
- Read slide 113 correctly: the three baselines, the geometric means, and why the TPU column swings so widely.
- Map every sparsity type of this lecture to the system that exploits it and the granularity it needs.
- State what the next lecture adds (numeric types, the idea of quantization, its common methods) and spot the references the deck cites but never lists.
The roadmap on slide 110 puts PointAcc in the last row, next to TorchSparse, under the heading activation sparsity. Read the row as a pair: TorchSparse is the software answer to sparse inputs, and PointAcc is the hardware answer to the same inputs. Both start from the Sparse convolution of part 11, where a layer is driven by maps of (In, Out, Wgt) tuples and each tuple contributes f_out = f_out + f_in × W_wgt.
What changes between the two is where the time goes. On a GPU, the multiplies are batched into matmuls and run well once the map exists. Building the map is the problem. A point cloud has dynamic sparsity: which coordinates are occupied depends on the scene, so the map cannot be precomputed and must be rebuilt on every input. The PointAcc paper measures that cost on PointNet++-based networks and reports that more than half of the total runtime on general-purpose hardware goes to mapping operations, and that existing neural accelerators simply do not support them, so a TPU has to ship the coordinates back to its host CPU, where data movement then takes 60 to 90 percent of the runtime (Lin et al., 2021, section 3).
The pairing rule, and how to turn it into an equality test
A 3 × 3 kernel has nine weight offsets, W−1,−1 through W1,1. Input point p contributes to output point q through offset δ exactly when p sits at q + δ. On a GPU the natural code is a loop over outputs that asks a hash table "is there an input at q + δ?". PointAcc rewrites the same condition so that no lookup is needed.
Subtract δ from every input coordinate and the question becomes "which shifted inputs land on an output coordinate?", which is a set intersection. If both sets are sorted, an intersection is found by merging them and looking at adjacent elements: any input and output that coincide must end up side by side. This is why slide 112 adds (−1, −1) to the inputs for W1,1 and slide 111 adds (1, 1) for W−1,−1. The shift is always −δ, so the sign flips relative to the offset name.
Worked example
Finding the pairs for W1,1 on slide 112
Shift
The inputs are P0 (1,1), P1 (2,2), P2 (2,4), P3 (3,2), P4 (4,3). With stride 1 the outputs Q0 to Q4 sit at the same five coordinates. For δ = (1, 1) add (−1, −1) to every input: (0,0) (1,1) (1,3) (2,1) (3,2).Merge sort
Both lists are already sorted by x then y, so one pass merges them: P0 (0,0), Q0 (1,1), P1 (1,1), P2 (1,3), P3 (2,1), Q1 (2,2), Q2 (2,4), Q3 (3,2), P4 (3,2), Q4 (4,3).Compare neighbors
Ten cells give nine adjacent comparisons. Two of them are equal across owners: positions 2 and 3 (Q0 and P1, both (1,1)) and positions 8 and 9 (Q3 and P4, both (3,2)).Emit tuples
(P1, Q0, W1,1) and (P4, Q3, W1,1). Check against the rule: P1 = (2,2) = Q0 + (1,1) and P4 = (4,3) = Q3 + (1,1).Result
Two map entries out of 25 possible input-output pairs, found with 9 comparators and zero random memory accesses.
| Position | Owner | Coordinate | Equal neighbor |
|---|---|---|---|
| 1 | P0 | 0,0 | no |
| 2 | Q0 | 1,1 | yes, with 3 |
| 3 | P1 | 1,1 | yes, with 2 |
| 4 | P2 | 1,3 | no |
| 5 | P3 | 2,1 | no |
| 6 | Q1 | 2,2 | no |
| 7 | Q2 | 2,4 | no |
| 8 | Q3 | 3,2 | yes, with 9 |
| 9 | P4 | 3,2 | yes, with 8 |
| 10 | Q4 | 4,3 | no |
Slide 111 runs the identical procedure for the opposite corner of the kernel. The table below puts the two passes side by side. Notice the symmetry: the pairs for W1,1 are the pairs for W−1,−1 with the roles of input and output exchanged, P1 with Q0 against P0 with Q1. That is exactly what p = q + δ predicts, because if p = q + δ then q = p − δ, and with the input and output clouds sharing coordinates the same two points swap places.
| W1,1 (slide 112) | W−1,−1 (slide 111) | |
|---|---|---|
| Offset δ | (1, 1) | (−1, −1) |
| Shift applied to inputs | + (−1, −1) | + (1, 1) |
| Shifted inputs P0 to P4 | (0,0) (1,1) (1,3) (2,1) (3,2) | (2,2) (3,3) (3,5) (4,3) (5,4) |
| Merged order | P0 Q0 P1 P2 P3 Q1 Q2 Q3 P4 Q4 | Q0 Q1 P0 Q2 Q3 P1 P2 Q4 P3 P4 |
| Equal neighbors | Q0 = P1, Q3 = P4 | Q1 = P0, Q4 = P3 |
| Tuples emitted | (P1, Q0, W1,1), (P4, Q3, W1,1) | (P0, Q1, W−1,−1), (P3, Q4, W−1,−1) |
- P00,0
- P11,1
- P21,3
- P32,1
- P43,2
- Q01,1
- Q12,2
- Q22,4
- Q33,2
- Q44,3
- P00,0
- Q01,1
- P11,1
- P21,3
- P32,1
- Q12,2
- Q22,4
- Q33,2
- P43,2
- Q44,3
- (P1, Q0, W1,1)
- (P4, Q3, W1,1)
Input p and output q pair up for offset δ exactly when p = q + δ, so subtracting δ from every input turns the search into an equality test. The merge reads the two sorted strips once, head against head, and the only checks are between adjacent cells of the merged strip, which is why the comparator count is the strip length minus one. A hash table would instead probe a random address once per output point. With stride 2 the output coordinates are quantized to the stride grid by clearing the low log2(ts) bits, which the same unit separates from kernel mapping.
Why a hash table is the wrong tool for silicon
The GPU library that PointAcc compares against builds its maps with a hash table, and on a GPU that is a reasonable choice: memory is large and random access is cheap enough. Neither holds on chip. The paper puts two numbers on it. First, a hash table sized for a real point cloud at a sensible load factor can reach 160 MB, which no accelerator can hold in SRAM. Second, to serve N lookups in parallel the SRAM needs an N-by-N crossbar so that any lane can reach any bank, and that crossbar grows as O(N²) in area (Lin et al., 2021, section 4.1).
Merging has neither problem. The Mapping Unit feeds window-sized chunks of the two sorted lists to a fixed-size bitonic merger, a parallel comparator network, and a forwarding loop carries leftover elements into the next cycle, so the lists are read in order and never probed at random. Detecting the intersection is just as local: the paper describes feeding each pair of adjacent elements of the merged array to a comparator that checks whether their coordinates are equal. With |I| shifted inputs and |O| outputs the strip has |I| + |O| cells and |I| + |O| − 1 adjacent comparisons, all independent, so they can run in a single cycle. The Mapping unit builds this from a bitonic sorting network feeding a merger of fixed length, and the paper reports that at the same parallelism the merge-sort design is 1.4x faster than the hash-table design while saving up to 14x in area (Lin et al., 2021, section 4.1).
| Hash table | Merge sort | |
|---|---|---|
| Memory access pattern | Random probes, one per output point per offset | Two sequential streams, read once |
| Parallel read hardware | N-by-N crossbar, O(N²) area | Fixed-size bitonic merger with a forwarding loop |
| On-chip storage | Table can reach 160 MB at realistic load factors | Sorted coordinate lists, no table |
| Result at equal parallelism | Baseline | 1.4x faster, up to 14x less area |
One sorting unit, four point-cloud operations
The reason PointAcc calls this block a mapping unit rather than a convolution helper is that sorting turns out to be the common core of every irregular operation a point-cloud network needs. Kernel mapping is an equality after a shift. Building the output cloud under a stride s is quantizing coordinates to the stride grid and then deduplicating, which sorting does by putting duplicates next to each other. Farthest point sampling picks the point with the largest distance, a top-1 of a ranking. k-nearest-neighbor search is a top-k of the same ranking, and ball query is a threshold on the sorted distances. The paper lists these as the operations the single ranking-based unit implements (Lin et al., 2021, sections 2.1 and 4.1). Flip the simulator above to stride 2 to see the output construction case: the five inputs collapse to fewer outputs before any offset is tried.
Recall
State the condition that makes input p and output q a pair for offset δ, and say what PointAcc does to turn it into an equality test.
Recall
For W−1,−1 on slide 111, which tuples come out, and why does the shift carry a plus sign?
Recall
Give two reasons a hash table is a poor mapping unit on chip.
Quick check
For weight offset W1,1, the PointAcc mapping unit adds which vector to every input coordinate?
Quick check
A parallel hash table is rejected as the mapping unit mainly because it needs
Slide 113 is a pair of bar charts with three baselines, and the baselines matter more than the bars. Red is an NVIDIA RTX 2080Ti, the server GPU that already runs TorchSparse-style code well. Dark grey is an Intel Xeon Skylake host paired with a TPU V3, a dense-matmul accelerator that has to send every mapping operation back to the host. Light grey is an Intel Xeon Gold 6130 CPU alone. The right-most group, GeoMean, is the geometric mean across the eight networks, so no single network dominates the average.
Start with the GeoMean row and read the two charts together. Against the GPU, PointAcc is 3.7x faster and 22x more energy efficient. Against the TPU system it is 53x faster and saves 210x energy. Against the CPU it is 90x faster and saves 176x (the slide prints 193x, see the errata below). The paper's abstract leads with the GPU pair, 3.7x and 22x over an RTX 2080Ti, evaluated on eight models across four applications (Lin et al., 2021).
| Network | Speedup vs 2080Ti | Speedup vs TPU V3 | Speedup vs Gold 6130 | Energy vs 2080Ti | Energy vs TPU V3 | Energy vs Gold 6130 |
|---|---|---|---|---|---|---|
| PointNet | 3.7 | 27 | 127 | 18 | 1,319 | 172 |
| PointNet++ (c) | 2.8 | 113 | 97 | 14 | 169 | 119 |
| PointNet++ (ps) | 2.8 | 37 | 82 | 25 | 99 | 152 |
| DGCNN | 3.7 | 3.4 | 65 | 27 | 38 | 91 |
| F-PointNet++ | 3.7 | 269 | 131 | 16 | 682 | 394 |
| PointNet++ (s) | 4.7 | 88 | 106 | 45 | 161 | 221 |
| MinkNet(i) | 8.3 | 102 | 94 | 36 | 324 | 268 |
| MinkNet(o) | 2.4 | 71 | 51 | 13 | 127 | 139 |
| GeoMean | 3.7 | 53 | 90 | 22 | 210 | 193 (paper: 176) |
The network names encode the benchmark. The PointNet++ suffixes are (c) classification, (ps) part segmentation and (s) semantic segmentation. F-PointNet++ is the frustum detector built on PointNet++. MinkNet(i) and MinkNet(o) are MinkowskiUNet on an indoor dataset (S3DIS) and an outdoor dataset (SemanticKITTI), the two sparse-convolution workloads closest to part 11 (Lin et al., 2021, Table 2).
Why the TPU column swings from 3.4x to 269x
The GPU column is flat, between 2.4x and 8.3x, because a GPU handles both the mapping and the matmuls in the same memory. The TPU column ranges from 3.4x on DGCNN to 269x on F-PointNet++, and the spread is the lesson of the whole part. The paper attributes the gain over the TPU mainly to supporting mapping operations on chip (Lin et al., 2021, section 5.2). The paper does not break that number down per network, so the following is a reading of the chart, not a quoted result. DGCNN's neighbor search is a pairwise-distance computation in feature space, recomputed inside every EdgeConv layer, and a dense matmul unit already runs that well, so it has the least mapping work to move on chip. F-PointNet++ and the segmentation variants of PointNet++ are dominated by sampling, neighbor search and gathering, exactly the operations the TPU must hand back to the host, so removing that round trip is worth two orders of magnitude.
Recall
Slide 113 prints 193 for the CPU energy GeoMean. Using the definition of a geometric mean and the eight per-network bars, how would you check it?
Recall
Quote PointAcc's geometric-mean speedup and energy saving over the RTX 2080Ti, and name the other two baselines on slide 113.
Quick check
On slide 113, what is PointAcc's speedup on DGCNN over the Xeon Skylake plus TPU V3 system, the smallest entry in that column?
Slide 114 compresses the lecture into two bullets: automated ways to find pruning ratios, and system and hardware support for different granularities. Those two bullets are two separate questions from the five that opened the deck. The first asks how much to remove from each layer. The second asks how the zeros you created turn into time and energy actually saved. Neither is worth much without the other.
Thread one: choosing the ratio
Sensitivity analysis prunes one layer at a time across a sweep of ratios, plots accuracy against ratio, and reads each layer's rate where its curve crosses an accuracy threshold. It is cheap and transparent, and its weakness is that it ignores Layer interaction: the compounding loss when many layers are pruned together, which is why its per-layer rates are only a starting point. AMC (AutoML for Model Compression) replaces the human with a DDPG agent that sees a layer embedding and emits a continuous sparsity ratio, rewarded by accuracy under a FLOPs or latency budget. NetAdapt keeps a rule instead of a policy: cut latency by a fixed step, choose the layer whose short-term fine-tuned accuracy is highest, consult a measured latency lookup table rather than FLOPs, repeat until the budget is met, then long-term fine-tune. Whichever chooses the ratios, Fine-tuning and Iterative pruning are what recover the accuracy afterwards.
Thread two: making the zeros pay
A pruned weight is only free if the hardware skips it. EIE (Efficient Inference Engine) skips two kinds at once: static Weight sparsity stored in CSC form across an array of processing elements, and dynamic activation sparsity caught by leading non-zero detection so that a zero activation is never broadcast. NVIDIA Ampere tensor cores accept 2:4 sparsity only, and in return the Sparse tensor core uses the two-bit metadata to select operands and doubles math throughput (Mishra et al., 2021). TorchSparse handles the sparsity of point-cloud inputs in software by trading a little padding for regular batched matmuls through Adaptive grouping, and TorchSparse++ overlaps the gather and scatter with compute. PointAcc moves the same problem into hardware, with the merge-sort mapping unit of the previous concept. The granularity is the thread joining all four: the finer the sparsity, the more bookkeeping the system must do to skip it, and the coarser the sparsity, the more the pruning method must give up to fit the pattern.
| Sparsity | Where it comes from | Granularity needed | System | Mechanism |
|---|---|---|---|---|
| Fine-grained weight | Pruning, static | Irregular, individual weights | EIE | CSC storage, PE array, weight sharing, skip zero weights |
| M:N weight (2:4) | Pruning with a pattern, static | 2 nonzeros in every 4 along a row | NVIDIA Ampere sparse tensor cores | 2-bit metadata selects the paired activations, 2x math throughput |
| Activation (ReLU zeros) | ReLU at run time, dynamic | Element level | EIE | Leading non-zero detection, never broadcast a zero |
| Activation (sparse point-cloud inputs) | Data occupancy, dynamic | Point (coordinate) level | TorchSparse (software), PointAcc (hardware) | Maps plus gather, matmul, scatter with adaptive grouping; merge-sort mapping unit |
The bridge to the next lecture
Pruning removes weights. Quantization shrinks the ones that stay. Slide 114 sets the order for the next lecture: first the numeric data types modern computer systems actually offer, then the basic concept of neural network quantization, then the common quantization methods. The two techniques are complementary in the deep compression sense: after pruning left AlexNet with a ninth of its connections, quantizing and coding the survivors is what pushed the total to 35x in Han et al.'s pipeline, and both will show up together in the memory and energy arguments of the next lecture (Han, Mao and Dally, 2016).
Recall
Name the three automated ways to find pruning ratios from this lecture and one weakness of the first.
Recall
Which two topics open the next lecture before the quantization methods?
Quick check
Which system on slide 55 is paired with M:N weight sparsity?
Slide 115 lists nineteen references. Read as a map of the lecture they fall into six groups: foundations of model compression and energy (items 1, 2, 4, 5, 6), pruning criteria (3, 12, 13, 15), structured and channel pruning (7, 10, 11, 14, 16, 17), automated ratio search (9), hardware support (8), and one-shot pruning of large language models (18), with Prof. Han's TinyML course (19) as the source the whole deck follows. The Sources block at the end of this part gives a link for each one that has an archival home.
Where the references land in this lecture
- Foundations
- Deng et al. 2020 survey; Horowitz 2014 on the energy of memory access; Han et al. 2015; Han's Stanford thesis; Walsh 2013 on Huttenlocher's synapse counts
- Criteria
- LeCun et al. 1989 Optimal Brain Damage; Molchanov et al. 2017 and 2019 Taylor ranking; Wang's first-order Taylor note
- Structured pruning
- Mao et al. on granularity; Wen et al. 2016; Liu et al. 2017 Network Slimming; Hu et al. Network Trimming; He et al. 2017 channel pruning; Luo et al. 2017 ThiNet
- Automation
- He et al. 2018 AMC
- Hardware
- NVIDIA Ampere and TensorRT sparsity blog
- Large models
- Frantar and Alistarh 2023 SparseGPT
- Course
- Prof. Han's TinyML course (MIT 6.5940)
The list is also worth checking against the slides themselves, because several of the papers this lecture leaned on hardest are cited in slide footers but never make it to the reference page. Every hardware system in the second half of the deck is in that position. If you cite from this lecture in your own writing, take the references from the Sources below rather than from slide 115.
Recall
Which two hardware papers from this lecture are missing from the reference slide?
Recap
If you remember nothing else
- Sparse convolution pairs input p with output q for offset δ exactly when p = q + δ. PointAcc tests this as an equality after shifting every input by −δ.
- The mapping unit merge-sorts the shifted inputs with the outputs. Equal adjacent neighbors are map entries, found with |I| + |O| − 1 local comparisons and no random SRAM reads.
- On slide 112, W_1,1 yields (P1, Q0) and (P4, Q3). On slide 111, W_-1,-1 yields (P0, Q1) and (P3, Q4). The two lists are the same pairs with roles swapped.
- A parallel hash table needs an O(N²) crossbar and a table that can reach 160 MB. The merge-sort unit is 1.4x faster and up to 14x smaller at equal parallelism.
- One ranking kernel also serves farthest point sampling, kNN and ball query. Stride downsampling uses coordinate quantization instead.
- PointAcc geomean: 3.7x, 53x and 90x speedup and 22x, 210x and 176x energy saving (slide 113 prints 193x for the last one) over an RTX 2080Ti, a Xeon Skylake plus TPU V3, and a Xeon Gold 6130.
- Ratio methods: sensitivity analysis, AMC, NetAdapt. Systems: EIE (weight plus activation), Ampere tensor cores (M:N), TorchSparse and PointAcc (activation sparsity from sparse inputs).
- Next lecture: numeric data types, the basic concept of quantization, common quantization methods.
- Slide 115 omits NetAdapt, EIE, Mishra et al. 2021, TorchSparse, TorchSparse++ and PointAcc, and dates Hu et al. to 2017 when the paper appeared in 2016.
Sources
- PointAcc: Efficient Point Cloud AcceleratorPaperMICRO 2021, Lin, Zhang, Tang, Wang and HanMapping bottleneck (section 3), hash table critique and merge-sort mapping unit (section 4.1), 3.7x and 22x over an RTX 2080Ti, results (section 5.2, Figure 13, Table 2).(opens in a new tab)
- TorchSparse: Efficient Point Cloud Inference EnginePaperMLSys 2022, Tang, Liu, Li, Lin and HanCited on slides 87 to 107, absent from slide 115.(opens in a new tab)
- TorchSparse++: Efficient Training and Inference Framework for Sparse Convolution on GPUsPaperMICRO 2023, Tang et al.Cited on slides 108 and 109, absent from slide 115.(opens in a new tab)
- EIE: Efficient Inference Engine on Compressed Deep Neural NetworkPaperISCA 2016, Han et al.Cited on slides 57 to 77, absent from slide 115.(opens in a new tab)
- Submanifold Sparse Convolutional NetworksPaperarXiv, Graham and van der Maaten, 2017Cited on slide 86 as Graham, BMVC 2015 (that venue is Graham's earlier Sparse 3D Convolutional Neural Networks, arXiv 1505.02890), absent from slide 115.(opens in a new tab)
- NetAdapt: Platform-Aware Neural Network Adaptation for Mobile ApplicationsPaperECCV 2018, Yang et al.Cited on slides 33 to 40, absent from slide 115.(opens in a new tab)
- Accelerating Sparse Deep Neural NetworksPaperNVIDIA, Mishra et al., 20212:4 sparsity giving twice the math throughput on Ampere tensor cores.(opens in a new tab)
- Accelerating Inference with Sparsity Using the NVIDIA Ampere Architecture and NVIDIA TensorRTArticleNVIDIA Technical Blog, Pool, Sawarkar and Rodge, 2021Slide 115 item 8.(opens in a new tab)
- MIT 6.5940 TinyML and Efficient Deep Learning Computing, Lecture 4: Pruning and Sparsity (Part II)DocsMIT HAN LabSlide 115 item 19. The deck follows this lecture.(opens in a new tab)
- 4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural NetworksPaperCVPR 2019, Choy, Gwak and SavareseMinkowskiNet, the MinkNet(i) and MinkNet(o) workloads on slide 113.(opens in a new tab)
- PointNet++: Deep Hierarchical Feature Learning on Point Sets in a Metric SpacePaperNeurIPS 2017, Qi, Yi, Su and GuibasThe PointNet++ variants on slide 113 and their sampling and grouping operations.(opens in a new tab)
- Deep Compression: Compressing Deep Neural Networks with Pruning, Trained Quantization and Huffman CodingPaperICLR 2016, Han, Mao and DallyPruning and quantization combined, 35x on AlexNet, the bridge to the next lecture.(opens in a new tab)
- The Lottery Ticket Hypothesis: Finding Sparse, Trainable Neural NetworksPaperICLR 2019, Frankle and CarbinRelated reading, not covered in the deck.(opens in a new tab)
- Model Compression and Hardware Acceleration for Neural Networks: A Comprehensive SurveyPaperProceedings of the IEEE 108(4), 2020, Deng, Li, Han, Shi and XieSlide 115 item 1.(opens in a new tab)
- Computing's Energy Problem (and What We Can Do About It)PaperISSCC 2014, HorowitzSlide 115 item 2.(opens in a new tab)
- Optimal Brain DamagePaperNIPS 1989, LeCun, Denker and SollaSlide 115 item 3.(opens in a new tab)
- Learning Both Weights and Connections for Efficient Neural NetworksPaperNeurIPS 2015, Han, Pool, Tran and DallySlide 115 item 4, and the before and after pruning figure on slide 114.(opens in a new tab)
- Efficient Methods and Hardware for Deep LearningPaperStanford University PhD thesis, Han, 2017Slide 115 item 5.(opens in a new tab)
- Peter Huttenlocher (1931 to 2013)ArticleNature 502, 2013, WalshSlide 115 item 6.(opens in a new tab)
- Exploring the Regularity of Sparse Structure in Convolutional Neural NetworksPaperCVPR Workshops 2017, Mao et al.Slide 115 item 7, listed there under its workshop title.(opens in a new tab)
- AMC: AutoML for Model Compression and Acceleration on Mobile DevicesPaperECCV 2018, He, Lin, Liu, Wang, Li and HanSlide 115 item 9.(opens in a new tab)
- Learning Structured Sparsity in Deep Neural NetworksPaperNeurIPS 2016, Wen et al.Slide 115 item 10.(opens in a new tab)
- Learning Efficient Convolutional Networks through Network SlimmingPaperICCV 2017, Liu et al.Slide 115 item 11.(opens in a new tab)
- Importance Estimation for Neural Network PruningPaperCVPR 2019, Molchanov et al.Slide 115 item 13.(opens in a new tab)
- Network Trimming: A Data-Driven Neuron Pruning Approach towards Efficient Deep ArchitecturesPaperarXiv, Hu, Peng, Tai and Tang, July 2016Slide 115 item 14, dated 2017 on the slide.(opens in a new tab)
- Pruning Convolutional Neural Networks for Resource Efficient InferencePaperICLR 2017, Molchanov et al.Slide 115 item 15.(opens in a new tab)
- Channel Pruning for Accelerating Very Deep Neural NetworksPaperICCV 2017, He, Zhang and SunSlide 115 item 16.(opens in a new tab)
- ThiNet: A Filter Level Pruning Method for Deep Neural Network CompressionPaperICCV 2017, Luo, Wu and LinSlide 115 item 17.(opens in a new tab)
- SparseGPT: Massive Language Models Can Be Accurately Pruned in One-ShotPaperICML 2023, Frantar and AlistarhSlide 115 item 18.(opens in a new tab)