Max pooling shrinks a feature map while keeping the strongest response in each local region. A 2 × 2 max-pooling window outputs the maximum value for each channel; with a stride of 2, it typically halves the map’s height and width. Unlike a convolution, this operation uses a fixed maximum rather than a learned kernel. section 8.1.2
A small MNIST convnet
In R with keras3, place `layer_max_pooling_2d(pool_size = 2)` between convolution layers: ```r library(keras3) inputs <- keras_input(shape = c(28, 28, 1)) outputs <- inputs |> layer_conv_2d(filters = 64, kernel_size = 3, activation = "relu") |> layer_max_pooling_2d(pool_size = 2) |> layer_conv_2d(filters = 128, kernel_size = 3, activation = "relu") |> layer_max_pooling_2d(pool_size = 2) |> layer_conv_2d(filters = 256, kernel_size = 3, activation = "relu") |> layer_global_average_pooling_2d() |> layer_dense(10, activation = "softmax") model <- keras_model(inputs, outputs) ``` The first convolution produces a 26 × 26 feature map; the following max-pooling layer reduces it to 13 × 13 without changing its 64 channels. section 8.1 section 8.1.2
Why shrink the maps? As convolution and pooling stages alternate, later features can draw on larger regions of the original image. Without the pooling layers in this example, the last map remains 22 × 22, while a third-layer 3 × 3 window draws on only a 7 × 7 region of the input. Downsampling helps build a spatial hierarchy and makes the information less spread across positions before global average pooling. section 8.1.2
For larger images, more convolution–max-pooling stages can reduce spatial size further: a dogs-versus-cats model starts with 180 × 180 images and reaches 7 × 7 maps before global average pooling. Max pooling is not the only way to reduce dimensions: strided convolutions also downsample feature maps. Pooling a whole token sequence is a different use of the idea; a Transformer classifier instead takes its first token’s context-aware representation. section 8.2.3 section 8.1.1 section 15.4.4
Listing 8.2 Displaying the model’s summary
model Model: "functional" ┌─────────────────────────────────┬────────────────────────┬───────────────┐ │ Layer (type) │ Output Shape │ Param # │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ input_layer (InputLayer) │ (None, 28, 28, 1) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d (Conv2D) │ (None, 26, 26, 64) │ 640 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d (MaxPooling2D) │ (None, 13, 13, 64) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_1 (Conv2D) │ (None, 11, 11, 128) │ 73,856 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_1 (MaxPooling2D) │ (None, 5, 5, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_2 (Conv2D) │ (None, 3, 3, 256) │ 295,168 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ global_average_pooling2d │ (None, 256) │ 0 │ │ (GlobalAveragePooling2D) │ │ │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense (Dense) │ (None, 10) │ 2,570 │ └─────────────────────────────────┴────────────────────────┴───────────────┘ Total params: 372,234 (1.42 MB) Trainable params: 372,234 (1.42 MB) Non-trainable params: 0 (0.00 B)
Inspect the layer-by-layer shapes to see spatial dimensions shrink at max-pooling layers while channel counts stay fixed. section 8.1









