Majid Al-RaimiFull guide

COE 592Lecture 03Full guide

Neural network efficiency metrics

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
4
Concepts
18
Slides
29
Reading
108 min
Understood
0/18 concepts

Part 01: Latency, throughput and energy

The efficiency triangle of storage, latency and energy, what latency and throughput each measure, why one does not imply the other, the analytical latency model, and why data movement dominates energy.

5 concepts, slides 1-9

Why this part matters

Your research project will put a detector on an embedded board, and the board will judge it by three costs that have nothing to do with accuracy: does the model fit, does it answer before the next frame arrives, and does it drain the battery. Every metric in this lecture exists to predict one of those three costs before you ever flash the board.

This part gives you the map and the first three costs. It fixes the vocabulary (latency, throughput, energy), shows why a latency number is meaningless without the conditions it was measured under, works the batching example that exams love, derives a one-line latency model that separates what the network controls from what the hardware controls, and ends with the energy table that explains why every efficient design of the last decade is really a design for moving fewer bytes. Parts 02 to 04 then fill in the metrics that feed these costs.

By the end you can

  1. Place any efficiency metric in the memory or computation group and say which of storage, latency and energy it predicts.
  2. Define latency and throughput, and compute both for a batched design.
  3. Explain with numbers why higher throughput does not imply lower latency, and lower latency does not imply higher throughput.
  4. Write Latency ≈ max(T_computation, T_memory) with its sub-formulas, label each term NN or hardware specification, and decide compute-bound versus memory-bound.
  5. Quote the 45 nm energy table and argue why data movement, not arithmetic, sets the energy bill of an inference.

Suppose the detector you trained in the cloud is to run on a Jetson-class board mounted on a vehicle. Before the board can use it, three separate questions must be answered. Does the model fit in the flash and RAM you have? Does one inference finish before the next camera frame lands, roughly every 33 ms at 30 frames per second? And how much charge does each inference pull from the battery? Slide 4 draws these as the three outer goals of a triangle, Smaller, Faster and Greener, and the three costs that quantify them: Storage, Latency and Energy.

The part of the triangle that matters is the middle. All three costs are driven by only two resources, Computation and Memory. Storage is purely a memory question: how many bytes the weights occupy. Latency and energy depend on both, because an inference both performs arithmetic and moves data, and each of those takes time and burns charge. That is why the metric list on the side of the slide has exactly two groups. The efficiency metrics that are memory-related are the number of parameters, the model size and the total and peak number of activations. The computation-related ones are MACs, FLOPs with their rate FLOPS, and OPs with their rate OPS.

Resources feed costs, costs feed goals. Memory wires into all three costs, computation into latency and energy. Hover Storage to see that only the memory metrics predict it.
GoalCostResourceMetrics that predict it
SmallerStorageMemory#parameters, model size
FasterLatencyComputation and memoryMACs, OPs, model size, peak #activations
GreenerEnergyComputation and memoryMACs, OPs, and above all the bytes moved
Each goal, the cost that quantifies it, the resource it draws on, and the metrics that predict it

This taxonomy is the spine of the whole lecture. Parts 02 and 03 fill the memory group (parameters, model size, activations), part 04 fills the computation group (MACs, FLOPs, OPs), and this part explains the three costs those metrics are meant to predict. Whenever a later metric appears, place it here first: which group is it in, and which cost does it feed?

Metrics you count versus costs you measure

One distinction keeps the rest of the part honest. Parameters and MACs are properties of the network alone. You can count them on paper from the layer shapes, and they do not change when you move the model to another chip. Latency, throughput and energy are properties of the network running on a specific processor with a specific runtime. They must be measured, or at least estimated from hardware numbers. The same split reappears in the latency model of concept 4 as NN specification versus hardware specification.

Quick check

In the efficiency triangle, which pair of resources drives all three of storage, latency and energy?

Recall

Name the two groups of efficiency metrics, list the members of each, and say which cost each group predicts.

Memory-related: #parameters, model size, total and peak #activations; they predict storage and the memory part of latency and energy. Computation-related: MAC, FLOP and FLOPS, OP and OPS; they predict the computation part of latency and energy.

Slide 5 shows the same Cityscapes street segmented twice. The two masks look almost identical, and by the usual accuracy metric they are: SegFormer-B5 reaches 82.4 mIoU and EfficientViT-L1 reaches 82.7 mIoU. The difference is time. SegFormer needs 638 ms per frame and EfficientViT needs 45.9 ms (the slide rounds to 46 ms). At 30 frames per second a new frame arrives every 33 ms, so one model falls nineteen frames behind for every frame it finishes, and the other almost keeps up.

That per-frame time is latency: the delay between starting one specific task and finishing it. Patterson and Hennessy call the same quantity response time or execution time, the time between the start and completion of a task. It is a property of one task, not of a stream of tasks, and the next concept shows why that restriction matters. The 13.9x gap (638 / 45.9) is exactly the headline of the EfficientViT paper, which reports up to 13.9x GPU latency reduction over SegFormer at the same or better accuracy (Cai et al., ICCV 2023).

ModelmIoUParametersMACsOrin latencyA100 throughput
SegFormer-B582.485M1460G638 ms12 image/s
EfficientViT-L182.740M282G45.9 ms122 image/s
Ratio+0.32.1x fewer5.2x fewer13.9x faster10x more
Both models on Cityscapes at 1024 x 2048, from Table 3 of the EfficientViT paper. Latency on Jetson AGX Orin at batch size 1, throughput on an A100.

Read the ratio row carefully, because it plants the seed for concept 4. The MAC count falls 5.2x, but latency falls 13.9x. If latency were simply proportional to arithmetic, the two ratios would match. They do not, because SegFormer's softmax attention moves large intermediate tensors through memory, and that data movement, not its MACs, is what makes it slow on an edge GPU. MACs alone do not predict latency; they are one input to it.

Four conditions every latency must state

The slide's footnote is not fine print. Latency is measured, so it depends on everything in the measurement. The paper's setup sentence names four things: the hardware, the runtime, the numeric precision and the batch size. Change any one of them and the number changes, sometimes by an order of magnitude. The same paper measures EfficientViT-B1 at 24.3 ms on Orin and 0.82 s on a Jetson Nano, and SegFormer-B1 at 146 ms on Orin and 5.6 s on Nano. Same model, same precision, same batch size, different board: 34x to 38x apart.

The measurement conditions behind slide 5

Hardware
NVIDIA Jetson AGX Orin: 2048-core Ampere GPU, 64 Tensor Cores at 43 dense FP16 TFLOPS (the CUDA cores alone give 10.6), 204.8 GB/s LPDDR5, 15 W to 60 W
Runtime
TensorRT, which NVIDIA describes as turning a trained model into a fast, GPU-specific program for inference; the speedup depends on the model, precision, batch size and GPU
Precision
fp16, half the bytes per weight and activation of fp32
Batch size
1, one image per inference, which is what an on-device detector sees

Quick check

Which set of conditions must accompany a reported latency for it to be comparable?

Recall

Define latency in one sentence and name the four conditions that slide 5 states for its numbers.

Latency is the delay to complete one specific task, here one segmentation of one frame. Conditions: hardware (Jetson AGX Orin), runtime (TensorRT), precision (fp16) and batch size (1).

Slide 6 replaces one street with two mosaics of video clips and asks a different question: not how long one clip takes, but how many clips get done per second. One system manages 6.1 videos per second, the other 77.4. Those two numbers come from Table 5 of the TSM paper (Lin, Gan and Han, ICCV 2019): I3D at 306 GFLOPs versus TSM8F at 33 GFLOPs, both on a single Tesla P100.

That rate is throughput: the amount of work completed per unit time, what Patterson and Hennessy also call bandwidth. The TSM paper is unusually helpful here because it states its protocol: latency was measured with batch size 1 and throughput with batch size 16. TSM8F's latency is 17.4 ms. If throughput were the reciprocal of latency you would expect 1000 / 17.4 = 57.5 videos per second, yet the paper reports 77.4. The extra comes from batching, and it is the whole point of slide 7.

throughput=bTbatch,latency=Tbatch\text{throughput} = \frac{b}{T_{\text{batch}}}, \qquad \text{latency} = T_{\text{batch}}
b inputs processed together in one batch that takes T_batch

Two designs, same processor, opposite answers

Slide 7 pits two designs against each other. Design 1 handles one image at a time and takes 50 ms per image. Design 2 takes four images together and finishes the whole group in 100 ms. Each image in Design 2 waits the full 100 ms, because nothing leaves the processor until the batch is done.

DesignHow images are handledPer-image latencyImages per batchBatch timeThroughput
Design 1One after another50 ms150 ms1 / 0.050 = 20 image/s
Design 2Four in parallel100 ms4100 ms4 / 0.100 = 40 image/s
Slide 7's two designs
Both lanes run for the same 200 ms. Design 1 finishes four images in four 50 ms steps. Design 2 finishes eight in two 100 ms steps, yet every one of its images waited twice as long.

Worked example

Answering slide 7's two questions

  1. Does higher throughput mean lower latency?

    No. Design 2 has twice the throughput (40 versus 20 image/s) and twice the latency (100 versus 50 ms). Batching raised both, because throughput counts images and latency counts the wait of one image, and that image waits for its whole batch.
  2. Does lower latency mean higher throughput?

    No. Design 1 has half the latency and half the throughput. With no parallelism, a fast single lane still moves only one image per step, so a short step buys a short wait but not a high rate.
  3. When the two coincide

    Throughput equals 1 / latency only when the batch size is 1 and nothing is pipelined or run in parallel. Any batching or parallelism breaks the identity, always in the direction of more throughput per unit of latency.
SimulatorLatency versus throughput under batching
images done at 1000 ms: 40
Latency per image100msevery image waits for its whole batch, so L = t_batch
Throughput40.0image/s4 / 100 ms
1 / latency10.0per sonly equals throughput when b = 1

Batching multiplies throughput by b = 4 (4x the reciprocal of latency) while latency stays at 100 ms for every image. In one 1 s window this design completes 10 whole batches, 40 images. The TSM preset back-computes its batch time from the paper's 77.4 video/s at batch 16, so it illustrates the arithmetic rather than confirming it.

A second scenario for practice

A cloud server serves the same model at two batch sizes. At batch 1 a request takes 2 ms. At batch 32 the whole batch takes 8 ms, because the GPU can spread thirty-two images over its cores far more efficiently than one.

SettingBatch timeImages per batchLatency per imageThroughput
Batch 12 ms12 ms500 image/s
Batch 328 ms328 ms4000 image/s
Change4x longer32x more4x worse8x better
One server, two batch sizes

Batching paid 4x latency to buy 8x throughput. Whether that is a good trade depends on who is waiting. A brake camera needs one frame answered now: latency, at batch size 1, which is why slide 5 measured that way. A data center indexing videos overnight needs clips per hour: throughput, at whatever batch size fills the GPU. Your research project sits on the first side of that line.

Quick check

Design 2 processes 4 images in parallel in 100 ms. What are its latency and throughput?

Recall

A design processes 8 images together every 200 ms. What are its latency and throughput, and what would the naive reciprocal give?

Latency 200 ms per image. Throughput 8 / 0.2 = 40 image/s. The reciprocal 1 / 0.2 = 5 per second is wrong by the batch size.

Concept 2 left a puzzle: MACs fell 5.2x but latency fell 13.9x. To resolve it you need a model of where the milliseconds go. Watch one layer execute. The processor loads the input activations, loads the layer's weights, multiplies and accumulates, and stores the output activations. Two of those steps are arithmetic; the other two are data movement. Real hardware does not wait for one to finish before starting the other. While the multipliers chew on the current tile, the memory system is already fetching the next weights, so the two streams run side by side and the layer finishes when the slower stream finishes.

