A feature map keeps track of both *what* a convolutional network detects and *where* it detects it. For one image, it is a rank-3 tensor with height, width, and channels. Each channel is a 2D grid of responses from one filter at different locations—not a color channel like red, green, or blue. section 8.1.1
From pixels to filter responses
A 28 × 28 grayscale digit has shape (28, 28, 1). A convolutional layer with 64 filters produces a (26, 26, 64) feature map: 64 separate 26 × 26 response grids. Read `output[:, :, n]` as the response of filter `n` across the image. section 8.1.1
Follow the shape through a small classifier:
- Convolution applies the same learned transformation to local patches. Later layers can combine earlier patterns into larger ones. section 8.1.1
- Max pooling takes the maximum in each channel’s local window. A 2 × 2 window with stride 2 turns a 26 × 26 map into a 13 × 13 map, reducing how widely information is spread across locations. section 8.1.2
- Global average pooling turns a (3, 3, 256) feature map into a 256-value vector by averaging each channel’s grid, ready for a Dense classifier. section 8.1
Listing 8.2 Displaying the model’s summary
>>> model.summary() 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)
The model summary makes the changing spatial dimensions and channel counts visible after each convolution and pooling layer. section 8.1
To inspect a feature map, plot its channels separately as 2D images rather than treating the whole tensor as one picture. For a cat image, a first-layer activation has shape (1, 178, 178, 32): the leading dimension holds the image batch, and one channel appears to respond to diagonal edges. Learned filters can differ between runs. section 10.1
Listing 10.5 Visualizing the sixth channel
import matplotlib.pyplot as plt plt.matshow(first_layer_activation[0, :, :, 5], cmap="viridis")
This plotting command selects one image and one channel from a batched activation, leaving the 2D grid that can be displayed. section 10.1







