Convolutional networks: output shapes and parameter counts
Compute how convolution and pooling change the size of an image, and why sharing weights saves parameters.
On this page
Integer division and multiplication.
- Compute how convolution and pooling change the size of an image, and why sharing weights saves parameters.
- Predict the sample output and explain the state changes.
- Complete the practice task and check the boundary cases.
The concept
A convolutional neural network (CNN) is built for data with a grid structure, such as images. A convolutional layer slides small filters over the input. Each filter has a fixed number of weights and is applied at every position, so the same weights are reused: this is weight sharing. A layer with c_out filters of size k × k on an input with c_in channels has (k·k·c_in + 1)·c_out parameters, including one bias per filter, however large the image is.
The size of the output depends on the input size n, the filter size k, the stride s (how far the filter moves), and the padding p added around the border: out = floor((n + 2p − k) / s) + 1. Pooling layers shrink the maps further, for example 2 × 2 max pooling with stride 2 halves the width and height. Each output value depends only on a small neighbourhood of its input, so the network is built from local features that later layers combine into larger patterns. Deep learning libraries actually compute cross-correlation, which does not flip the filter, and call it convolution.
The program follows a small LeNet-style network on a 28 × 28 grayscale image. The first layer has 6 filters of size 5 × 5 and needs only 156 parameters. A fully connected layer producing the same 24 × 24 × 6 output from all 784 inputs would need 2,712,960. The second convolution, with 16 filters, adds 2,416 parameters. After pooling, 4 × 4 × 16 = 256 values feed into a dense layer with 120 units.
Code example
def conv_out(n, k, stride=1, pad=0):
return (n + 2 * pad - k) // stride + 1
size, channels = 28, 1
size = conv_out(size, 5)
conv1_params = (5 * 5 * channels + 1) * 6
channels = 6
print(size, channels, conv1_params)
size = conv_out(size, 2, stride=2)
print(size, channels)
size = conv_out(size, 5)
conv2_params = (5 * 5 * channels + 1) * 16
channels = 16
print(size, channels, conv2_params)
size = conv_out(size, 2, stride=2)
print(size, channels, size * size * channels)
print((28 * 28) * (24 * 24 * 6) + 24 * 24 * 6)
print(256 * 120 + 120)24 6 156 12 6 8 16 2416 4 16 256 2712960 30840
Follow the code
Open the walkthrough to inspect the example one step at a time.
Show guided walkthrough
def conv_out(n, k, stride=1, pad=0): return (n + 2 * pad - k) // stride + 1 size, channels = 28, 1size = conv_out(size, 5)conv1_params = (5 * 5 * channels + 1) * 6channels = 6print(size, channels, conv1_params)size = conv_out(size, 2, stride=2)print(size, channels)size = conv_out(size, 5)conv2_params = (5 * 5 * channels + 1) * 16channels = 16print(size, channels, conv2_params)size = conv_out(size, 2, stride=2)print(size, channels, size * size * channels)print((28 * 28) * (24 * 24 * 6) + 24 * 24 * 6)print(256 * 120 + 120)Follow the example
Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.
View the complete dry-run table
| Step / line | What happens | State after step | Output so far |
|---|---|---|---|
| Output size = floor((n + 2·pad − k) / stride) + 1: how many positions the filter fits. | — | — | |
| Each of 6 filters has 5 × 5 × 1 weights plus a bias: 26 × 6 = 156 parameters, regardless of image size. | — | — | |
| A 28 × 28 image becomes 24 × 24 with 6 channels. | — | 24 6 156 | |
| After the second convolution and pooling, the maps are 4 × 4 with 16 channels: 256 values to flatten. | — | 24 6 156 12 6 8 16 2416 4 16 256 | |
| A fully connected layer with the same output size would need almost 2.7 million parameters. | — | 24 6 156 12 6 8 16 2416 4 16 256 2712960 | |
| The dense layer after flattening has 30,840 parameters, far more than the convolutions before it. | — | 24 6 156 12 6 8 16 2416 4 16 256 2712960 30840 |
Behind the scenes
How Python processes this code
Python runs this source through its interpreter. It creates objects for values and resolves names as each statement runs.
Cost and common mistakes
A convolution layer costs O(out_h · out_w · c_out · k² · c_in) multiply-adds, and stores only O(k² · c_in · c_out) parameters.
- Shape mistakes are the most common bug in CNNs. Compute the output size of every layer before training.
- Filters are learned, not designed. The 5 × 5 size is a hyperparameter you choose.
- Pooling and strides discard spatial detail. Too much downsampling can lose information needed for fine tasks.
Try it yourself
What output size does a 3 × 3 filter with padding 1 and stride 1 give for a 32 × 32 input?
Reveal answer and reasoning
(32 + 2·1 − 3) / 1 + 1 = 32. Padding of 1 with a 3 × 3 filter preserves the size.