Global Average Pooling against Flatten

How a feature map becomes a vector, and why one of the two ways costs fifty times more weights than the other.

Overview

Two ways to collapse a block

Convolutional layers output a 3D block: height × width × channels. A classifier needs a single vector. Something has to turn one into the other, and there are two candidates.

Flatten reads every value in the block into one long vector. For a 7×7×512 map that is 25,088 numbers, and the dense layer that follows needs a weight for each of them per class.

Global average pooling takes the mean of each channel over its whole spatial extent. Every 7×7 slice becomes one number, and the block becomes 512 numbers.

Global Average Pooling against Flatten

Worth knowing

The convolutional part of a network outputs a 3D block. A classifier needs a vector, so something has to collapse it.
Flatten reads every value in order. A 7×7×512 map becomes 25,088 numbers.
Global average pooling takes the mean of each channel. The same map becomes 512 numbers.
Pooling also removes the fixed input size: the mean of a channel is one number whatever the spatial dimensions were.

Global Average Pooling against Flatten

The step between the convolutions and the classifier, and why the obvious version wastes most of the model's parameters.

Count them

Drag the controls and watch the readout. At the defaults — 7×7×512 into 10 classes:

flatten  ->  7 * 7 * 512 * 10  =  250,880 weights
GAP      ->          512 * 10  =    5,120 weights

Forty-nine times fewer, and 49 is exactly 7×7. The ratio is always the spatial area of the feature map, which is why the saving grows as the map gets larger.

Set classes to 1000, as in ImageNet, and the flattened version needs 25 million weights in a single layer. Early architectures really did this: VGG-16 keeps about 90% of its 138 million parameters in its final dense layers, and almost all of that is the first one immediately after the flatten.

What pooling gives up, and what it buys

Averaging discards where in the map each activation was. If channel 7 responds to wheels, flatten preserves that the wheels were at the bottom left, and GAP records only that there were wheels.

For classification that is usually the right trade. The question is whether a car is present, not where the wheels sat, and the convolutional layers underneath have already encoded position-sensitive structure into which channels fire.

Three things are bought in exchange.

Far fewer parameters, and therefore much less overfitting. A dense layer with 25 million weights on a dataset of 50,000 images is an invitation to memorise.

Any input size. The mean of a channel is one number regardless of the spatial dimensions, so a GAP network accepts a 224-pixel image or a 400-pixel one without modification. A flattened network cannot: 25,088 weights expect exactly 25,088 inputs, which is why older models are rigid about input size.

Interpretability. With GAP followed by a single dense layer, each class score is a weighted sum of channel means. That weighting is exactly what Class Activation Mapping uses to produce a heatmap, and [Grad-CAM](grad_cam.html) generalises it.

What replaced the debate

Every modern architecture uses GAP. ResNet, Inception, MobileNet, EfficientNet and the convolutional stems of hybrid transformers all end with a global pool and one dense layer.

The exception worth knowing is Vision Transformers, which typically use a dedicated class token instead — a learned vector that attends to all the [patches](vision_transformer_patches.html) and carries the summary. Some ViT variants pool the patch tokens instead and report it works about as well.

The parameters it deletes

The saving is exact and it is large. A 7×7×512 feature map into 10 classes, two ways to reach the classifier:

methodweights in that layer
flatten + dense7 × 7 × 512 × 10 = 250,880
global average pool + dense512 × 10 = 5,120

Forty-nine times fewer — and 49 is exactly the 7×7 spatial area, so the ratio is always the size of the feature map. Scale the classes to ImageNet's 1000 and the flattened version needs 25 million weights in a single layer, which is why VGG-16 keeps about 90% of its 138 million parameters in its final dense layers, almost all in the one right after the flatten. GAP deletes those, and gets two things back for free: any input size works, because the mean of a channel is one number whatever the spatial dimensions, where 25,088 flatten-weights demand exactly 25,088 inputs; and each class score becomes a weighted sum of channel means, which is precisely the structure [Grad-CAM](grad_cam.html) reads to make a heatmap. What it gives up is *where* each activation was — usually the right trade for classification, where presence matters more than position.

What pooling gives up is *where* each activation was — if a channel responds to wheels, flatten preserves that they were at the bottom-left, GAP records only that there were wheels — and for classification that is the right trade, because the question is whether a car is present, not where its wheels sat. Every modern architecture uses GAP: ResNet, Inception, MobileNet and EfficientNet all end with a global pool and one dense layer. The exception is the Vision Transformer, which usually carries a dedicated class token instead, though some variants pool the patch tokens and report it works about as well — and global *max* pooling is the sibling worth remembering, better when one strong local response matters more than an average.

The parameter cut is also a regularisation story. A dense layer with 25 million weights on a dataset of 50,000 images is an invitation to memorise; replacing it with a 512-to-classes layer removes most of the capacity that overfitting lives in, which is part of why the change stuck across every architecture that followed VGG.

Where it goes wrong

Pooling too early. GAP belongs after the last convolutional block. Applied midway it destroys the spatial structure the remaining layers need.

Using flatten because a tutorial did. Most tutorials predate the change. Check what the parameter count is doing before accepting it.

Expecting GAP to fix a small feature map. With a 1×1 map there is nothing to average and the two are identical.

Forgetting global max pooling exists. It takes the maximum instead of the mean, and for tasks where one strong local response matters more than an average — some detection and audio tasks — it can be the better choice.

Replacing the flatten layer with one number per channel

Global average pooling collapses a whole feature map to a single number per channel. It looks like it throws away almost everything -- and that is exactly what makes it work, in a way this measures against the flatten-and-dense alternative it replaced.

Check yourself

0 of …

Answer without scrolling back up.

  1. How many times fewer weights does GAP need than flatten, for a 7x7 feature map?

  2. Why can a GAP network accept any input size?

  3. What does global average pooling discard?

Cheat sheet

Global Average Pooling against Flatten

Convolutional layers output a 3D block: height × width × channels. A classifier needs a single vector. Something has to turn one into the other, and there are two candidates.

COMPUTER VISION · AI.Cruz.in/computer_vision/global_average_pooling.html

About the author

AI.Cruz builds and maintains AI.Cruz. 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.