COE 592Lecture 03Part 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.
- Concepts
- 4
- Slides
- 18-22
- Reading
- 24 min
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
- 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.
- 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.
- 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.
- State the assumptions behind the peak approximation: layer-by-layer execution, no branches, no in-place operations, no scratch buffers.
- 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.
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.
| Model | Param memory (flash) | Peak activation (SRAM) | Fits STM32F746 (1 MB flash, 320 kB SRAM)? | Fits STM32H743 (2 MB flash, 512 kB SRAM)? |
|---|---|---|---|---|
| ResNet-18 | 11.2 MB | 0.9 MB | No (flash and SRAM) | No (flash and SRAM) |
| MobileNetV2-0.75 | 2.5 MB | 1.7 MB | No (flash and SRAM) | No (flash and SRAM) |
| MCUNet (paper, Figure 8) | 1.9 MB | 0.49 MB | No (flash and SRAM) | Yes |
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).
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?
Recall
Where do weights and activations live on a microcontroller at run time, and which one sets the 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).
| Model | Parameters (MB) | Activations (MB) | Activations ÷ parameters |
|---|---|---|---|
| ResNet-50 | 102 | 707 | about 7x |
| MobileNetV2-1.4 | about 24 | about 626 | about 26x |
| Reduction | 4.3x | 1.1x |
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.
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.
| Mode | Which activations are held | How many | Memory rule |
|---|---|---|---|
| Inference | Input and output of the layer running now | Two tensors | Largest input + output pair |
| Training | Every layer input a_i until its dL/dW_i is computed | All tensors, times the batch | Sum of all activations × batch size |
Worked example
AlexNet in fp32, inference against training
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.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.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.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.
Recall
Why does training need every activation while inference needs only two?
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.
| Layers | Activation memory | Weight memory | Dominant |
|---|---|---|---|
| 0 to 5 | 50 to 75 kB | about 0 | Activation |
| 6 to 17 | 20 to 55 kB | about 0 | Activation |
| 18 to 30 | under 15 kB | under 15 kB | Neither |
| 32 to 42 | 5 to 10 kB | 35 to 75 kB | Weight |
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.
| Layer | Output C×H×W | Activations | Weights | Which dominates |
|---|---|---|---|---|
| conv1 | 96×55×55 | 290,400 | 34,848 | Activations, 8x |
| conv2 | 256×27×27 | 186,624 | 307,200 | Weights, 1.6x |
| conv3 | 384×13×13 | 64,896 | 884,736 | Weights, 14x |
| conv4 | 384×13×13 | 64,896 | 663,552 | Weights, 10x |
| conv5 | 256×13×13 | 43,264 | 442,368 | Weights, 10x |
| fc6 | 4096 | 4,096 | 37,748,736 | Weights, 9,216x |
| fc7 | 4096 | 4,096 | 16,777,216 | Weights, 4,096x |
| fc8 | 1000 | 1,000 | 4,096,000 | Weights, 4,096x |
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?
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).
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.
| Layer executing | Input | Output | Live | At 8-bit |
|---|---|---|---|---|
| 150,528 | 290,400 | 440,928 | 440.9 kB | |
| 290,400 | 69,984 | 360,384 | 360.4 kB | |
| 69,984 | 186,624 | 256,608 | 256.6 kB | |
| 186,624 | 43,264 | 229,888 | 229.9 kB | |
| 43,264 | 64,896 | 108,160 | 108.2 kB | |
| 64,896 | 64,896 | 129,792 | 129.8 kB | |
| 64,896 | 43,264 | 108,160 | 108.2 kB | |
| 43,264 | 9,216 | 52,480 | 52.5 kB | |
| 9,216 | 4,096 | 13,312 | 13.3 kB | |
| 4,096 | 4,096 | 8,192 | 8.2 kB | |
| 4,096 | 1,000 | 5,096 | 5.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
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.Sum for the total
932,264 values, matching the slide. This is the number that training would have to hold.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
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.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)
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?
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?
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
- MCUNet: Tiny Deep Learning on IoT DevicesPaperNeurIPS 2020, Lin, Chen, Lin, Cohn, Gan and Han4.6x and 1.8x, SRAM versus flash roles, MCU list with STM32F746 at 320 kB, 5.3x in Table 1, in-place depthwise convolution, 2.2x block imbalance on a 0.3x-width MobileNetV2 (Figure 11).(opens in a new tab)
- MCUNetV2: Memory-Efficient Patch-based Inference for Tiny Deep LearningPaperNeurIPS 2021, Lin, Chen, Cai, Gan and HanPeak = input + output rule, imbalanced MobileNetV2 profile with 1372 kB peak, 539 kB first-conv example, resolution versus channel growth. True source of the right chart on slide 18.(opens in a new tab)
- TinyTL: Reduce Activations, Not Trainable Parameters for Efficient On-Device LearningPaperNeurIPS 2020, Cai, Gan, Zhu and Han102 MB versus 707 MB, 4.3x versus 1.1x (the slide halves the paper's batch 16 values, so it shows batch 8), equation 2 for backpropagation memory, bias-only updates, DRAM access two orders of magnitude costlier than SRAM.(opens in a new tab)
- On-Device Training Under 256KB MemoryPaperNeurIPS 2022, Lin, Zhu, Wang, Cai, Gan and HanFigure 11(a): activation and weight memory of updating each layer of MCUNet. True source of slide 20.(opens in a new tab)
- ImageNet Classification with Deep Convolutional Neural NetworksPaperNeurIPS 2012, Krizhevsky, Sutskever and HintonAlexNet architecture: five convolutions, max pooling, three fully connected layers, about 60M parameters.(opens in a new tab)
- Deep Learning, chapter 6: Deep Feedforward NetworksBookMIT Press, Goodfellow, Bengio and Courville, 2016Section 6.5.7: hidden-layer inputs are stored until the backward pass returns, at cost O(m n_h) per layer.(opens in a new tab)
- MIT 6.5940 TinyML and Efficient Deep Learning Computing, Fall 2023DocsMIT HAN LabLecture 02 slides 70 to 75 are the origin of slides 18 to 22. The 14, 16, 16, 17 axis typo is already in Figure 1 of the MCUNetV2 paper and was carried into this deck and the slide.(opens in a new tab)
- Get started with LiteRT for MicrocontrollersDocsGoogle for DevelopersThe tensor arena preallocates RAM for input, output and intermediate arrays; the model ships as a byte array.(opens in a new tab)
- STM32F746NG product pageDocsSTMicroelectronicsCortex-M7 up to 216 MHz, 1 MB flash, 320 KB SRAM; the same figures appear in MCUNet's table 1.(opens in a new tab)