Reduce dimensionality and extract dominant features using pooling operations.
Pooling Parameters
Info
Pooling reduces the spatial size of the representation.
Max Pooling (2x2, stride 2) reduces data by 75%.
Overview
What pooling does
A pooling layer slides a window over the feature map and replaces the vals inside it with a single summary. With a 2×2 window and stride 2 — by far the most common setting — the windows do not overlap. And the output is half the height and half the width. So a quarter of the vals.
Max pooling keeps the largest value in the window. Since a feature map records how strongly a filter responded at each position, the max says “this feature was detected somewhere in this neighbourhood”. It is often the useful part.Average pooling takes the mean, preserving total intensity rather than peak response. It is smoother and less common in hidden layers. But global average pooling — averaging each channel down to a single count — is now standard at the end of a network, replacing the large fully connected layer that used to sit there.
Pooling has no params. It is a fixed step, so it adds nothing to the net size and nothing to train.
This page checks max pooling, average pooling. And strided convolutions side by side, shows how they affect the receptive field of later layers. And covers global average pooling — the replacement for fully connected layers that VGG-16 made obvious was needed. The visualisation above lets you switch between ways and watch the output change on real feature maps. By the end you will know when to pool, when to stride. And why modern designs tend to prefer the latter.
Reduce dimensionality and extract dominant features using pooling operations.
Pooling shrinks a feature map by summarising each small neighbourhood into one value. It cuts computation, widens what later layers can see, and buys a small amount of tolerance to things moving.
What pooling does
A pooling layer slides a window over the feature map and replaces the vals inside it with a single summary. With a 2×2 window and stride 2 — by far the most common setting — the windows do not overlap. And the output is half the height and half the width. So a quarter of the vals.
Max pooling keeps the largest value in the window. Since a feature map records how strongly a filter responded at each position, the max says “this feature was detected somewhere in this neighbourhood”. It is often the useful part.Average pooling takes the mean, preserving total intensity rather than peak response. It is smoother and less common in hidden layers. But global average pooling — averaging each channel down to a single count — is now standard at the end of a network, replacing the large fully connected layer that used to sit there.
Pooling has no params. It is a fixed step, so it adds nothing to the net size and nothing to train.
This page checks max pooling, average pooling. And strided convolutions side by side, shows how they affect the receptive field of later layers. And covers global average pooling — the replacement for fully connected layers that VGG-16 made obvious was needed. The visualisation above lets you switch between ways and watch the output change on real feature maps. By the end you will know when to pool, when to stride. And why modern designs tend to prefer the latter.
The three reasons it is there
Computation. Quartering the spatial dimensions quarters the work of each later layer. In a deep network that compounds enormously.Receptive field. This is the one people miss. After pooling, each position in the less map summarises a more region of the first pic. So a 3×3 filter applied afterwards covers twice the input area it would have before. Stacking convolution and pooling is what lets a network built from small filters eventually see the whole pic — without it, a network of 3×3 filters would need to be impractically deep.Translation invariance. If a feature shifts by one pixel within a pooling window, the max is unchanged. This is a genuine but modest gain — it tolerates small shifts, not large ones. And it is often overstated.
Making the map less on purpose
A network that kept each layer at 224×224 would be enormously costly and would never see more than a few pixels at a time. Downsampling — deliberately reducing the spatial size of feature maps — is what makes deep vision networks affordable and gives them a wide enough view to recognise whole objects.
The three mechanisms:
Method
How
Parameters
Max pooling
Take the largest value in each window
None
Average pooling
Take the mean of each window
None
Strided convolution
Skip positions while convolving
Learned
A 2×2 max pool with stride 2 on a 4×4 map:
6 8 3 1 max of each 2x2 block
2 4 9 5 -> [8 9]
1 0 7 2 [3 7]
3 2 4 6
Sixteen counts turn four. The map is a quarter of the size. And each later layer costs a quarter as much.
Three things it buys
Computation. The saving compounds through the network. Halving both dimensions once quarters the cost of all after it.
Receptive field. After downsampling, each filter position covers twice as much of the first pic. Without it, a 3×3 filter stacked twenty times would still just see a 41×41 region — not enough to recognise an object in a 224×224 photograph.
A little translation invariance. Max pooling reports the strongest response in a window no matter just where in the window it occurred. So a small shift often gives the same output. The effect is real but modest. And it is not a substitute for augmentation.
The cost is precision. Downsampling discards spatial detail permanently. It is fine for "is this a cat?" and a serious problem for "which pixels are the cat?"
Max or average?
Max pooling keeps the strongest evidence and discards the rest. It suits feature detection, where the question is "was this pattern present anywhere in the window". And it gives sparse, high-contrast maps. It has been the default in classification networks for a decade.
Average pooling keeps a smoothed summary. It suits cases where total level matters more than peak response. And it is the standard choice at the very end of a network.
Global average pooling deserves split mention. It reduces each feature map to a single count — a 7×7×512 tensor turns 512 vals — and feeds those straight to the classifier.
That single design change removed most of the params from pic classifiers. VGG's flatten-and-dense head held about 100 million weights. Global average pooling replaces it with none. And it makes the network accept any input size, since the output no longer depends on the spatial dimensions. Each modern design uses it.
The trend towards strided convolutions
Modern designs increasingly downsample with stride-2 convolutions instead of pooling layers, on the grounds that how to reduce resolution is a decision worth learning rather than fixing.
ResNet uses stride-2 convolutions in its blocks. Many detection and segmentation backbones do the same. Pooling has not disappeared — ResNet still starts with a max pool and ends with a global average pool — but it is no longer the main downsampling mechanism.
A tied refinement addresses aliasing. Downsampling without smoothing first violates the sampling theorem and makes networks sensitive to one-pixel shifts. Adding a small blur before the stride ("anti-aliased downsampling") measurably improves shift-consistency and accuracy, at a small cost.
Interactive Exploration Guide
Halve the map. Draw a pattern, set Window Size to 2×2 and Stride to 2, then press Animate Pooling. The output is half the width and height. And the windows tile without overlapping.
Check max with average. Switch Step Type between them on the same drawing. Max keeps sharp peaks and discards all else. Average blurs, preserving total intensity.
Test the invariance claim. Draw a small mark, pool it, then Clear and redraw it shifted by one cell within the same window. The max-pooled output is identical. Shift it into the next window and the output changes — the invariance is strictly local.
Overlap the windows. Set Stride to 1 with a 2×2 window. The output barely shrinks, since overlapping windows downsample far less.
Why some designs drop it
Pooling is a fixed rule. And a strided convolution reaches the same downsampling while learning how to summarise. Many modern designs use stride-2 convolutions instead. And all-convolutional networks remove pooling fully.
It is also destructive in a way that matters for some tasks. Max pooling discards the position of the max within the window. It is fine for classification and harmful for segmentation. There the output must be pixel-exact. U-Net’s skip connections exist largely to restore the spatial detail pooling threw away.
What often goes wrong
Pooling too aggressively. A few 2×2 pools in quick succession reduce a 224×224 pic to a handful of pixels, destroying the spatial information later layers need.
Expecting real translation invariance. It handles a shift of a pixel or two. More shifts need data augmentation.
With max pooling for segmentation without skip connections. The precise locations are gone and cannot be recovered from the pooled map alone.
Forgetting it has no params. A pooling layer cannot learn or adapt. If you want a learned reduction, use a strided convolution.
Odd input sizes. A 2×2 pool on a 7×7 map leaves a remainder. And other frameworks handle the edge differently. Check whether yours floors or pads.
What to remember
Pooling summarises each neighbourhood into one value, most often taking the max of a 2×2 window at stride 2. It quarters the feature map for free — it has no params. Its real value is enlarging the receptive field so small filters can eventually see large structures, with computational saving second and a modest, purely local translation tolerance third. Strided convolutions do the same job with learned weights. It is why newer designs often skip it.
Recovering resolution when you need it
Classification can afford to throw resolution away. Segmentation and detection cannot — they must give answers at. Or near, the first pixel grid.
Three ways, all in current use:
Encoder-decoder with skip connections. U-Net downsamples through an encoder, then upsamples through a decoder, concatenating each decoder stage with the matching encoder feature map. The deep path supplies semantics ("this is a road"). The skip connections supply the fine edges that downsampling destroyed. This pairing is the reason U-Net works so well on small datasets.
Dilated convolutions. Widen the receptive field by spacing out the filter taps instead of shrinking the map. Resolution is preserved throughout, at more memory cost. DeepLab is built on this.
Feature pyramids. Keep feature maps at a few resolutions and make predictions from all of them. So small objects are detected in the high-resolution maps and large ones in the low-resolution maps. Standard in modern object detectors.
Choosing how much to downsample
The total reduction from input to final feature map is the network's output stride. A typical classifier has an output stride of 32: 224×224 turns 7×7.
Task
Typical output stride
Why
Classification
32
Only the label matters
Object detection
8–32, several scales
Boxes need moderate precision
Semantic segmentation
8–16
Boundaries need fine precision
Super-resolution
1, or upsampling
Output is a full-size image
Reducing the output stride from 32 to 8 makes the last stages sixteen times more costly in area. It is why segmentation networks are slower than classifiers on the same backbone.
Common mistakes
Downsampling too aggressively on small pics. A 32×32 CIFAR pic cannot survive five stride-2 stages. It would be down to 1×1 before the network has done anything.
Expecting pooling to give real invariance. It tolerates shifts of a pixel or two, not rotation, scale. Or a shifted object. Augmentation is what handles those.
With max pooling right at the end. Global average pooling is almost always the better final layer.
Flattening a large feature map into a dense layer. That is where the param explosion lives. Global average pooling removes it.
Downsampling in a segmentation network without skip connections. The edges will be soft and the output blocky.
Four ways to halve a feature map
Max pooling, average pooling, strided convolution and blur-then-subsample, applied to the same input. Each keeps something other, and the gaps are visible in the counts.
example_01.pyNumPy
import numpy as np
img = np.array([
[10, 12, 90, 11, 13, 14, 12, 10],
[11, 13, 95, 12, 14, 13, 11, 12],
[12, 11, 92, 13, 12, 15, 13, 11],
[10, 12, 88, 11, 13, 14, 12, 10],
[80, 82, 85, 83, 12, 13, 11, 12],
[81, 83, 86, 84, 13, 12, 12, 11],
[12, 11, 13, 12, 11, 13, 12, 10],
[11, 13, 12, 11, 12, 11, 13, 12],
], float)
SHADE = " .:-=+*#%@"
def show(a, label):
lo, hi = a.min(), a.max()
print(" %s (%dx%d, %.0f to %.0f)" % (label, a.shape[0], a.shape[1], lo, hi))
for row in a:
print(" " + "".join(SHADE[int(np.clip((v-lo)/max(hi-lo,1e-9),0,1)*9)] for v in row))
show(img, "input -- bright vertical and horizontal bars on dark")
print()
def pool(a, mode, k=2):
h, w = a.shape[0]//k, a.shape[1]//k
out = np.zeros((h, w))
for i in range(h):
for j in range(w):
win = a[i*k:(i+1)*k, j*k:(j+1)*k]
out[i, j] = win.max() if mode == "max" else win.mean()
return out
mp, ap = pool(img, "max"), pool(img, "avg")
for name, out in [("max pool 2x2", mp), ("avg pool 2x2", ap)]:
show(out, name); print()
print("WHAT EACH ONE KEPT (brightest = %.0f):" % img.max())
print("%20s %10s %10s %10s" % ("method", "max kept", "mean", "std"))
for name, out in [("input", img), ("max pool", mp), ("avg pool", ap)]:
print("%20s %10.1f %10.2f %10.2f" % (name, out.max(), out.mean(), out.std()))
Output
Strided convolution and blur-then-subsample are two learnable or anti-aliased options.
example_02.pyNumPy
import numpy as np
def strided_conv(a, k=2):
kern = np.full((2,2), 0.25)
h, w = a.shape[0]//k, a.shape[1]//k
out = np.zeros((h, w))
for i in range(h):
for j in range(w):
out[i, j] = (a[i*k:i*k+2, j*k:j*k+2] * kern).sum()
return out
print("STRIDED CONV applies a learned 2x2 kernel at every other position.")
print(" strided conv 2x2 has %s parameters (for 64->64 channels)" % "{:,}".format(2*2*64*64))
print(" max/avg pool have 0 -- they are fixed rules.")
print()
def blur_subsample(a, k=2):
g = np.array([[1,2,1],[2,4,2],[1,2,1]], float); g /= g.sum()
p = np.pad(a, 1, mode="edge")
bl = np.zeros_like(a)
for i in range(a.shape[0]):
for j in range(a.shape[1]):
bl[i, j] = (p[i:i+3, j:j+3] * g).sum()
return bl[::k, ::k]
stripes = np.zeros((8, 8)); stripes[:, ::2] = 100.0
print("ALIASING: a fine stripe pattern sampled two ways:")
print(" input stripe columns : %s" % np.unique(stripes[0]))
print(" naive subsample [::2] : %s" % np.unique(stripes[::2, ::2]))
print(" blur then subsample : %s" % np.round(np.unique(blur_subsample(stripes)), 1))
print(" naive subsampling kills the texture. blurring first preserves")
print(" evidence of it -- anti-aliased CNNs blur before every stride.")
Output
The gradient behaviour is what decides which way trains well.
example_03.pyNumPy
import numpy as np
img = np.array([
[10, 12, 90, 11],
[11, 13, 95, 12],
[80, 82, 85, 83],
[81, 83, 86, 84],
], float)
print("THE GRADIENT determines which method trains well:")
print(" max pool -- gradient goes to the ONE winning pixel per window.")
print(" the other three receive exactly zero.")
print(" avg pool -- gradient is split evenly, every pixel gets a quarter.")
print()
win = img[0:2, 0:2]
print(" for the top-left 2x2 window %s:" % win.ravel())
gmax = np.zeros(4); gmax[win.ravel().argmax()] = 1.0
print(" max pool gradient : %s" % gmax)
print(" avg pool gradient : %s" % np.full(4, 0.25))
print(" a pixel that never wins a max-pool window never learns from it.")
print()
print(" MAX POOL preserves contrast and peak values exactly.")
print(" AVERAGE POOL dilutes isolated features: a lone bright pixel")
lone = np.zeros((2, 2)); lone[0, 0] = 100.0
print(" in a 2x2 window: max pool keeps %.0f, average returns %.0f."
% (lone.max(), lone.mean()))
Output
Questions people ask
Is pooling obsolete? No — global average pooling is universal. And max pooling is still common early in a network. What has changed is that mid-network downsampling is now often strided convolution.
Does pooling have params? No, which is part of its appeal: it reduces size at almost no cost and cannot overfit.
What window size should I use? 2×2 with stride 2 is standard and halves each dimension. 3×3 with stride 2 gives overlapping windows and is used in some designs.
Can I avoid downsampling fully? Yes, with dilated convolutions, at considerably more memory and compute cost.
Why is my segmentation output blocky? Since the output stride is too large and the decoder has too little high-resolution information. Add skip connections or reduce the stride.
Does downsampling cause information loss? Yes, permanently. That is the trade: cheaper computation and a wider view, in exchange for spatial detail.
Recap in one screen
Downsampling shrinks feature maps to cut cost and widen the receptive field.
Max pooling keeps the strongest response. Average pooling smooths; strided convolution learns what to keep.
Global average pooling replaced the huge dense head and removed most of a classifier's params.
Spatial detail is lost permanently — segmentation recovers it with skip connections or avoids losing it with dilation.
Total reduction is the output stride: 32 for classification, 8–16 for dense prediction.
Recall check
0 of 4
Say the answer out loud before you reveal it — recalling it is what makes it stick, and rereading it is not.
What is meant by “Downsampling too aggressively on small pics” here?
What is meant by “Expecting pooling to give real invariance” here?
What is meant by “With max pooling right at the end” here?
What is meant by “Flattening a large feature map into a dense layer” here?
Cheat sheet
Pooling Layer
Shrink a feature map with max, average or min pooling and see how downsampling keeps the signal but discards the detail.
Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.