Data movement and computation run on parallel tracks. The memory track sits idle while the multipliers catch up and stores the last outputs only after the last MAC, so the layer takes as long as the busier track, which is why the estimate is a max and not a sum.
Latencymax(Tcomputation,  Tmemory)\text{Latency} \approx \max\left(T_{\text{computation}},\; T_{\text{memory}}\right)
The two overlapped streams
Tcomputationnumber of operations in the modeloperations per second the processor can doT_{\text{computation}} \approx \frac{\text{number of operations in the model}}{\text{operations per second the processor can do}}
NN specification over hardware specification
TmemoryTmove(activations)+Tmove(weights)T_{\text{memory}} \approx T_{\text{move}}(\text{activations}) + T_{\text{move}}(\text{weights})
Both kinds of data must cross the same memory bus, so these add
Tmove(weights)model sizememory bandwidth,Tmove(activations)input activation size+output activation sizememory bandwidthT_{\text{move}}(\text{weights}) \approx \frac{\text{model size}}{\text{memory bandwidth}}, \qquad T_{\text{move}}(\text{activations}) \approx \frac{\text{input activation size} + \text{output activation size}}{\text{memory bandwidth}}
Bytes over bytes per second

Computation time is the operation count divided by the rate at which the processor retires operations. Memory time is the bytes that must move divided by the memory bandwidth, once for the weights and once for the activations in and out. Now look at the colour coding on the slide, because it is the sentence the exam wants. Every numerator is a property of the network: operations, model size, activation sizes. Every denominator is a property of the processor: operations per second, bandwidth. That split is the NN specification versus hardware specification distinction, and it makes efficiency a co-design problem. You change numerators by redesigning the network, denominators by choosing hardware, and latency by whichever of the two you can actually afford to change.

