COE 592Lecture 02Part 04
Pooling and what CNN filters learn
Parameter-free downsampling with max and average pooling, the feature hierarchy a CNN learns, and two interactive demos.
- Concepts
- 4
- Slides
- 21-26
- Reading
- 24 min
Why this part matters
Pooling is the cheapest layer you will ever deploy: zero parameters, four times fewer activations, and it is therefore the first tool for fitting a CNN into microcontroller SRAM. The feature hierarchy that follows it explains why pruning, quantization and transfer learning treat early and late layers differently.
The two skills this part drills are pure counting: the output shape of a pooling layer and the parameter count of a convolution layer. That same counting is the first step of every embedded model budget, because parameters set flash and activation shapes set SRAM. The two browser demos at the end give you the numbers layer by layer so you can check yourself.
By the end you can
- Compute the output shape of any pooling layer from W1, H1, C, F and S, and state why its parameter count is zero.
- Evaluate max and average pooling by hand on a small slice and explain the small translation invariance max pooling brings.
- Describe the edges, parts, objects feature hierarchy and tie it to receptive-field growth through CONV-RELU-POOL blocks.
- Count the parameters of a conv layer from its filter shape, including biases, as in the ConvNetJS first layer.
- Chain shapes through a real small network (CNN Explainer) and separate the layers that cost parameters from those that cost only activations.
A VGG-style block hands the next layer a volume of 224 x 224 x 64, which is 3,211,264 activations. A 2 x 2 pool with stride 2 returns 112 x 112 x 64, which is 802,816. Nothing was learned, nothing was mixed across channels, and every one of the 64 maps was simply shrunk on its own. That is the whole job of a Pooling layer.
The rule behind the example: a pooling layer applies a fixed summary over a small window of each activation map, one map at a time. Two summaries are common. Max pooling keeps the largest value in the window, and Average pooling keeps the mean. Because the summary is computed inside one Channel and never across channels, the depth of the volume is preserved while the spatial size falls. Pooling is therefore the second Downsampling tool of this lecture, next to Stride, and its output is a smaller Feature map per channel.
Slide 21 pinned as shapes
- Input
- 224 x 224 x 64
- Spatial extent F, stride S
- 2, 2
- Output
- 112 x 112 x 64
- Channels
- Unchanged, 64 in and 64 out
- Activations
- 3,211,264 to 802,816 (75% discarded)
- Learned parameters
- 0
Why max pooling is the default, and why that is a heuristic
Pooling of any kind brings an approximate translation invariance, and max pooling shows it most sharply, which is why slide 21 attaches "Introduces spatial invariance" to max pooling. Goodfellow, Bengio and Courville describe pooling in all its forms as making the representation "approximately invariant to small translations of the input": if the input shifts by a pixel, the values of most pooled outputs do not change, because the maximum is still inside its window. Their example is face detection, where the network need not know the location of the eyes with pixel-perfect accuracy, only that there is an eye on each side. They also point out that pooling regions spaced k pixels apart give the next layer roughly k times fewer inputs to process, which is the memory saving your microcontroller will feel.
| Max pooling | Average pooling | |
|---|---|---|
| What it returns | The largest value in the window | The mean of all values in the window |
| What it is sensitive to | One strong activation anywhere in the window | Every value equally, so a strong spike is diluted |
| Effect of a one-cell shift | Usually none, if the maximum stays inside the window | Small change, the average moves slightly |
| Gradient in the backward pass | Routed to the argmax cell only | Spread equally, 1/F² to every cell |
| Typical place in a network | Inside the trunk after a conv block | Global average pooling as the classifier head |
Slide 21 goes further and says max pooling "performs a lot better" because it discards noisy activations. Treat that as the slide's heuristic, not a law. Boureau, Ponce and LeCun analysed the two in 2010 and found that which one wins depends on how sparse the features are and how large the pool is; they note that earlier comparisons had been "purely empirical". CS231n states more cautiously that max pooling "has been shown to work better in practice". And the field has partly moved on: Springenberg et al. showed in 2014 that max pooling "can simply be replaced by a convolutional layer with increased stride without loss in accuracy", and Lin, Chen and Yan's Network in Network replaced the fully connected head with global average pooling, which they found "less prone to overfitting". ResNet and MobileNet families follow that pattern: strided convolutions inside, a single global average pool at the end.
Recall
A 224x224x64 volume passes through max pooling with F = 2 and S = 2. What are the output shape and the number of learned parameters?
Quick check
A 56x56x128 volume passes through max pooling with a 2x2 window and stride 2. What does it output?
Take the single depth slice from slide 22, a 4 x 4 grid, and pool it with a 2 x 2 window and Stride 2. The window lands in four places and never overlaps itself, so the four coloured quadrants of the slide are the four windows. Each quadrant becomes one output cell.
| Window | Values | Max | Mean |
|---|---|---|---|
| Top left (pink on the slide) | {1, 1, 5, 6} | 6 | 13 / 4 = 3.25 |
| Top right (green) | {2, 4, 7, 8} | 8 | 21 / 4 = 5.25 |
| Bottom left (yellow) | {3, 2, 1, 2} | 3 | 8 / 4 = 2 |
| Bottom right (blue) | {1, 0, 3, 4} | 4 | 8 / 4 = 2 |
Read the two results as grids. Max pooling gives [[6, 8], [3, 4]] and Average pooling gives [[3.25, 5.25], [2, 2]]. Notice what each one threw away. Max kept only the argmax cell of each window (the 6, the 8, the 3, the 4) and forgot the other three values entirely. Mean kept a trace of all four but flattened the 8 down to 5.25.
The general rule
Let the input be W1 x H1 x C. A Pooling layer needs exactly two hyperparameters, the spatial extent F of the window and the stride S, and it produces W2 x H2 x C.
The shape formula is the convolution formula from part 03 with p = 0 and the kernel size renamed to F. PyTorch writes the same rule in its general form, H_out = floor((H_in + 2p - d(F - 1) - 1)/S + 1), with the stride defaulting to the kernel size, so MaxPool2d(2) means F = 2, S = 2 (PyTorch docs). The floor matters when the division is not exact, and the second worked example shows why.
The zero comes from what pooling does in the backward pass. CS231n notes that a pooling layer "introduces zero parameters since it computes a fixed function of the input". Implementations keep the index of the maximum, the "switch", so the gradient is routed to exactly one cell per window in max pooling; in average pooling it is spread as 1/F² to each cell. Either way the layer has no Weight and no Bias, so it adds nothing to the Parameter count.
Worked example
224 to 112, the slide 21 numbers
Substitute into the width formula
W2 = (224 - 2)/2 + 1 = 111 + 1 = 112. The height is identical.Carry the depth across
C2 = C1 = 64, because the window only ever looks inside one channel.Count the activations
Before: 224 x 224 x 64 = 3,211,264. After: 112 x 112 x 64 = 802,816. Exactly one quarter survives; CS231n phrases it as "discards exactly 75% of the activations in an input volume".Result
Output 112 x 112 x 64, 0 parameters, 75% of runtime memory for that tensor gone.
Worked example
Why F = 3, S = 2 needs care
Overlapping pool on 224
(224 - 3)/2 + 1 = 111.5. Not an integer: the last window would hang off the edge. PyTorch floors to 111 by default and rounds up to 112 only with ceil_mode=True.The AlexNet case that does divide
AlexNet pools 55 x 55 maps with F = 3, S = 2: (55 - 3)/2 + 1 = 27, a clean integer, which is why that configuration is famous.Rule of thumb
Check that (W1 - F) divides by S. If it does not, state the floor explicitly.
Changing F and S on the same 4 x 4 slice shows how strongly the two hyperparameters shape the result. The values below are max pooling; the simulator lets you check the means.
| F, S | W2 | Output | Values | What happened |
|---|---|---|---|---|
| F = 2, S = 2 | (4 - 2)/2 + 1 = 2 | 2 x 2 | [[6, 8], [3, 4]] | Windows tile the input, 75% of activations dropped |
| F = 2, S = 1 | (4 - 2)/1 + 1 = 3 | 3 x 3 | [[6, 7, 8], [6, 7, 8], [3, 3, 4]] | Windows overlap, the row 6, 7, 8 appears twice |
| F = 3, S = 1 | (4 - 3)/1 + 1 = 2 | 2 x 2 | [[7, 8], [7, 8]] | Nine cells per window, the small values vanish |
| F = 3, S = 2 | (4 - 3)/2 + 1 = 1.5 | 1 x 1 (floored) | [[7]] | Not an integer, PyTorch floors and drops the last row and column |
- This window
- hover an output cell
- Input W1 × H1 × C
- 4 × 4 × 1
- Output W2 × H2 × C
- 2 × 2 × 1
- Learned parameters
- 0
- Activations in, out
- 16 to 4 (75% discarded)
Recall
Compute max and mean pooling with F = 2, S = 2 on [[1,1,2,4],[5,6,7,8],[3,2,1,0],[1,2,3,4]].
Quick check
Why does a pooling layer add nothing to a network's parameter count?
The grid on slide 23 comes from Lee, Grosse, Ranganath and Ng (ICML 2009), who learned a first layer of edge detectors from natural images once, then trained the second and third layers of a convolutional deep belief network separately on unlabeled Caltech-101 images of faces, cars, elephants and chairs, and visualized what each layer responds to. Their own summary: the first, second and third layers "learn edge detectors, object parts, and objects respectively". Look at the bottom row of the slide. It is the same across all four columns because that first layer was learned once from natural images: small oriented edges like Gabor patches. The middle row diverges into eyes and noses, wheels and bumpers, tusks and ears, chair legs and backs. The top row shows entire faces, cars, elephants and chairs.
This ladder is the Feature hierarchy, and it is not designed by hand. Every Convolution layer runs the same operation with a small Kernel (filter). What changes with depth is the Receptive field: a first-layer unit sees only its k x k patch of pixels, so the most it can detect is an edge. A second-layer unit sees a k x k patch of first-layer responses, which covers a larger region of the image (L(k - 1) + 1 pixels after L stride-1 layers, faster with stride or pooling), so it can combine edges into a curve or an eye. Deep units cover most of the image and can match a whole face. Zeiler and Fergus confirmed in 2013 that the same ladder appears inside a supervised ImageNet CNN, using a deconvolutional visualization of intermediate layers.
| Tier | Layers | What the filters respond to | Receptive field, roughly |
|---|---|---|---|
| Low level | First convolution layers | Oriented edges, bars, blobs, colour opponents | 3 x 3 to 11 x 11 pixels (the first kernel size) |
| Mid level | Middle layers | Curves, corners, eyes, wheels, tusks, chair legs | tens of pixels |
| High level | Deepest layers | Whole faces, cars, elephants, chairs | most of the image |
The mechanism in action: slide 24
Slide 24 shows a network of the pattern [CONV, RELU, CONV, RELU, POOL] repeated three times and then a fully connected layer, run on a photo of a car. Each column is the activation maps of one layer. Read them left to right and the hierarchy appears live: the first columns look like edge-filtered copies of the car, the middle columns are sparse and blotchy, and the last columns are tiny grids that no longer resemble the photo at all.
Two convs with ReLU, then pool: edges and colour blobs.
Same pattern on the smaller maps: corners, wheels, parts.
Coarse maps whose units see most of the image.
car, truck, airplane, ship, horse; car wins.
The ReLU after each conv keeps only positive responses, which is why the columns after it are darker. Each POOL halves the Feature map and, because the next block's k x k window now covers twice as many original pixels, pushes the receptive field outward. Two pools have already halved the maps twice, so the third block works on maps one quarter the width of the input, and the third pool leaves the fully connected layer maps one eighth the width; that is why the last units can see a whole car. The Fully connected layer at the end reads every unit of the final maps at once and produces one score per class. On the slide, car scores highest, well above truck, then airplane, ship and horse.
Why this matters on an embedded device
The hierarchy explains a pattern you will meet throughout this course. Early layers have few parameters (a 5 x 5 x 3 filter is 75 weights) but large activation maps; late layers have many parameters but tiny maps. So SRAM pressure comes from the front of the network and flash pressure from the back, and pruning or quantizing them calls for different budgets. Transfer learning on the edge uses the hierarchy directly: the edge and part detectors are generic, so you freeze the low tiers and retrain only the top.
Recall
Name the three tiers of the feature hierarchy with one example each, and say what property of deep layers makes the top tier possible.
Quick check
In the feature hierarchy, what do the deepest convolution layers respond to?
Open the ConvNetJS CIFAR-10 demo and read its first conv block. It prints "conv (32x32x16), filter size 5x5x3, stride 1, parameters: 16x5x5x3+16 = 1216". That one line is a complete exam answer, and it is worth rebuilding by hand.
Worked example
The ConvNetJS first conv layer
Weights
16 filters, each 5 x 5 and 3 deep to match the RGB input: 16 x 5 x 5 x 3 = 1200 weights.Biases
One Bias per filter, so 16.Why the map stays 32 x 32
The demo's layer definition uses pad 2: (32 + 2·2 - 5)/1 + 1 = 32. With Padding equal to (F - 1)/2, a stride-1 conv keeps its size.Result
1200 + 16 = 1216 parameters, output 32 x 32 x 16, which is 16,384 activations for one image.
The ConvNetJS CIFAR-10 demo
- Dataset
- CIFAR-10: 60,000 colour images of 32 x 32, 10 classes, 50,000 train and 10,000 test (Krizhevsky)
- Classes
- airplane, automobile, bird, cat, deer, dog, frog, horse, ship, truck
- Accuracy quoted on the page
- state of the art "about 90%", humans "about 94%" (2014 figures; current models exceed 99%)
- Augmentation
- random flips and random shifts of up to 2 px
- Optimizer
- Adadelta, batch size 4, L2 decay 0.0001
The whole demo network is small enough to count in full. Two things to watch: every conv filter is as deep as the channels feeding it, and the three pooling layers contribute nothing to the total while cutting the activations by four each time.
| Layer | Output | Parameters | Note |
|---|---|---|---|
| input | 32 x 32 x 3 | 0 | Raw CIFAR-10 image |
| conv, 16 filters 5x5x3, pad 2 | 32 x 32 x 16 | 16 x 5 x 5 x 3 + 16 = 1216 | The count printed on slide 25 |
| max pool 2x2, stride 2 | 16 x 16 x 16 | 0 | Activations cut by 4x |
| conv, 20 filters 5x5x16, pad 2 | 16 x 16 x 20 | 20 x 5 x 5 x 16 + 20 = 8020 | Depth of the filter equals the input channels |
| max pool 2x2, stride 2 | 8 x 8 x 20 | 0 | |
| conv, 20 filters 5x5x20, pad 2 | 8 x 8 x 20 | 20 x 5 x 5 x 20 + 20 = 10020 | |
| max pool 2x2, stride 2 | 4 x 4 x 20 | 0 | |
| softmax, 10 classes | 10 | 320 x 10 + 10 = 3210 | The only layer whose count depends on image size |
| Total | 22,466 | Three pools contribute nothing |
The total is 22,466 parameters. The softmax layer is the only one whose count depends on the image size, because it reads the flattened 4 x 4 x 20 = 320 activations; every conv layer's count depends only on its filter shape, which is Weight sharing at work.
CNN Explainer as retrieval practice
CNN Explainer (Wang et al., IEEE VIS 2020) runs a network the authors call Tiny VGG on ten classes: lifeboat, ladybug, pizza, bell pepper, school bus, koala, espresso, red panda, orange and sport car. Its training code uses 3 x 3 convolutions with 10 filters and no padding ("valid"), and 2 x 2 max pools with stride 2. The input is 64 x 64 x 3. Before you look at the table, chain the shapes yourself: a valid conv subtracts 2, a pool halves.
Recall
Chain the CNN Explainer shapes from 64x64x3 to the second pool.
| Layer | Shape formula | Output | Parameters |
|---|---|---|---|
| input | 64 x 64 x 3 | 0 | |
| conv_1_1, 10 filters 3x3, valid | 64 - 3 + 1 | 62 x 62 x 10 | 10 x 3 x 3 x 3 + 10 = 280 |
| conv_1_2, 10 filters 3x3, valid | 62 - 3 + 1 | 60 x 60 x 10 | 10 x 3 x 3 x 10 + 10 = 910 |
| max_pool_1, 2x2, stride 2 | (60 - 2)/2 + 1 | 30 x 30 x 10 | 0 |
| conv_2_1, 10 filters 3x3, valid | 30 - 3 + 1 | 28 x 28 x 10 | 910 |
| conv_2_2, 10 filters 3x3, valid | 28 - 3 + 1 | 26 x 26 x 10 | 910 |
| max_pool_2, 2x2, stride 2 | (26 - 2)/2 + 1 | 13 x 13 x 10 | 0 |
| flatten, dense 10, softmax | 13 x 13 x 10 = 1690 | 10 | 1690 x 10 + 10 = 16,910 |
| Total | 19,920 |
The pattern repeats: 19,920 parameters, of which the two pools contribute 0 while each removes three quarters of the activations. The dense layer holds 16,910 of the total because it multiplies the image-dependent 1690 by the ten classes. Click any activation map in the live page and it animates the window that produced it, which is the pooling and convolution arithmetic of this lecture rendered one cell at a time.
Recall
How many parameters does the ConvNetJS first conv layer hold, and why does the map stay 32x32?
Quick check
In the ConvNetJS CIFAR-10 demo the first conv layer has 16 filters of 5x5x3. How many parameters does it hold?
Quick check
In CNN Explainer, conv_1_2 outputs 60x60x10. What does max_pool_1 with a 2x2 window and stride 2 output?
Recap
If you remember nothing else
- Pooling summarizes a window in each activation map independently: spatial size drops, channel count stays, 224x224x64 becomes 112x112x64.
- W2 = (W1 - F)/S + 1, H2 = (H1 - F)/S + 1, depth C unchanged, parameters 0.
- On the slide's 4x4 slice, F = 2 and S = 2 give max [[6,8],[3,4]] and mean [[3.25,5.25],[2,2]].
- Max pooling adds approximate invariance to small shifts; 'max is always better' is a heuristic, and many modern networks use strided convolutions or global average pooling instead.
- Filters form a hierarchy: edges in early layers, object parts in the middle, whole objects deep, because receptive fields grow with depth and pooling.
- CONV-RELU-CONV-RELU-POOL repeated three times then FC turns an image into class scores; car beats truck, airplane, ship, horse.
- ConvNetJS first layer: 16 x 5 x 5 x 3 + 16 = 1216 parameters; CNN Explainer shapes: 64, 62, 60, 30, 28, 26, 13.
Sources
- CS231n Convolutional Neural Networks for Visual Recognition, Pooling LayerDocsStanford UniversityPooling formulas, zero parameters, 75% discard, the argmax switch, and getting rid of pooling.(opens in a new tab)
- Deep Learning, chapter 9.3 PoolingBookGoodfellow, Bengio and Courville, MIT PressApproximate translation invariance and k times fewer inputs for the next layer, pp. 335 to 337.(opens in a new tab)
- Convolutional Deep Belief Networks for Scalable Unsupervised Learning of Hierarchical RepresentationsPaperLee, Grosse, Ranganath and Ng, ICML 2009Source of the faces, cars, elephants, chairs figure on slide 23: edges, object parts, objects.(opens in a new tab)
- Visualizing and Understanding Convolutional NetworksPaperZeiler and Fergus, 2013Deconvolutional visualization showing the same hierarchy in a supervised ImageNet CNN.(opens in a new tab)
- Striving for Simplicity: The All Convolutional NetPaperSpringenberg, Dosovitskiy, Brox and Riedmiller, 2014Max pooling replaced by strided convolution with no loss in accuracy.(opens in a new tab)
- Network In NetworkPaperLin, Chen and Yan, 2013Global average pooling as a classifier head, less prone to overfitting than fully connected layers.(opens in a new tab)
- A Theoretical Analysis of Feature Pooling in Visual RecognitionPaperBoureau, Ponce and LeCun, ICML 2010When max beats average depends on feature sparsity and pool size.(opens in a new tab)
- torch.nn.MaxPool2dDocsPyTorch documentationFloor formula, stride defaulting to kernel size, ceil_mode, and C unchanged from input to output.(opens in a new tab)
- ConvNetJS CIFAR-10 demoDocsAndrej Karpathy, StanfordAbout 90% state of the art, 94% human, 2 px shifts, Adadelta; layer parameters printed live.(opens in a new tab)
- ConvNetJS CIFAR-10 demo sourceDocsGitHub, karpathy/convnetjslayer_defs with pad 2 and 16, 20, 20 filters; trainer with batch size 4 and L2 decay 0.0001.(opens in a new tab)
- The CIFAR-10 datasetDocsAlex Krizhevsky, University of Toronto60,000 colour 32x32 images in 10 classes, 50,000 train and 10,000 test.(opens in a new tab)
- CNN ExplainerDocsPolo Club of Data Science, Georgia TechInteractive Tiny VGG with layer shapes 64, 62, 60, 30, 28, 26, 13.(opens in a new tab)
- Tiny VGG training scriptDocsGitHub, poloclub/cnn-explainer3x3 valid convolutions with 10 filters, 2x2 max pools, dense 10 with softmax.(opens in a new tab)
- CNN Explainer: Learning Convolutional Neural Networks with Interactive VisualizationPaperWang et al., IEEE TVCG (IEEE VIS 2020)The paper behind the demo on slide 26.(opens in a new tab)
- MIT 6.5940 TinyML and Efficient Deep Learning Computing, Lecture 2DocsSong Han, MITThe course whose Basics of Deep Learning lecture these slides follow.(opens in a new tab)