TermNumerator: NN specificationDenominator: hardware specification
T_computationNumber of operations in the model (MACs, OPs: part 04)Operations per second of the processor (OPS)
T_move(weights)Model size (part 02)Memory bandwidth
T_move(activations)Input activation size + output activation size (peak #activations: part 03)Memory bandwidth
Where each term of the model comes from, and which later part counts it

The same model appears in the industry literature under different names. NVIDIA's GPU performance guide states that memory time is bytes accessed divided by memory bandwidth, math time is operations divided by math bandwidth, and the longer of the two shows what limits performance: math-limited if math time is longer, memory-limited if memory time is longer. The roofline model of Williams, Waterman and Patterson (CACM 2009) writes the same idea as a rate, attainable performance = min(peak compute, bandwidth x operational intensity). The vocabulary to adopt is compute-bound when T_computation wins and memory-bound when T_memory wins. One caution before using datasheet numbers: dividing by a peak OPS figure gives a floor on T_computation, not an estimate of it, because real kernels rarely keep every multiplier busy. The measured time over that floor is the inverse of the utilisation the runtime achieved.

Worked example A: a toy model and two processors

Worked example

Toy numbers that show the regime flipping

  1. Start on a 100 GOPS processor

    The model has 1 GOP of work, so T_computation = 1e9 / 1e11 = 10 ms. Weights are 50 MB and activations in plus out are 20 MB, over 10 GB/s: T_weights = 5 ms, T_activations = 2 ms, T_memory = 7 ms. Latency ≈ max(10, 7) = 10 ms, compute-bound.
  2. Buy a 200 GOPS processor

    T_computation halves to 5 ms, but T_memory is still 7 ms. Latency ≈ max(5, 7) = 7 ms, not 5 ms. The model became memory-bound and 2 ms of the new compute sits idle every inference.
  3. Quantize the weights to 8-bit instead

    Model size drops to 12.5 MB (part 02 shows why), so T_weights = 1.25 ms and T_memory = 3.25 ms. On the fast processor latency is back to max(5, 3.25) = 5 ms: the hardware upgrade only paid off once the network side shrank too.
  4. Three configurations

    ConfigurationT_computationT_memoryLatencyRegime
    100 GOPS, 32-bit weights10 ms5 + 2 = 7 ms10 msCompute-bound
    200 GOPS, 32-bit weights5 ms5 + 2 = 7 ms7 msMemory-bound
    200 GOPS, 8-bit weights5 ms1.25 + 2 = 3.25 ms5 msCompute-bound
ModelLatency as max(T_computation, T_memory)
light symbols are NN specification (numerators), teal symbols are hardware specification (denominators)
T_computation = N_ops / OPS10.0 ms
T_memory = T_weights + T_activations7.00 ms
T_weights = S_w / BW = 5.00 msT_activations = (S_in + S_out) / BW = 2.00 ms
Latency estimate10.0 msmax of the two bars
Regimecompute-bounda faster processor would help
Headroom1.43xhow much T_memory could grow before it becomes the bottleneck

The two Orin presets use 43 TFLOPS dense fp16 on the Tensor Cores and 204.8 GB/s from NVIDIA's Jetson AGX Orin page, MACs and parameters from the EfficientViT paper, and a 1024 × 2048 input with 19 output classes at 2 bytes each. Dividing by a peak rate gives a floor: measured latencies were 45.9 ms and 638 ms, 3.5x and 9.4x above it, and the gap shows what a first-order model leaves out.

Worked example B: back to slide 5

Worked example

Predicting the Orin numbers from public specifications

  1. EfficientViT-L1, computation

    282 GMACs is 564 GFLOPs at two FLOPs per MAC (part 04). TensorRT runs fp16 convolutions and matrix multiplies on the Tensor Cores, which the Orin page rates at 43 dense FP16 TFLOPS (the CUDA cores alone would give 10.6), so T_computation ≈ 564 / 43 000 ≈ 13.1 ms.
  2. EfficientViT-L1, memory

    Weights: 40M x 2 bytes = 80 MB, over 204.8 GB/s gives 0.39 ms. Activations: input 3 x 1024 x 2048 x 2 B = 12.6 MB, output 19 x 1024 x 2048 x 2 B = 79.7 MB, sum 92.3 MB, over the same bandwidth 0.45 ms. T_memory ≈ 0.84 ms.
  3. Compare with measurement

    Prediction max(13.1, 0.84) ≈ 13.1 ms, strongly compute-bound. Measured: 45.9 ms, 3.5x above the floor, so the runtime achieved roughly 29% of the Tensor Core peak. That is a normal utilisation for a real network: kernel launches, layers too small to fill the GPU, and intermediate activations moving between layers all sit outside the formula.
  4. SegFormer-B5 by the same recipe

    1460 GMACs = 2920 GFLOPs, so T_computation ≈ 2920 / 43 000 ≈ 68 ms. Weights 85M x 2 B = 170 MB give 0.83 ms; the activations are the same 0.45 ms. Prediction ≈ 68 ms. Measured: 638 ms, 9.4x above the floor, about 11% utilisation.
  5. Reading the two misses

    Both models land above the floor, as every real model does, but SegFormer misses by almost three times as much. The crude model counts only input and output activations. SegFormer's softmax attention materializes large intermediate attention maps that the formula never sees, which is exactly the memory traffic the EfficientViT paper set out to remove. The model is a first-order floor; the size of the miss tells you which term you forgot.
  6. Floor versus measurement

    ModelT_computationT_memoryFloorMeasuredMiss, utilisation
    EfficientViT-L1564 / 43 000 = 13.1 ms0.39 + 0.45 = 0.84 ms13.1 ms45.9 ms3.5x, about 29%
    SegFormer-B52920 / 43 000 = 68 ms0.83 + 0.45 = 1.3 ms68 ms638 ms9.4x, about 11%

Quick check

A model is memory-bound on its current processor. Which change is guaranteed to reduce its latency under the max model?

Recall

Write the latency model with its sub-formulas and label every term NN or hardware.

Latency ≈ max(T_computation, T_memory). T_computation ≈ operations in the model (NN) / operations per second (hardware). T_memory ≈ model size (NN) / bandwidth (hardware) + (input + output activation size) (NN) / bandwidth (hardware).

Recall

Why max and not plus?

Data movement and computation overlap on real hardware: the next weights load while the current ones are being multiplied. The layer therefore finishes when the slower of the two streams finishes, which is the max.

Recall

In the SegFormer versus EfficientViT comparison, MACs drop 5.2x but latency drops 13.9x. What does that tell you?

MACs are only the numerator of T_computation. SegFormer's attention moves large intermediate activations, so a memory term the simple model ignores inflates its latency, and operation count alone under-predicts it.

The third cost is energy, and slide 9 settles where it goes with one table. In a 45 nm process at 0.9 V, a 32-bit integer add costs 0.1 pJ and a 32-bit integer multiply 3.1 pJ. Reading one 32-bit word from DRAM costs 640 pJ. The multiply is the most expensive arithmetic on the list, and the memory access is two hundred times dearer than it.

Rough energy per operation, 45 nm, 0.9 V, 32-bit (slide 9, after Horowitz 2014 as tabulated by Han et al. 2015)

int ADD
0.1 pJ
float ADD
0.9 pJ
Register file access
1 pJ
int MULT
3.1 pJ
float MULT
3.7 pJ
SRAM cache access
5 pJ
DRAM memory access
640 pJ
On a log axis each grid step is ten times more energy. The six arithmetic and on-chip bars fit in the first two decades; DRAM sits two more decades out from SRAM (640 / 5 = 128x) and almost four decades from the int ADD bar.

Three ratios from that table are worth memorizing. DRAM over integer multiply is 640 / 3.1 ≈ 206, which the slide rounds to 200x. DRAM over SRAM is 640 / 5 = 128, so keeping data on-chip is worth two orders of magnitude on its own. And float add over integer add is 0.9 / 0.1 = 9, a seed for quantization: the same arithmetic in integers is nine times cheaper per add. Han et al. summarize the whole table in one line, that memory access is three orders of magnitude more energy expensive than simple arithmetic (640 / 0.1 = 6400).

The chain the slide writes across the top follows directly: data movement means more memory references, and more memory references mean more energy. Horowitz's own framing in the ISSCC 2014 talk is that a DRAM access at 1 to 2 nJ is a couple of orders of magnitude above a cache access or a functional operation at around 10 pJ, and that even with better I/O circuits DRAM will stay expensive, around 0.6 nJ per 8 bytes, because requests and data still have to travel a long physical distance. The slide's 640 pJ per 32-bit word is about half of the 1.3 nJ per 64-bit access in his Figure 1.1.9, as the provenance note below explains.

The log axis of the slide's chart is not decoration either. On a linear axis the six small bars would be invisible next to DRAM; a 0.1 pJ bar next to a 640 pJ bar is a pixel next to a page. Only a logarithmic axis can show both, and it is the honest way to read any table whose entries span four decades.

Worked example: AlexNet's energy bill

Worked example

Arithmetic versus weight fetch for one AlexNet inference

  1. Arithmetic in 32-bit integers

    AlexNet runs 724M MACs per image (part 04). Each is one multiply and one add: 724e6 x (3.1 + 0.1) pJ = 2.32 mJ.
  2. Weights read once from DRAM

    AlexNet has 61M parameters (part 02). Reading each once as a 32-bit word: 61e6 x 640 pJ = 39.0 mJ. That is 16.8x the arithmetic, before a single activation has moved.
  3. Two alternatives

    Keep the same weights in SRAM: 61e6 x 5 pJ = 0.31 mJ, cheaper than the arithmetic. Or keep DRAM but use float arithmetic: 724e6 x (3.7 + 0.9) = 3.33 mJ, still twelve times below the DRAM bill.
  4. Two orders of magnitude versus a factor of two

    Changing where the weights live changes the total by two orders of magnitude; changing how the arithmetic is done changes it by less than a factor of two.
  5. The bill, line by line

    ItemCountEnergy eachTotal
    Integer MACs (multiply + add)724M3.1 + 0.1 = 3.2 pJ2.32 mJ
    Weights read once from DRAM61M640 pJ39.0 mJ
    Same weights read from SRAM61M5 pJ0.31 mJ
    Float MACs instead of integer724M3.7 + 0.9 = 4.6 pJ3.33 mJ
CalculatorEnergy of one inference, operation by operation
1,000,000 × 0.1 pJ
100 nJ
0 × 0.9 pJ
0.0 pJ
0 × 1 pJ
0.0 pJ
1,000,000 × 3.1 pJ
3.10 µJ
0 × 3.7 pJ
0.0 pJ
100,000 × 5 pJ
500 nJ
10,000 × 640 pJ
6.40 µJ
bars use a log scale from 1 pJ to the largest row, so equal steps are ten times more energy
linear share of the total: light is arithmetic, teal is memory access
Total energy10.1 µJ
Arithmetic3.20 µJadds and multiplies
Memory access6.90 µJDRAM alone: 63% of total

Per-operation costs are the 45 nm, 0.9 V figures from slide 9 (Horowitz 2014, as tabulated by Han et al. 2015). The AlexNet presets use 724M MACs as one multiply plus one add each, and one fetch per weight for its 61M weights.

Every efficiency technique later in the course can be read as a way of cutting that memory line. Keep weights in on-chip SRAM, which is 128x cheaper per access than DRAM. Reuse each fetched value as many times as possible before it leaves the chip; Horowitz notes that efficient designs complete on the order of a thousand operations per DRAM fetch. And make the model small enough to fit on-chip in the first place, which is what model size in part 02, peak activations in part 03, and pruning and quantization later in the course are all about.

Quick check

In the 45 nm table, how does one 32-bit DRAM access compare with one 32-bit integer multiply?

Recall

Quote the DRAM to integer multiply energy ratio, the numbers behind it, and the process conditions.

640 pJ / 3.1 pJ ≈ 206, quoted as 200x. Conditions: 45 nm, 0.9 V, 32-bit operations, Horowitz ISSCC 2014 via Han et al. 2015.

Recall

For one AlexNet inference, how does the energy of fetching every weight once from DRAM compare with the energy of all its integer MACs?

61M x 640 pJ = 39 mJ for the weights against 724M x 3.2 pJ = 2.3 mJ for the arithmetic, about 17x. Moving the weights to SRAM drops the fetch cost to 0.31 mJ.

Recap

If you remember nothing else

  • Three goals (smaller, faster, greener) map to three costs (storage, latency, energy). All three are driven by two resources, computation and memory, so the metrics split into memory-related and computation-related.
  • Latency is the delay for one task. SegFormer-B5 takes 638 ms and EfficientViT-L1 takes 45.9 ms on Jetson AGX Orin with TensorRT, fp16, batch size 1: a 13.9x gap at equal or better mIoU.
  • A latency number without hardware, runtime, precision and batch size is not comparable to any other.
  • Throughput is items per second. Batching raises it (Design 2: 40 image/s) while raising latency (100 ms). Throughput equals 1 / latency only with batch size 1 and no parallelism.
  • Latency ≈ max(T_computation, T_memory) because data movement and computation overlap. Numerators are NN specification, denominators are hardware specification.
  • A faster processor helps only when compute-bound. A memory-bound model needs smaller weights, smaller activations or more bandwidth.
  • At 45 nm and 0.9 V: int ADD 0.1 pJ, int MULT 3.1 pJ, SRAM 5 pJ, DRAM 640 pJ. One DRAM access costs about 206 int multiplies, and a float ADD costs 9 int ADDs.
  • Fetching AlexNet's 61M weights once from DRAM (39 mJ) costs about 17 times its 724M MACs of integer arithmetic (2.3 mJ).

Sources

Part 02: Parameters and model size

Counting weights for linear, convolution, grouped and depthwise layers, totaling AlexNet to 61M parameters, and converting parameter count into storage at different bit widths.

4 concepts, slides 10-17

Why this part matters

Every result you will meet later in this course, from pruning AlexNet "9x smaller" to Deep Compression's "35x" storage cut, is a ratio of two numbers computed the way this part teaches. Before you can judge pruning, quantization or an architecture search, you must be able to count what a network stores, and the same count decides whether a model fits into a microcontroller's flash.

Lecture 02 taught how linear, convolution, grouped and depthwise layers compute their outputs. This part does not repeat that. It asks one narrower question of each layer: how many numbers does it keep? Four short formulas answer it, AlexNet gives them a real workout, and one multiplication by the bit width turns the answer into megabytes. Along the way you will find a typo on the slide, a hidden value to compute yourself, and a simulator you can use to check every parameter and model-size number here and the MAC and FLOP numbers in part 04.

By the end you can

  1. Define #Parameters as the element count of all weight tensors and explain why n, h and w never enter it.
  2. Write and derive the four counting formulas (linear, convolution, grouped, depthwise) and justify the single division by g.
  3. Total AlexNet layer by layer, identify where 96 percent of the weights sit, and spot the slide's conv1 typo.
  4. Convert a parameter count to model size at any bit width in bits, KB and MB, stating the decimal convention.
  5. Predict how architecture choices (groups, depthwise filters, linear layer width) move model size before touching hardware.

Start with the smallest network worth drawing: five inputs x0 to x4 and three outputs y0 to y2, every input wired to every output. Count the arrows. Each input sends one arrow to each output, so there are 3 × 5 = 15 arrows, labelled from w00 up to w42. Each arrow carries exactly one learned number, its weight. That is the whole idea of the number of parameters: it is the synapse count, the number of weights, and for this layer it is 15.

Five inputs fully wired to three outputs: 15 arrows, 15 weights, c_o · c_i

Now look at the same layer the way a framework stores it. The inputs for a batch are a matrix X of shape n × c_i, the weights are a matrix W of shape c_o × c_i, and the outputs come out as Y = X · W^T of shape n × c_o. The fifteen arrows have become the fifteen elements of W. This is the second, equivalent definition the slides give: #Parameters is the number of elements in the network's weight tensors. For one linear layer that is the product of its two dimensions.

#Paramslinear=coci\#\text{Params}_{\text{linear}} = c_o \cdot c_i
One weight per input and output pair, bias ignored

One thing in that matrix picture deserves a second look. The batch size n appears in X and in Y, but never in W. Feed the layer one image or a thousand and the weight matrix is the same c_o × c_i block. Parameter count is a property of the model, not of the data flowing through it. Hold on to this observation: it returns in the next concept for spatial size, and it is the reason parameters and MACs behave so differently in part 04.

The slides define the count for the "given" (slide 10) or "entire" (slide 11) neural network; both mean the same thing, the sum over every layer. They also say bias is ignored, and this lecture keeps that convention throughout. In PyTorch a linear layer stores a bias vector of length c_o and a convolution stores one bias per output channel, so the true count is larger by c_o per layer (PyTorch Conv2d documentation). Next to c_o · c_i that is a rounding error, which is why the lecture drops it.

Notation used on slides 11 to 14 and in the rest of this lecture

n
Batch size, the number of inputs processed together
c_i, c_o
Input and output channels (for a linear layer, input and output features)
h_i, h_o
Input and output height
w_i, w_o
Input and output width
k_h, k_w
Kernel height and width
g
Number of groups in a grouped convolution

Layer mechanics live in lecture 02

How a linear layer, a convolution, padding and stride, grouped and depthwise convolution and pooling produce their outputs, including the output-shape arithmetic behind numbers like 96 × 55 × 55, was covered in lecture 02: neurons and linear layers, convolution layers, padding, stride and grouped convolution and pooling.

Recall

A linear layer maps 512 inputs to 256 outputs. How many parameters does it have, ignoring bias, and does the batch size change that number?

256 × 512 = 131,072. The batch size changes nothing: n never appears in a weight tensor.

Take AlexNet's third convolution: 384 filters, each looking at 256 input channels through a 3 × 3 window. One filter is a small brick of numbers, 256 deep and 3 × 3 across, so it holds 256 · 9 = 2,304 weights. There are 384 such bricks, so the layer holds 384 · 2,304 = 884,736 weights. That is the whole convolution formula for the #Parameters, read off the shape of the weight tensor.

#Paramsconv=cocikhkw\#\text{Params}_{\text{conv}} = c_o \cdot c_i \cdot k_h \cdot k_w
c_o filters, each c_i × k_h × k_w

Notice what is missing. The input is 256 × 13 × 13 and the output is 384 × 13 × 13, yet 13 appears nowhere in the count. A convolution slides the same brick to every output position, so the weights are shared across space. Goodfellow, Bengio and Courville make the point with an edge detector: a two-element kernel applied to a 320 × 280 image stores two parameters, where a dense matrix doing the same job would store billions (Goodfellow et al., section 9.2). The kernel size and the channel counts set the parameter count; the output height and width do not. Part 04 will show that MACs do multiply by h_o · w_o, because the brick is reapplied at every position, and that is the single most important difference between the two metrics.

Grouped convolution: derive it, do not memorize it

A grouped convolution with g groups cuts the c_i input channels into g slices of c_i/g and the c_o output channels into g slices of c_o/g, then runs g ordinary convolutions side by side, each reading only its own input slice and writing only its own output slice. So count one group with the formula you already have: (c_o/g) · (c_i/g) · k_h · k_w. There are g groups, so multiply by g. One factor of g cancels.

#Paramsgrouped=cogcigkhkwg=cocikhkwg\#\text{Params}_{\text{grouped}} = \frac{c_o}{g}\cdot\frac{c_i}{g}\cdot k_h k_w \cdot g = \frac{c_o \cdot c_i \cdot k_h \cdot k_w}{g}
Each group is smaller by g squared, but there are g of them
Four filters, each eight channels deep. With g = 2 each filter keeps only its half of the channels, and the lit volume is half of the resting stack.
Eight input and eight output channels. With g = 2 the 32 cross-group links disappear and two 4 × 4 blocks remain: 64 becomes 32, one division by g.

This matches what a framework actually stores. PyTorch gives Conv2d a weight of shape (out_channels, in_channels / groups, kH, kW) and requires that in_channels and out_channels are both divisible by groups (PyTorch documentation). The historical reason AlexNet has g = 2 in three of its layers is hardware, not elegance: the network was trained across two GTX 580 GPUs with 3 GB each, and "the kernels of the second, fourth, and fifth convolutional layers are connected only to those kernel maps in the previous layer which reside on the same GPU" (Krizhevsky et al., 2012, section 3.5). Grouping halved the weights each GPU had to hold.

Depthwise convolution: the limit g = c_i = c_o

Push the grouping to its extreme, one channel per group, and you get a depthwise convolution. Now g = c_i = c_o and every channel has its own private k_h × k_w filter. In the MobileNets paper this is stated directly: "the depthwise convolution applies a single filter to each input channel" (Howard et al., 2017, section 3.1). Plug g = c_i into the grouped formula and the c_i cancels.

#Paramsdepthwise=cocikhkwci=cokhkw\#\text{Params}_{\text{depthwise}} = \frac{c_o \cdot c_i \cdot k_h \cdot k_w}{c_i} = c_o \cdot k_h \cdot k_w
One k_h × k_w filter per channel

Worked example

One 3 × 3 layer with 256 input and 256 output channels

  1. Standard convolution

    256 · 256 · 3 · 3 = 589,824 weights.
  2. Grouped with g = 2

    589,824 / 2 = 294,912. Each of the two groups is a 128 → 128 convolution with 147,456 weights.
  3. Grouped with g = 8

    589,824 / 8 = 73,728. Eight groups of 32 → 32.
  4. Depthwise, g = 256

    256 · 9 = 2,304. Each channel keeps one 3 × 3 filter.
  5. Ratio to the standard layer

    LayerCount#ParametersRatio
    Standard, g = 1256 · 256 · 9589,8241
    Grouped, g = 2256 · 256 · 9 / 2294,9121/2
    Grouped, g = 8256 · 256 · 9 / 873,7281/8
    Depthwise, g = 256256 · 92,3041/256
Layer#ParametersDepends on h, w?Depends on n?Why
Linearc_o · c_iOnly through c_i after a flattenNoEvery input feature is wired to every output feature; a flattened c_i carries h × w
Convolutionc_o · c_i · k_h · k_wNoNoc_o filters, each c_i deep and k_h × k_w wide
Grouped convolutionc_o · c_i · k_h · k_w / gNoNog independent convolutions on c_i/g and c_o/g channels
Depthwise convolutionc_o · k_h · k_wNoNoGrouped with g = c_i = c_o, one filter per channel
The four counting formulas and what they ignore

The simulator collects all four formulas, adds the bit width from the final concept of this part and the MACs from part 04, and carries a preset for every parameterized AlexNet layer. Try conv3 now and confirm 884,736, then change h_o and watch which readouts move.

SimulatorLayer metrics calculator: parameters, model size, MACs
AlexNet presets, slide 16
Parameters884,736weightsc_o · c_i · k_h · k_w, matches slide 16
Model size (bits)28.31 Mbitsparameters × 32 bits
Model size (MB)3.539MB3,538.9 KB, decimal 10^6 as on slide 17, about 3.375 MiB
MACs149,520,384parameters × h_o × w_o, here × 169, about 149.52 M
FLOPs299.04 MFLOPs2 × MACs, one multiply and one add
Reads per filter256input channelseach filter sees all of c_i

Change h_o or w_o and watch MACs move while the parameter count and model size stay still. Only c_i, c_o, k_h, k_w and g touch the weight count, and only the bit width turns that count into storage.

Quick check

A 3 × 3 convolution has c_i = 64 and c_o = 128. How many parameters does it have?

Quick check

Doubling the input resolution of a CNN does what to a convolution layer's parameter count and MAC count?

Recall

Write the grouped-convolution count two ways and say why the division is by g, not g squared.

(c_o/g) · (c_i/g) · k_h · k_w · g = c_o · c_i · k_h · k_w / g. Each group shrinks both channel dimensions by g, a factor of 1/g², but there are g such groups, which multiplies back by g.

AlexNet is the convolutional network whose variant won the ILSVRC-2012 challenge with a top-5 test error of 15.3%, and its authors state up front that it has "60 million parameters and 650,000 neurons" (Krizhevsky et al., 2012). It is also the best possible exercise for this part: five convolutions, three of them grouped, three max-pools and three linear layers, with input 3 × 224 × 224. Walk it top to bottom and apply the right #Parameters formula at each layer. The output shapes come from lecture 02; here we only count.

Worked example

Counting AlexNet, part one: the convolutions

  1. conv1: 11 × 11, 96 channels, stride 4, pad 2

    Output 96 × 55 × 55. Weights 96 · 3 · 11 · 11 = 34,848. The stride and padding set the 55, but they do not touch the count.
  2. maxpool 3 × 3, stride 2

    Output 96 × 27 × 27. Pooling takes a maximum; it learns nothing and stores nothing: 0 parameters.
  3. conv2: 5 × 5, 256 channels, pad 2, groups 2

    Output 256 × 27 × 27. Grouped, so 256 · 96 · 5 · 5 / 2 = 307,200.
  4. maxpool 3 × 3, stride 2

    Output 256 × 13 × 13, 0 parameters.
  5. conv3: 3 × 3, 384 channels, pad 1

    Output 384 × 13 × 13. 384 · 256 · 3 · 3 = 884,736.
  6. conv4: 3 × 3, 384 channels, pad 1, groups 2

    Output 384 × 13 × 13. 384 · 384 · 3 · 3 / 2 = 663,552.
  7. conv5: 3 × 3, 256 channels, pad 1, groups 2

    Output 256 × 13 × 13. The slide hides this one behind a question mark. Compute it before you reveal the answer below.

Recall

conv5: 3 × 3 kernels, 256 output channels, 384 input channels, groups 2. How many parameters?

256 · 384 · 9 / 2 = 442,368. Without the grouping it would be 884,736, the same as conv3.

Worked example

Counting AlexNet, part two: the linear layers and the total

  1. maxpool 3 × 3, stride 2

    Output 256 × 6 × 6, 0 parameters. This map is flattened into a vector of 256 · 6 · 6 = 9,216 values.
  2. fc6: linear, 4096 outputs

    4096 · 9,216 = 37,748,736. One layer, and already more than half of the network.
  3. fc7: linear, 4096 outputs

    4096 · 4096 = 16,777,216.
  4. fc8: linear, 1000 outputs

    1000 · 4096 = 4,096,000, one output per ImageNet class.
  5. Total

    2,332,704 in the convolutions plus 58,621,952 in the linear layers gives 60,954,656, about 61M, which is what the slide and the paper both round to.
LayerOutput C × H × WCount#ParametersShare
Image3 × 224 × 2240
conv1, 11 × 11, 96 ch, stride 4, pad 296 × 55 × 5596 · 3 · 11 · 1134,8480.06%
maxpool 3 × 3, stride 296 × 27 × 270
conv2, 5 × 5, 256 ch, pad 2, groups 2256 × 27 × 27256 · 96 · 5 · 5 / 2307,2000.50%
maxpool 3 × 3, stride 2256 × 13 × 130
conv3, 3 × 3, 384 ch, pad 1384 × 13 × 13384 · 256 · 3 · 3884,7361.45%
conv4, 3 × 3, 384 ch, pad 1, groups 2384 × 13 × 13384 · 384 · 3 · 3 / 2663,5521.09%
conv5, 3 × 3, 256 ch, pad 1, groups 2256 × 13 × 13256 · 384 · 3 · 3 / 2442,3680.73%
maxpool 3 × 3, stride 2256 × 6 × 60
fc6, linear 409640964096 · (256 · 6 · 6)37,748,73661.93%
fc7, linear 409640964096 · 409616,777,21627.52%
fc8, linear 100010001000 · 40964,096,0006.72%
Five convolutions2,332,7043.83%
Three linear layers58,621,95296.17%
Total60,954,656100%
AlexNet parameters per layer, with the corrected conv1 value and each layer's share of the total

Where the weights actually are

The share column is the real lesson. The five convolutions together hold 2.3M weights, under 4 percent. The three linear layers hold 58.6M, about 96 percent, and fc6 alone holds 62 percent. Krizhevsky and colleagues knew this: a footnote in the paper says that "most of the net's parameters are in the first fully-connected layer" (Krizhevsky et al., 2012). Every input of fc6 is wired to every one of its 4,096 outputs, and it has 9,216 inputs, so the dense wiring the convolutions avoided comes back in one enormous matrix.

There is a subtle exception hiding in that 9,216. The previous concept said parameter counts do not depend on input resolution, and for every convolution that is true. But fc6 takes the flattened 256 × 6 × 6 map as its c_i, and the 6 × 6 came from 224 × 224 through the strides and pools. Feed AlexNet a larger image and fc6 would need a larger weight matrix. The first linear layer after a flatten is the one place where resolution leaks into the parameter count. Global average pooling, introduced in Network in Network, removes that leak: it averages each channel to one number, and "there is no parameter to optimize" in it (Lin, Chen and Yan, 2014), so the classifier input no longer grows with the image.

This table is the starting line for two results you will study later. Han and colleagues pruned AlexNet "from 61 million to 6.7 million" parameters with no loss of accuracy, a 9x reduction (Han et al., 2015), and Deep Compression then cut its storage "from 240MB to 6.9MB" (Han, Mao and Dally, 2016). Both papers attack exactly the layers this table flags: when 96 percent of the weights sit in three linear layers, that is where pruning pays.

Quick check

In AlexNet, which group of layers holds most of the 61M parameters?

Recall

Which AlexNet layers hold about 96 percent of the parameters, and why is fc6 so large?

The three linear layers fc6, fc7 and fc8, with 58.6M of 61M. fc6 is the largest because its input is the flattened 256 × 6 × 6 = 9,216 map, fully wired to 4,096 outputs.

A parameter count is a number of boxes. To know how much storage the boxes take, you need the size of each box. Store AlexNet's 61M weights as 32-bit floating point and each weight takes 4 bytes, so the whole network takes 61M × 4 B = 244 MB. Store the same weights as 8-bitintegers and the same network takes 61 MB. Nothing about the architecture changed; only the bit width did.

Model Size=#ParametersBit Width\text{Model Size} = \#\text{Parameters} \cdot \text{Bit Width}
Valid when the whole network uses one data type. The result is in bits.

That is the definition of model size: the storage needed for the weights of the network, the #Parameters times the bits each one occupies. The slide lists MB, KB and bits as the common units, and the formula as written produces bits. To reach bytes divide by 8, and to reach megabytes divide by another 10^6. The slide is explicit that its megabyte is decimal, 244 × 10^6 bytes. For a single layer, kilobytes are the natural unit: AlexNet's conv3 holds 884,736 weights, which at 8 bits is 884,736 bytes, or 884.7 KB (divide bytes by 10^3), and at 32 bits 3,538.9 KB.

SizeMB=#Parametersbits per weight8106\text{Size}_{\text{MB}} = \frac{\#\text{Parameters} \cdot \text{bits per weight}}{8 \cdot 10^{6}}
Bits to decimal megabytes
The same 61M weights on four shelves. Each halving of the bit width halves the shelf, and int8 lands at a quarter of fp32.
Data typeSize in bitsSize (decimal MB)Slide rounding
32-bit float (fp32)1,950.5 Mbit243.8 MB244 MB
16-bit (fp16 or bfloat16)975.3 Mbit121.9 MB122 MB
8-bit integer (int8)487.6 Mbit61.0 MB61 MB
4-bit integer (int4)243.8 Mbit30.5 MB30.5 MB
1-bit (binary weights)61.0 Mbit7.6 MB7.6 MB
AlexNet model size at each bit width, using the exact count 60,954,656. The last column is what the slide's rounded 61M gives.

The formula assumes one data type for the whole network. Mixed-precision models break that assumption, and then the size is a sum over layers, each layer's count times its own bit width. That is the form you need when, for example, the first and last layers stay at 8 bits while the middle is pushed to 4.

Model Size=l#Paramslbitsl\text{Model Size} = \sum_{l} \#\text{Params}_l \cdot \text{bits}_l
Mixed precision: sum per layer

Why the multiplication matters for this course

The parameter count is fixed once the architecture is chosen, but the bit width is a knob. The lecture on quantization turns that knob, and this formula says exactly what it buys: every halving of the bit width halves the model size with no change to the architecture. Deep Compression combined pruning, quantization and Huffman coding to take AlexNet "from 240MB to 6.9MB" (Han, Mao and Dally, 2016); their 240 MB starting point is, up to rounding, the 244 MB computed in this concept. Part 03 shows a microcontroller SRAM budget of 256 kB (the MCU constraint, a budget for activations). The slides do not give a flash size, but a typical MCU of this class, such as the STM32F746 used by MCUNet (Lin et al., NeurIPS 2020), has about 1 MB of flash, where the weights would live; even 8-bitAlexNet at 61 MB is about 60 times too large for that flash, which is why edge deployment starts with counting.

Quick check

A 10M-parameter model stored entirely in 16-bit numbers occupies how much storage?

Recall

61M parameters at 8 bits: what is the model size in MB, and in bits?

61 MB, that is 61 × 10^6 bytes, because at 8 bits each weight is exactly one byte. In bits it is 61M × 8 = 488 × 10^6 bits.

Recap

If you remember nothing else

  • #Parameters is the number of elements in the weight tensors of the whole network. Bias is ignored in this lecture.
  • Linear c_o · c_i. Convolution c_o · c_i · k_h · k_w. Grouped divides that by g. Depthwise is c_o · k_h · k_w.
  • Parameter count ignores batch size and spatial size. MACs (part 04) do not, because every filter is reapplied at every output position.
  • AlexNet has 60,954,656 parameters, about 61M. conv1 is 34,848 (the slide prints 24,848) and the hidden conv5 is 442,368.
  • The three linear layers hold about 96 percent (58.6M). fc6 alone is 37.7M because its input is the flattened 256 × 6 × 6 map.
  • Pooling layers have zero parameters.
  • Model size = #Parameters × bit width. 61M weights are 244 MB at 32-bit, 122 MB at 16-bit and 61 MB at 8-bit, in decimal MB.

Sources

Part 03: Activations and peak memory

Why activations rather than parameters are the memory bottleneck in inference and training, how memory is spread across layers of MobileNetV2 and MCUNet, and how to compute total and peak activations for AlexNet.

4 concepts, slides 18-22

Why this part matters

When a vision model is pushed onto a UAV, a robot controller or an IoT board, the first question a compiler or a reviewer asks is not "how many parameters" but "what is the peak activation". Those boards carry 256 kB to 512 kB of SRAM and no DRAM, and it is the activations, not the weights, that have to live there.

Part 02 counted weights and turned them into a model size. This part counts the other tensor family, the activations, and shows why they decide fit. You get the two ratios to quote in an exam (parameters fell 4.6x while peak activation rose 1.8x; in training, 4.3x against 1.1x), the reason MobileNet-style models can still fail on a microcontroller, a rule for where in a network the memory sits, and a formula for peak memory that you can apply to any layer list.

By the end you can

  1. Explain why activations, not parameters, bound memory in both CNN inference and training, quoting 4.6x against 1.8x and 4.3x against 1.1x.
  2. Read a per-block or per-layer memory profile and say which layers set the SRAM peak, which set the flash budget, and why resolution and channel growth cause it.
  3. Compute total and peak #activations for a given layer list using peak ≈ max over layers of input + output, and convert to bytes for a chosen bit width.
  4. State the assumptions behind the peak approximation: layer-by-layer execution, no branches, no in-place operations, no scratch buffers.
  5. Place weights in flash and activations in SRAM, and connect activation size to the memory term of the latency model from part 01.

Take a real target: an STM32F746 microcontroller has a Cortex-M7 core, 1 MB of flash and 320 kB of SRAM. It has no DRAM and no operating system; MCUNet describes such boards as bare-metal devices (Lin et al., 2020). Now take two ImageNet classifiers that both reach about 70 percent top-1 accuracy with every value stored as an 8-bit integer. ResNet-18 needs 11.2 MB for its weights. MobileNetV2 at width 0.75 needs about 2.5 MB as MCUNet's Figure 8 labels the bar, a 4.6x reduction on the slide (strictly 11.2 / 2.5 ≈ 4.5; the paper rounds to 4.6x). If parameters were the memory story, the second model would be the obvious choice.

Then look at the other pair of bars. The largest amount of activation memory that ResNet-18 needs at any moment is 0.9 MB. For MobileNetV2-0.75 it is 1.7 MB. The efficient model is 1.8x worse on peak activations, and the MCUNet paper says so plainly: MobileNetV2 "reduces the model size by 4.6x compared to ResNet-18, but the peak activation size increases by 1.8x, making it even more difficult to fit the SRAM on microcontrollers" (Lin et al., 2020). Neither model fits 320 kB. The memory bottleneck moved without anyone shrinking it.

Parameter memory drops 4.6x from ResNet-18 to MobileNetV2-0.75, but peak activation rises 1.8x. Both peak bars stand far above a 320 kB SRAM line.

Two budgets, and the smaller one belongs to activations

The reason the two bars behave differently is that they are paid from different memories. Weights are read-only: they are written once when the firmware is flashed and only read during inference, so they live in flash, the larger and cheaper memory. Activations are produced by one layer and consumed by the next on every single inference, so they must sit in memory that can be written and read at speed, which on a microcontroller is the on-chip SRAM. MCUNet puts it in one sentence: "SRAM constrains the activation size (read&write); Flash constrains the model size (read-only)" (Lin et al., 2020). The model size from part 02 answers the flash question. The peak activation answers the SRAM question, and SRAM is the scarcer of the two by a factor of two to four on every board in MCUNet's list (the STM32F746 has about 3x more flash than SRAM).

This also explains why bit width alone does not rescue MobileNetV2. The slide already assumes 8-bit integers for both weights and activations. Even after that 4x shrink from 32-bit floats, the peak sits at 1.7 MB. MCUNet's Table 1 reports 1.7 MB for full-width int8 MobileNetV2 (6.8 MB in fp32), 5.3x over the 320 kB of an STM32F746, not counting im2col or other runtime buffers. Quantization scales both bars by the same factor; it does not change which bar is the problem.

ModelParam memory (flash)Peak activation (SRAM)Fits STM32F746 (1 MB flash, 320 kB SRAM)?Fits STM32H743 (2 MB flash, 512 kB SRAM)?
ResNet-1811.2 MB0.9 MBNo (flash and SRAM)No (flash and SRAM)
MobileNetV2-0.752.5 MB1.7 MBNo (flash and SRAM)No (flash and SRAM)
MCUNet (paper, Figure 8)1.9 MB0.49 MBNo (flash and SRAM)Yes
Two models at about 70 percent ImageNet top-1, int8, against two MCUNet target boards

The MCUNet row comes from Figure 8 of the same paper and is there to show what solving the right problem looks like: its designers shrank the peak activation below 0.5 MB rather than chasing a smaller parameter count, and only then did an ImageNet model fit a 512 kB board. The 4.6x model is not an efficient model for this class of device; it is an efficient model for a phone, where DRAM is plentiful and flash is not the constraint.

Why MobileNetV2 in particular: an imbalanced profile

The right-hand chart explains where MobileNetV2's peak comes from. Plot the memory that each of its eighteen blocks needs and the profile is wildly uneven: block 2 needs 1372 kB, blocks 0, 1, 3 and 4 sit between roughly 500 kB and 600 kB, and the remaining thirteen blocks mostly need 40 kB to 170 kB. Draw the 256 kB constraint of a typical microcontroller and exactly five blocks cross it. MCUNetV2, the follow-up paper that this chart comes from, states it directly: "The first 5 blocks have large peak memory, exceeding the memory constraints of MCUs, while the remaining 13 blocks easily fit 256kB memory constraints. The third block has 8x larger memory usage than the rest of the network" (Lin et al., 2021).

Eighteen MobileNetV2 blocks against a 256 kB line: the first five stand above it, with block 2 at 1372 kB, while thirteen stay below.

The two charts on the slide come from different papers with different memory accounting: the left bars are MCUNet's (2020) figures for MobileNetV2-0.75, while the right chart is MCUNetV2's analytic input-plus-output count for full-width MobileNetV2 in int8, so the numbers are not directly comparable. Its block 2 peak is 16×112×112 + 96×112×112 = 1,404,928 B, which is 1372 kB in 1024-byte kilobytes.

The cause is the shape of MobileNetV2's inverted residual block. Each block first expands the channel count about six times with a 1×1 convolution, applies a depthwise 3×3, and projects back down. The depthwise step is what makes the block cheap in weights and MACs, exactly as part 02 computed. But the expanded tensor exists at full spatial resolution, and in the early blocks that resolution is 112×112 or 56×56. Six times the channels at a large H×W gives a huge activation in a block that owns almost no parameters. MCUNet's per-block peak memory analysis (Figure 11) measures the same imbalance on a MobileNetV2 scaled to 0.3x width to fit 320 kB: even then one block has 2.2x the peak activation of the average block (Lin et al., 2020). A model can be light in weights and heavy in activations at the same time, and this architecture is the canonical example.

Quick check

At about 70 percent ImageNet top-1 with 8-bit values, what happens to peak activation memory going from ResNet-18 to MobileNetV2-0.75?

Recall

Why is MobileNetV2 not microcontroller friendly even though it has few parameters?

Its early inverted residual blocks expand channels about six times while the feature map is still at high resolution, so block 2 needs 1372 kB and the first five blocks all exceed 256 kB. The binding budget on a microcontroller is SRAM, which holds activations, not flash, which holds the weights.

Recall

Where do weights and activations live on a microcontroller at run time, and which one sets the peak?

Weights live in flash (read only, written once). Activations live in SRAM (written and read every inference). The largest input plus output pair sets the SRAM peak.

Inference keeps a few activations alive; training keeps all of them. Switch to 32-bit floats and a training step of ResNet-50. Its weights take 102 MB. Its activations, for one mini-batch, take 707 MB, about 7x more. Now swap in MobileNetV2 at width 1.4: the weights fall to about 24 MB, a 4.3x reduction, but the activations fall only to about 626 MB, a 1.1x reduction. The TinyTL paper that produced these numbers concludes: "It is the activation that bottlenecks the training memory, not the parameters" (Cai et al., 2020).

ModelParameters (MB)Activations (MB)Activations ÷ parameters
ResNet-50102707about 7x
MobileNetV2-1.4about 24about 626about 26x
Reduction4.3x1.1x
Training memory per mini-batch, fp32 (slide values, batch 8; TinyTL Figure 1 shows exactly double at batch 16)

The mechanism is backpropagation itself. Write one linear layer as a_(i+1) = a_i W + b, where a_i is the layer's input activation. To update the weight you need the gradient of the loss with respect to W, and that gradient is the outer product of the input activation with the gradient flowing back from the next layer.

LWi=aiTLai+1,Lbi=Lai+1\frac{\partial L}{\partial W_i} = a_i^{\mathsf{T}}\,\frac{\partial L}{\partial a_{i+1}}, \qquad \frac{\partial L}{\partial b_i} = \frac{\partial L}{\partial a_{i+1}}
Backpropagation through one linear layer (TinyTL, equation 2). The weight gradient needs the stored input a_i; the bias gradient does not.

The forward pass computes a_1, then a_2, and so on up to the loss. The backward pass returns in reverse order, and when it reaches layer i it must still have a_i. So every layer's input has to be held from the moment it is produced until the backward pass comes back to it. Goodfellow, Bengio and Courville make the same point for a multilayer perceptron: "we need to store the input to the nonlinearity of the hidden layer. This value is stored from the time it is computed until the backward pass has returned to the same point," and the cost per layer is O(m·n_h) for a mini-batch of m examples and n_h hidden units (Goodfellow et al., 2016, section 6.5.7). Depth multiplies that cost by the number of layers, and the batch size multiplies it again.

Inference slides a two-buffer window along the network. Training fills every buffer on the forward pass and only frees each one when the backward pass reads it.
ModeWhich activations are heldHow manyMemory rule
InferenceInput and output of the layer running nowTwo tensorsLargest input + output pair
TrainingEvery layer input a_i until its dL/dW_i is computedAll tensors, times the batchSum of all activations × batch size
What has to be alive at once
Mtrainmiaibytes  +  Mweights  +  Mgradients  +  MoptimizerM_{\text{train}} \approx m \sum_i |a_i| \cdot \text{bytes} \;+\; M_{\text{weights}} \;+\; M_{\text{gradients}} \;+\; M_{\text{optimizer}}
Training memory. The slide counts only the first two terms, so the true gap to inference is even larger.

Worked example

AlexNet in fp32, inference against training

  1. Inference peak

    The last concept derives AlexNet's peak (440,928 values) and total (932,264 values); take them as given here. At 4 bytes each, the peak is 1.76 MB of activations alive at once.
  2. Training, batch of one

    All 932,264 activations are held for the backward pass: 932,264 × 4 B = 3.73 MB, more than double the inference peak before counting gradients.
  3. Training, batch of sixteen

    Activations scale with the batch: 16 × 3.73 MB ≈ 60 MB. The weights do not scale; AlexNet's 61M parameters stay at 244 MB whatever the batch, and their gradients add another 244 MB.
  4. Why the slide's bars look the way they do

    AlexNet is unusual: its huge fully connected layers make weights dominate even in training. ResNet-50 and MobileNetV2 are mostly convolutions with large feature maps, so at the slide's batch of 8 their activations (707 MB and about 626 MB) dwarf their weights (102 MB and 24 MB).

The formula also points to the cure that TinyTL proposes and that this course returns to when it reaches on-device learning. The bias gradient in equation 2 needs no stored activation at all. If you freeze the weights and update only biases (plus a small added module), the a_i tensors never have to be kept, and the 707 MB term collapses. That is a memory argument, not an accuracy argument, and it is only visible once you have separated activations from parameters as this slide does. It matters doubly on a microcontroller, because TinyTL notes that DRAM access consumes two orders of magnitude more energy than on-chip SRAM access (Cai et al., 2020), echoing the Horowitz numbers from part 01.

Quick check

Why does training need far more activation memory than inference for the same network?

Recall

Quote the four ratios from slides 18 and 19 and say what each one compares.

4.6x less parameter memory and 1.8x more peak activation: ResNet-18 to MobileNetV2-0.75, int8, inference. 4.3x less parameter memory and 1.1x less activation memory: ResNet-50 to MobileNetV2-1.4, fp32, training at batch 8.

Recall

Why does training need every activation while inference needs only two?

The weight gradient dL/dW_i is the product of the stored input a_i and the gradient from the next layer, so every a_i is held until the backward pass reaches it. Inference has no backward pass and frees an input as soon as the layer's output exists.

Plot, layer by layer, how much memory the activations and the weights of an efficient network take, and a clear shape appears. For MCUNet, a network designed for microcontrollers, the first six layers need 50 kB to 75 kB of activation memory and almost no weight memory, and activation stays the dominant term, mostly 20 kB to 55 kB, out to about layer 17. Around layers 18 to 30 both are small, under about 15 kB. From layer 32 onward the weight memory climbs to 35 kB to 75 kB while activations stay near 5 kB to 10 kB. The total traces a U: expensive at both ends, cheap in the middle, for two different reasons. The chart comes from MCUNet's on-device training work and shows the memory needed to update each layer, which is the stored input activation plus the weight and its gradient. The same geometry governs inference, as the AlexNet arithmetic below shows.

LayersActivation memoryWeight memoryDominant
0 to 550 to 75 kBabout 0Activation
6 to 1720 to 55 kBabout 0Activation
18 to 30under 15 kBunder 15 kBNeither
32 to 425 to 10 kB35 to 75 kBWeight
The U in one table: which tensor dominates each band of the MCUNet profile
Activation memory (amber) decays across the early layers while weight memory (teal) climbs across the late ones; the dashed U is their sum.

The two counting rules from part 02 predict this. An activation tensor holds C × H × W values. A convolution weight tensor holds C_o × C_i × k_h × k_w values. Now follow a CNN from input to output. At every downsampling stage the spatial size halves in each direction, so H × W drops by 4x, while the channel count typically only doubles. The activation count C × H × W therefore falls by about 2x per stage. The weight count contains C_o × C_i, which grows by about 4x when channels double and does not care about H and W at all. MCUNetV2 states the consequence: "the memory bottleneck tends to appear at the early stage of the network" because resolution shrinks faster than channels grow (Lin et al., 2021).

The same U in numbers you already computed

You do not have to trust the chart. Take the AlexNet layers from part 02, put each layer's output activation count next to its weight count, and the profile reproduces itself from arithmetic.

LayerOutput C×H×WActivationsWeightsWhich dominates
conv196×55×55290,40034,848Activations, 8x
conv2256×27×27186,624307,200Weights, 1.6x
conv3384×13×1364,896884,736Weights, 14x
conv4384×13×1364,896663,552Weights, 10x
conv5256×13×1343,264442,368Weights, 10x
fc640964,09637,748,736Weights, 9,216x
fc740964,09616,777,216Weights, 4,096x
fc810001,0004,096,000Weights, 4,096x
AlexNet per layer: output activations against weights (biases ignored, as in this lecture)

The first convolution has 8x more activations than weights: a 55×55 map with 96 channels is large, and an 11×11 filter over only 3 input channels is small. By conv3 the map is 13×13 and the weights are already 14x the activations. The fully connected layers are the extreme: fc6 emits 4,096 values and owns 37.7M weights. Nothing about AlexNet was designed to show this; it is the geometry of every CNN.

What each end of the U decides

  • The early, activation-heavy stage sets the SRAM peak. That is why MobileNetV2's problem in the previous concept was in blocks 0 to 4, and why MCUNetV2 runs only that stage in patches.
  • The late, weight-heavy stage sets the flash budget and most of the parameter count. Pruning and quantization pay off most there.
  • The cheap middle is where on-device training is affordable: updating a middle layer needs neither a large stored activation nor a large weight gradient. This band is exactly what the training chart above measures, and the paper it comes from exploits exactly that band (Lin et al., 2022).

Quick check

In the MCUNet per-layer profile, which memory dominates the last layers, and why?

Recall

In one sentence each: why is activation memory high in early layers, and why is weight memory high in late layers?

Early layers keep a large H × W with few channels, so C × H × W is large. Late layers have many input and output channels, so C_o × C_i × k_h × k_w is large while the map has shrunk to a few pixels.

Counting AlexNet activations: total versus peak

Now make the peak a number you can compute. AlexNet takes a 3×224×224 image: 150,528 values. Its first convolution emits 96×55×55 = 290,400 values. While that convolution runs, both tensors must exist, because the layer is still reading the image as it writes the output: 150,528 + 290,400 = 440,928. When the first pooling layer runs, the image is no longer needed and can be freed, but the convolution output (290,400) and the pooling output (69,984) are both alive: 360,384. Memory rises and falls one layer at a time.

Two counts fall out of this picture. The total number of activations is the sum over the input and every layer output, which for AlexNet is 932,264. The peak number of activations is the largest number alive at any one moment. For a plain chain of layers executed one at a time, that is the largest input plus output pair. MCUNetV2 gives the rule and the reason: "the memory required for a layer is the sum of input and output activation (since weights can be partially fetched from Flash)", and the runtime "allocates the input and output activation buffer in SRAM, and releases the input buffer after the whole layer computation is finished" (Lin et al., 2021).

#acttotal=x0+i=1Lai\#\text{act}_{\text{total}} = |x_0| + \sum_{i=1}^{L} |a_i|
Total activations: the input plus every layer output
#actpeakmaxi(ai1+ai)\#\text{act}_{\text{peak}} \approx \max_{i}\big(|a_{i-1}| + |a_i|\big)
Peak activations: the largest input plus output pair over all layers

The approximation sign carries four assumptions, and an exam answer should name at least one of them. The network runs layer by layer, with no two layers in flight together. Weights are streamed from flash and are not counted in SRAM. There are no residual branches; if there are, MCUNetV2 says to add the memory of all branches alive at the same time, counting a shared input once. And there are no in-place tricks: MCUNet shows that a depthwise layer can overwrite its input channel by channel, needing N + 1 instead of 2N values (Lin et al., 2020). Real runtimes also need scratch buffers for im2col or accumulation, which push the true peak slightly above the formula.

Sweep through AlexNet yourself before reading the worked example. Watch which two bars are highlighted, how the running peak stops moving after the first layer, and how the bit width and the SRAM preset change whether the same 440,928 values fit.

SimulatorPeak memory sweeper: AlexNet, one layer at a time
image150,528conv1290,400pool1conv2pool2conv3conv4conv5pool3fc6fc7fc8256 kB SRAM290.4 kB0
Live now (input + output)440,928elements150,528 + 290,400 = 440.9 kB, over the 256 kB limit
Running peak440,928elements440.9 kB at conv1; whole network peaks at 440.9 kB
Total so far440,928elementsevery tensor produced so far; all 12 sum to 932,264 = 932.3 kB
Layer executingInputOutputLiveAt 8-bit
150,528290,400440,928440.9 kB
290,40069,984360,384360.4 kB
69,984186,624256,608256.6 kB
186,62443,264229,888229.9 kB
43,26464,896108,160108.2 kB
64,89664,896129,792129.8 kB
64,89643,264108,160108.2 kB
43,2649,21652,48052.5 kB
9,2164,09613,31213.3 kB
4,0964,0968,1928.2 kB
4,0961,0005,0965.1 kB

Each bar is one tensor at 8-bit, linear scale; the dashed window holds the executing layer's input and output. Bytes are elements × bits ÷ 8 and kB is decimal (÷ 1000), as on slide 17. Selected preset: STM32F412, Cortex-M4. Weights are not counted here because on a microcontroller they stay in flash and are streamed in, so SRAM only has to hold the two live activation buffers.

Worked example

Total and peak activations of AlexNet

  1. Write the C × H × W column

    150,528; 290,400; 69,984; 186,624; 43,264; 64,896; 64,896; 43,264; 9,216; 4,096; 4,096; 1,000, from the image through fc8. Each entry is channels × height × width, or just the channel count for a linear layer.
  2. Sum for the total

    932,264 values, matching the slide. This is the number that training would have to hold.
  3. Form the eleven adjacent sums

    Input + output while each layer executes

    conv1 runs (image + conv1 out)
    150,528 + 290,400 = 440,928
    pool1 runs (conv1 out + pool1 out)
    290,400 + 69,984 = 360,384
    conv2 runs (pool1 out + conv2 out)
    69,984 + 186,624 = 256,608
    pool2 runs (conv2 out + pool2 out)
    186,624 + 43,264 = 229,888
    conv3 runs (pool2 out + conv3 out)
    43,264 + 64,896 = 108,160
    conv4 runs (conv3 out + conv4 out)
    64,896 + 64,896 = 129,792
    conv5 runs (conv4 out + conv5 out)
    64,896 + 43,264 = 108,160
    pool3 runs (conv5 out + pool3 out)
    43,264 + 9,216 = 52,480
    fc6 runs (pool3 out + fc6 out)
    9,216 + 4,096 = 13,312
    fc7 runs (fc6 out + fc7 out)
    4,096 + 4,096 = 8,192
    fc8 runs (fc7 out + fc8 out)
    4,096 + 1,000 = 5,096
  4. Pick the maximum

    The first row wins: 440,928 while conv1 runs. The runner-up, conv1 output plus pool1 output, is 360,384, and by conv3 the pairs are a quarter of the peak.
  5. Convert to bytes for a bit width

    AlexNet activation memory by bit width (kB decimal, KiB binary)

    Peak, 8-bit integers
    440,928 B ≈ 441 kB (431 KiB)
    Peak, 32-bit floats
    1,763,712 B ≈ 1.76 MB (1.68 MiB)
    Total, 8-bit integers
    932,264 B ≈ 932 kB (910 KiB)
    Total, 32-bit floats
    3,729,056 B ≈ 3.73 MB (3.56 MiB)
  6. Peak = 440,928 values

    441 kB at 8-bit and 1.76 MB at 32-bit. Even fully quantized, AlexNet's first layer alone exceeds a 256 kB or 320 kB microcontroller, and the peak is 47 percent of the total.

The same arithmetic explains why MobileNetV2 failed in the first concept. Its first convolution maps a 3×224×224 image to 32×112×112: 150,528 + 401,408 = 551,936 values, which MCUNetV2 quotes as "539kB even when quantized in int8" (using 1024-byte kilobytes). A 224 input through a standard stem can never run layer by layer on a 256 kB board, whatever happens to the weights afterwards.

Finally, connect the counts back to latency. Part 01 approximated memory time as the bytes of activations and weights moved divided by the memory bandwidth. The per-layer input plus output is the activation traffic of that layer, so the same column that gives the peak also feeds the latency model. Peak tells you whether the model fits; total tells you how many activation bytes cross the memory interface per inference.

Quick check

During layer-by-layer inference, which quantity approximates the peak activation memory of a CNN?

Recall

A toy CNN: input 3×32×32, a convolution to 16×32×32, a pool to 16×16×16, then a linear layer to 10 outputs. Total and peak #activations?

Counts: 3,072; 16,384; 4,096; 10. Total 23,562. Adjacent sums 19,456, 20,480, 4,106. Peak 20,480, while the pool runs (convolution output plus pool output), not the input pair. About 20.5 kB at 8-bit.

Recall

AlexNet's peak is 440,928 values. How many kB is that at 8-bit and at 32-bit, and does either fit a 320 kB STM32F746?

441 kB at 8-bit and 1.76 MB at 32-bit (decimal kilobytes). Neither fits 320 kB; the first layer alone is over budget.

Recap

If you remember nothing else

  • SRAM holds activations (read and write); flash holds weights (read only). SRAM is the smaller budget, so activations decide whether a model fits.
  • ResNet-18 to MobileNetV2-0.75 at about 70 percent top-1, int8: parameter memory 4.6x smaller, peak activation 1.8x larger.
  • MobileNetV2's memory is imbalanced: 1372 kB at block 2, the first five blocks above 256 kB, the remaining thirteen below it.
  • Training keeps every layer input for dL/dW. ResNet-50 in fp32 at batch 8: 102 MB of weights against 707 MB of activations; MobileNetV2-1.4 cuts weights 4.3x but activations only 1.1x.
  • Activation memory is high in early layers (large H×W) and weight memory is high in late layers (large C_o·C_i); the middle is cheap.
  • Total #activations sums every tensor (AlexNet: 932,264). Peak ≈ the largest input + output pair (AlexNet: 150,528 + 290,400 = 440,928 at conv1).
  • 440,928 values are 441 kB at 8-bit and 1.76 MB at 32-bit, above a 256 kB or 320 kB microcontroller either way.
  • The peak formula assumes layer-by-layer execution and ignores residual branches, in-place tricks and runtime scratch buffers.

Sources

Part 04: MACs, FLOPs and operations

Counting computation as multiply-accumulate operations for matrix products and each layer type, AlexNet's 724M MACs, and converting to FLOPs, FLOPS, OPs and OPS.

5 concepts, slides 23-29

Why this part matters

Part 02 measured what a network stores and part 03 what it must hold in memory. This part measures what it must compute. That number is the numerator of computation time in the Latency model of slide 8, the figure every accelerator datasheet is quoted against, and the figure you will report for any model in the research project.

The counting unit is the multiply-accumulate, and everything else is bookkeeping on top of it: how many MACs a matrix product costs, how many each layer type costs, what AlexNet adds up to, and how the count becomes FLOPs, OPs and finally milliseconds on a specific chip. The surprise waiting at the centre of the part is that the layers holding almost all of AlexNet's weights do almost none of its arithmetic. Every exam question on efficiency metrics circles back to that inversion.

By the end you can

  1. Define a multiply-accumulate operation and count MACs for a matrix-vector product and a matrix-matrix product.
  2. Fill the MACs table for linear, convolution, grouped and depthwise layers, and explain why conv MACs equal parameters times h_o·w_o.
  3. Reproduce AlexNet's 724M MACs layer by layer and explain why convolutions dominate compute while linear layers dominate parameters.
  4. Convert MACs to FLOPs and OPs, and tell a count (FLOPs, OPs) apart from a rate (FLOPS, OPS).
  5. Estimate T_computation for a model on a device from the model's OPs and the device's OPS.

Start with one neuron that has four inputs. Its output before the activation function is w₁x₁ + w₂x₂ + w₃x₃ + w₄x₄. A processor evaluates that as four identical steps: multiply a weight by an input, add the product to a running total. Each step is one multiply-accumulate operation, and the whole of neural network inference is this step repeated a few hundred million times.

aa+bca \leftarrow a + b \cdot c
One MAC: multiply b by c and accumulate into a

The definition is standard well beyond this course. The Wikipedia entry on the multiply-accumulate operation gives exactly a ← a + (b × c), and notes that IEEE 754-2008 defines a fused multiply-add that performs the whole step with a single rounding. Sze, Chen, Yang and Emer call the MAC "the fundamental component" of DNN processing in their survey of efficient DNN hardware. Counting MACs is therefore counting what the hardware executes, not an abstraction layered over it.

From one neuron to a matrix-vector product

A layer of m neurons that each read the same n inputs is a matrix-vector multiplication: an m × n weight matrix times an n-vector. Each of the m outputs needs n MACs, one per weight in its row, so the product costs m · n MACs. Notice that this is also the number of weights. In a matrix-vector product, every weight is touched exactly once.

Feed the layer a batch of inputs at once and the vector becomes a matrix. The slide renames the dimensions here: the input count becomes k and the letter n is reused for the batch, the number of columns of B. The result is a general matrix-matrix multiplication: A of size m × k times B of size k × n gives C of size m × n. Every one of the m · n cells of C is a dot product over the shared dimension k, so it costs k MACs, and the whole product costs m · n · k.

MACsMV=mnMACsGEMM=mnk\text{MACs}_{MV} = m \cdot n \qquad \text{MACs}_{GEMM} = m \cdot n \cdot k
Rows times columns for a vector, rows times columns times the shared dimension for a matrix
Each cell of C is one dot product over the shared dimension: k pairs, k MACs. There are m × n such cells.

Dimensions used in the GEMM count

m
Rows of A and of C: the number of outputs (neurons)
k
Columns of A and rows of B: the shared dimension summed over, the number of inputs per neuron
n
Columns of B and of C: the number of input vectors, the batch

Why a whole network reduces to this

A Linear layer is literally a matrix-vector product at batch size one and a GEMM for a batch. Convolution looks different but is executed the same way: frameworks reorder the input patches into columns (the im2col trick described in the CS231n notes) so that a convolution becomes one large GEMM, and the MobileNets paper points out that this is why convolutions can ride on "highly optimized general matrix multiply (GEMM) functions". NVIDIA's performance guide states the cost of a GEMM as 2 · M · N · K floating point operations because "each FMA is 2 operations, a multiply and an add", which previews the FLOP conversion at the end of this part. Once you can count MACs for a matrix product, you can count them for every layer.

Recall

Write the MAC operation, and state how many MACs an m × n matrix times an n-vector costs.

a ← a + b · c. The product costs m · n MACs, one for every weight in the matrix.

Take the first layer of AlexNet. One filter spans all 3 input channels with an 11 × 11 window, so it holds 3 × 11 × 11 = 363 weights. Producing a single output pixel is one dot product of those 363 weights against a patch of the image: 363 MACs. But the filter does not produce one pixel. It slides to every one of the 55 × 55 = 3,025 output positions, and there are 96 filters. So the layer costs 363 × 3,025 × 96 = 105,415,200 MACs from only 34,848 weights.

That example contains the whole rule. In a convolution layer every weight is applied once per output position, so the MAC count is the parameter count from part 02 multiplied by the output height and width:

MACsconv=cocikhkwparametershowo\text{MACs}_{conv} = \underbrace{c_o \cdot c_i \cdot k_h \cdot k_w}_{\text{parameters}} \cdot h_o \cdot w_o
Parameters times output positions, at batch size n = 1 and ignoring bias
Nine weights stamped onto twenty-five output positions: 225 MACs from 9 parameters. The filter is reused, never copied.

The other rows of the slide's table follow from the same idea. A Linear layer has h_o = w_o = 1, so its MACs equal its parameters, c_o · c_i. A Grouped convolution splits the channels into g groups, so each filter sees only c_i / g input channels and both parameters and MACs are divided by g. A Depthwise convolution is the extreme case g = c_i = c_o: each filter sees exactly one channel, so c_i disappears from the formula entirely and only c_o · k_h · k_w weights remain, each still applied h_o · w_o times.

LayerParametersMACsMACs per parameter
Linearc_o · c_ic_o · c_i1
Convolutionc_o · c_i · k_h · k_wc_o · c_i · k_h · k_w · h_o · w_oh_o · w_o
Grouped convolutionc_o · c_i · k_h · k_w / gc_o · c_i · k_h · k_w · h_o · w_o / gh_o · w_o
Depthwise convolutionc_o · k_h · k_wc_o · k_h · k_w · h_o · w_oh_o · w_o
Parameters and MACs per layer type (batch size n = 1, bias ignored)

How a convolution slides, how padding and stride set the output size, and how groups partition channels were covered in lecture 02, part 02 and part 03. This part only counts, and it takes the kernel size and output shape of each layer as given.

Why this mirrors part 02

Goodfellow, Bengio and Courville explain parameter sharing in one sentence that is the whole story of this part: sharing "does not affect the runtime of forward propagation, it is still O(k × n), but it does further reduce the storage requirements of the model to k parameters". Convolution saves storage by reusing weights, and reusing weights is exactly what makes the arithmetic grow. That is why parts 02 and 04 are mirror images. The layers cheapest to store are the most expensive to run.

Worked example: the MobileNet block that makes depthwise worth it

The MobileNets paper replaces one standard 3 × 3 convolution with a depthwise 3 × 3 followed by a pointwise 1 × 1. Its equations 4 and 5 give the depthwise and separable costs, and dividing by the standard cost gives the ratio 1 / N + 1 / D_K², where N is the number of output channels and D_K the kernel size. The formulas in the table let you reproduce that with real numbers.

Worked example

Standard versus depthwise separable at 112 × 112, 32 to 64 channels

  1. Standard 3 × 3 convolution

    64 × 32 × 3 × 3 × 112 × 112 = 231,211,008 MACs.
  2. Depthwise 3 × 3

    32 × 3 × 3 × 112 × 112 = 3,612,672 MACs. No c_i factor.
  3. Pointwise 1 × 1

    64 × 32 × 1 × 1 × 112 × 112 = 25,690,112 MACs. A convolution with k = 1.
  4. Ratio

    (3,612,672 + 25,690,112) / 231,211,008 = 0.1267, and 1 / 64 + 1 / 9 = 0.1267.
  5. Result

    About 7.9× fewer MACs at 64 output channels, approaching the paper's "between 8 to 9 times less computation" as the channel count grows and the 1 / D_K² = 1 / 9 pointwise term is all that remains.

The calculator below lets you scrub every symbol in the table. Its FLOPs, OPs and hardware rows are explained in the last concept of this part; for now watch how parameters and MACs move apart as the output size grows.

SimulatorLayer compute calculator: MACs, FLOPs and computation time
Layer presets
k_h = k_wKernel size
Parameters34,848weightsc_o · c_i · k_h · k_w
MACs105,415,200(105.42 M)parameters × h_o × w_o = parameters × 3,025
MACs per parameter3,025uses per weightequal to h_o × w_o
FLOPs210.83 MFLOPs2 × MACs: one multiply and one add
OPs210.83 MOPssame count for integer weights and activations
Share of AlexNet14.6% of 724M MACsthis one layer against the whole network
Hardware: processor throughput100.0 GOPS
10^11.0 OPS

illustrative mobile GPU-class figure

T computation2.11msOPs of the layer ÷ OPS of the processor
Reading210.83 MOPs ÷ 100.0 GOPSthe numerator is a count, the denominator a rate

Drag h_o = w_o and watch MACs climb while parameters stay put: a convolution reuses every weight at every output position. Switch to linear and the two counts collapse into one. The hardware box only divides: the same layer takes 1000× longer at 1 GFLOPS than at 1 TFLOPS, and marketing peak TOPS are rarely sustained, so treat the time as a floor.

Quick check

A grouped convolution has c_i = 96, c_o = 256, a 5 × 5 kernel, a 27 × 27 output and g = 2. How many MACs does it perform?

Recall

A grouped convolution has 384 filters over 384 input channels, a 3 × 3 kernel, a 13 × 13 output and g = 2. How many MACs, how many parameters, and what is their ratio?

MACs: 384 · 384 · 9 · 169 / 2 = 112,140,288. Parameters: 384 · 384 · 9 / 2 = 663,552. The ratio is 169 = 13 × 13, one use of each weight per output position. This is AlexNet conv4.

Slide 25 hands you the eight weighted layers of AlexNet with their output shapes and an empty MACs column. Slide 26 fills it in, except for one layer hidden behind a question mark. Work through the column yourself before you read the answers. Every entry is the formula from the previous concept with the layer's numbers substituted, and the pooling layers contribute nothing because they hold no weights.

Worked example

AlexNet, layer by layer (batch size 1, bias ignored)

  1. conv1: 11 × 11, 3 to 96 channels, output 55 × 55

    96 × 3 × 11 × 11 × 55 × 55 = 105,415,200
  2. conv2: 5 × 5, 96 to 256 channels, groups 2, output 27 × 27

    256 × 96 × 5 × 5 × 27 × 27 / 2 = 223,948,800. Without the groups it would be 447,897,600; g = 2 halves it.
  3. conv3: 3 × 3, 256 to 384 channels, output 13 × 13

    384 × 256 × 3 × 3 × 13 × 13 = 149,520,384
  4. conv4: 3 × 3, 384 to 384 channels, groups 2, output 13 × 13

    384 × 384 × 3 × 3 × 13 × 13 / 2 = 112,140,288
  5. conv5: 3 × 3, 384 to 256 channels, groups 2, output 13 × 13

    This is the entry the slide hides. Compute it before revealing.

    Recall

    conv5 MACs?

    256 × 384 × 3 × 3 × 13 × 13 / 2 = 74,760,192
  6. fc6: 256 × 6 × 6 = 9,216 inputs to 4,096 outputs

    4,096 × 9,216 = 37,748,736. The flattened pooling output is the input vector.
  7. fc7: 4,096 to 4,096

    4,096 × 4,096 = 16,777,216
  8. fc8: 4,096 to 1,000 classes

    1,000 × 4,096 = 4,096,000
  9. Total

    724,406,816 MACs, the slide's "724M in total". Sze et al. list the same figure, 724M MACs and 61M weights, in their survey table.

Put the parameters next to the MACs

The total is not the interesting number. The interesting number appears when you place the parameter counts from part 02 beside the MACs and add a column for their ratio, which by the previous concept is just h_o · w_o.

LayerShapeParametersMACsMACs per parameter
conv196 × 3 × 11 × 11, out 55 × 5534,848105,415,2003,025
conv2256 × 96 × 5 × 5 / 2, out 27 × 27307,200223,948,800729
conv3384 × 256 × 3 × 3, out 13 × 13884,736149,520,384169
conv4384 × 384 × 3 × 3 / 2, out 13 × 13663,552112,140,288169
conv5256 × 384 × 3 × 3 / 2, out 13 × 13442,36874,760,192169
fc64096 × (256 × 6 × 6)37,748,73637,748,7361
fc74096 × 409616,777,21616,777,2161
fc81000 × 40964,096,0004,096,0001
conv1 to conv5five convolutions2,332,704 (3.8%)665,784,864 (91.9%)
fc6 to fc8three linear layers58,621,952 (96.2%)58,621,952 (8.1%)
Totaleight weighted layers60,954,656724,406,816
AlexNet: parameters and MACs per layer
The last column of the table, drawn. Each layer's slice of the MAC bar is its slice of the parameter bar stretched by h_o · w_o: conv1 grows 3,025 times, the linear layers not at all, so the convolution segments take over the lower bar.

The five convolutions hold 2,332,704 parameters, under 4% of the network, yet perform 665,784,864 MACs, 92% of the compute. The three linear layers hold 58,621,952 parameters, 96% of the network, yet perform only 58,621,952 MACs, 8% of the compute. The last column explains it: each conv1 weight is used 3,025 times, each conv3 to conv5 weight 169 times, each linear weight once. Large spatial maps early in the network make convolution compute heavy. Large c_i · c_o products late in the network make the linear layers parameter heavy.

InteractiveWhere AlexNet spends parameters versus compute
total 60,954,656 weights
fc6fc7fc8
conv1 to conv53.8%2.3M
fc6 to fc896.2%58.6M

Flip the toggle and watch which single layer is largest. Under parameters it is fc6, about 62% of the network on its own. Under MACs it is conv2, about 31%, while conv1, invisible on the parameter bar at 0.06%, grows to 15% because its 34,848 weights each fire 3,025 times. Each layer's exact count is listed below the bar.

  • conv134,848 (0.1%)
  • conv2307,200 (0.5%)
  • conv3884,736 (1.5%)
  • conv4663,552 (1.1%)
  • conv5442,368 (0.7%)
  • fc637,748,736 (61.9%)
  • fc716,777,216 (27.5%)
  • fc84,096,000 (6.7%)

What this means for making a model faster

The inversion sets the strategy for the rest of the course. Pruning or quantizing the linear layers shrinks Model size dramatically, because that is where the weights are, but it barely changes the MAC count and therefore barely changes computation time. To make inference faster you must attack the convolutions: fewer channels, grouped or depthwise filters as in MobileNet, or a lower input resolution so that h_o · w_o shrinks in every layer at once. The pruning lecture that follows will keep returning to this table, and when you profile a model for the research project, report both columns, not one.

Quick check

Pruning removes 90 percent of the weights in AlexNet's fc6 and fc7. Roughly how much does the network's total MAC count fall?

Recall

Which AlexNet layer family holds most of the parameters, which performs most of the MACs, and why?

The linear layers hold about 96% of the 61M parameters. The convolutions perform about 92% of the 724M MACs. Convolution MACs equal parameters times h_o · w_o, which is 3,025 for conv1 and 1 for every linear layer.

A MAC hides two arithmetic operations: a multiply and an add. When each is counted as one floating point operation, one MAC is two FLOPs, and AlexNet's 724,406,816 MACs become 1,448,813,632 FLOPs. The slide rounds that to 1.4G; the exact figure is 1.449G, and showing the factor of two matters more than the rounding.

FLOPs=2MACs\text{FLOPs} = 2 \cdot \text{MACs}
One multiply plus one add per MAC

The count on its own says nothing about time. To get time you need to know how fast a processor can drain it, and that is a different quantity with an almost identical name. FLOPS, with a capital S, is floating point operations per second: a throughput that belongs to the hardware. FLOPs, with a lowercase s, is a plural count that belongs to the model. TOP500 ranks supercomputers by exactly this rate, reporting Linpack results as Rmax and Rpeak in Flop/s, and NVIDIA's GPU performance background guide writes the time a math-limited kernel takes as its number of operations divided by the processor's math bandwidth, which is FLOPs over FLOPS.

FLOPS=FLOPssecondTcomputation=FLOPs of the modelFLOPS of the processor\text{FLOPS} = \frac{\text{FLOPs}}{\text{second}} \qquad T_{computation} = \frac{\text{FLOPs of the model}}{\text{FLOPS of the processor}}
A rate is a count per second; dividing a count by a rate gives a time
The hopper holds a count, the pipe drains at a rate, and the clock reads the quotient: 1.449 G FLOPs through 100 GFLOPS takes 14.5 ms.

This is the computation time term of the latency model on slide 8, where the numerator is a network specification and the denominator a hardware specification. Run AlexNet's count through a few devices and the scale of the answer changes by orders of magnitude while the model does not change at all.

ProcessorCount ÷ rateT_computation
1 GFLOPS1.449 × 10^9 / 10^91,449 ms
100 GFLOPS1.449 × 10^9 / 10^1114.5 ms
1 TFLOPS1.449 × 10^9 / 10^121.45 ms
67 TOPS (Orin Nano, INT8 sparse peak)1.449 × 10^9 / 6.7 × 10^130.022 ms
AlexNet's 1.449G FLOPs on different processors; the last row treats the count as OPs, as slide 28 allows for an INT8 model

OPs: the same count for any data type

The F in FLOP assumes floating point arithmetic. A quantized network, the kind you deploy on a microcontroller or an INT8 accelerator, stores weights and activations at an Bit width of 8 bits and multiplies integers. Those are not floating point operations, but they are still operations, and there are still two per MAC. The lecture therefore generalizes: an operation (OP) is one multiply or add of any data type, AlexNet is 724M × 2 = 1.4G OPs, and OPS is operations per second. The layer compute calculator in the second concept of this part uses OPS in its hardware box for exactly this reason: the formula for time does not care whether the operands were floats.

OPS=OPssecond\text{OPS} = \frac{\text{OPs}}{\text{second}}
The general form; FLOPS is the floating point special case
TermKindMeaningBelongs to
MACCountOne multiply accumulated into a sumA model, per inference
FLOPCountOne floating point multiply or add; a MAC is twoA model, per inference
OPCountOne operation of any data type; a MAC is twoA model, per inference
FLOPSRateFloating point operations per secondA processor
OPSRateOperations per second, any data typeA processor
Five terms, two kinds of quantity

Quick check

A model needs 3.6G FLOPs and a chip sustains 400 GFLOPS. What is T_computation?

Quick check

Why does the lecture generalize from FLOPs to OPs?

Quick check

A datasheet advertises a board at 67 TOPS. What kind of quantity is that?

Recall

State the rule that turns a MAC count into a FLOP count and a FLOP count into a time, then apply it: AlexNet on a 1 TFLOPS processor.

FLOPs = 2 × MACs, and T_computation = FLOPs / FLOPS. 2 × 724,406,816 = 1,448,813,632 FLOPs; 1.449 × 10^9 / 10^12 = 1.45 ms.

Recall

Why use OPs rather than FLOPs for an INT8 model, and how many OPs per MAC?

Its multiplies and adds act on integers, so they are not floating point operations. OPs counts operations of any data type. There are still two per MAC, one multiply and one add.

The reading list behind this lecture

Slide 29 lists the ten works the lecture draws on. Six were used directly in this lecture's counting and examples; the other four appear here as context for the architectures and normalization layers of lecture 02 and the pruning lectures ahead.

Used in this lecture

Context for other lectures

Recap

If you remember nothing else

  • A MAC is a <- a + b·c. A matrix-vector product costs m·n MACs and a matrix-matrix product m·n·k MACs.
  • Linear: c_o·c_i. Convolution: c_o·c_i·k_h·k_w·h_o·w_o. Grouped: divide by g. Depthwise: c_o·k_h·k_w·h_o·w_o, with no c_i.
  • Convolution MACs equal parameters times h_o·w_o. Linear MACs equal parameters.
  • AlexNet performs 724,406,816 MACs. Its convolutions hold 3.8 percent of the parameters but perform 92 percent of the MACs; the linear layers are the reverse.
  • One MAC is two FLOPs, so AlexNet is about 1.45G FLOPs, which the slide rounds to 1.4G.
  • FLOPs and OPs are counts that belong to a model. FLOPS and OPS are rates that belong to a processor. T_computation = OPs / OPS.
  • OPs generalizes FLOPs to quantized integer networks; the count per MAC stays two.
  • Conventions differ: many papers and tools report MACs under the label FLOPs. Check before comparing numbers.

Sources