Vocabulary for this course

The terms the chapters assume, in plain words. You can open this from any chapter.

anchor
A reference box of a fixed size and shape that a detector adjusts to fit an object.
augmentation
Random changes to training images that keep the correct answer intact, such as crops, flips and brightness shifts.
bounding box
Four numbers marking an object’s edges, either as two corners or as a centre, width and height.
channel
One grid of values per colour or per learned pattern; an RGB image has three such grids.
convolution
Sliding a small grid of weights across an image, multiplying and summing at each position.
feature map
The grid of responses one kernel produces when slid across an image.
IoU
The overlap area of two boxes divided by the area they cover together; one means identical, zero means no overlap.
kernel
The small grid of weights a convolution slides over an image.
normalisation
Rescaling values to a common range or spread, often using statistics from the training images.
padding
Extra values, usually zeros, added around an image’s border so a sliding window can reach the edge.
pixel
One number in an image grid, giving brightness or colour strength at a single position.
pooling
Summarising each small window of a feature map into one value, such as its maximum or average.
receptive field
The part of the input that can affect one output value.
stride
How far a sliding window moves between positions; larger steps shrink the output.

Computer vision from the ground up

Capstone: a convolution layer and its output

A convolution layer is a bank of kernels with a bias, applied over every position and every input channel. Build one and the shapes stop being mysterious.

Part 10 of 10

Intermediate18 min readBack to Courses

The layer, completely

The input has C_in channels, each of height H and width W. The layer owns C_out filters. A filter is the full set of weights that produces one output channel. Each filter is a stack of C_in kernels of size K by K. There is one bias per output channel, and the bias is a learned offset. The output has C_out channels. Every output value is the sum of a K by K by C_in patch times the corresponding filter, plus the bias.

The parameter count follows directly: C_out times C_in times K times K, plus C_out. A layer with 3 input channels, 32 output channels and a 3 by 3 kernel has 896 parameters. That is small compared with a dense layer on the same input. It is the reason convolutional networks can be deep without exploding.

Padding and stride are arguments of the layer, not separate operations. Padding adds zeros around the input before the sliding starts. Stride changes how far the window moves. Both change the output size, and both are recorded in the layer configuration. A saved model can therefore reproduce its own shapes without the original code.

The forward pass as loops

The definition is six nested loops: output channel, output row, output column, input channel, kernel row, kernel column. The innermost line multiplies an input value by a weight and adds it to the accumulator. The accumulator is the running total. Every optimised implementation computes exactly this, in a different order. The loops are flattened into matrix multiplies.

Writing the loops once is the best way to understand the shapes. The input channel loop is the one people forget. A filter is not a single 3 by 3 grid when the input has depth. It is a 3 by 3 grid per input channel, and all of them contribute to one output value.

The loop order is arbitrary. Putting the output channel outermost makes the weight reuse obvious. Putting the kernel loops innermost makes the memory access contiguous. Real implementations use im2col or a direct kernel with register blocking, but they compute the same sum. im2col rearranges image patches into columns so the convolution becomes one matrix multiply. The loops are the specification, not the implementation.

The layer and its parameter count

import torch
from torch import nn

layer = nn.Conv2d(3, 32, kernel_size=3, padding=1, bias=True)
x = torch.randn(1, 3, 64, 64)

print(layer(x).shape)     # (1, 32, 64, 64)
print(layer.weight.shape) # (32, 3, 3, 3)
print(layer.bias.shape)   # (32,)

Two channels, two filters

Run the layer on an input with a vertical bar in one channel and a horizontal bar in the other. Each filter reads both channels, and the output channel that matches its pattern lights up.

Output
Click "Run" to execute your code

What the output means

Each output channel is a feature map: a grid of responses to one learned pattern. A high value means the pattern was present at that position. The first layer of a trained network usually learns edges and colour blobs. Deeper layers learn textures and parts. None of that is imposed by the architecture, only by the data and the loss.

A channel that is zero everywhere is dead. Its filter never produced a positive response, or the ReLU after it never opened. That can be a sign of a learning rate that was too high. It can also mean an initialisation that was too aggressive, or a filter that is irrelevant to the task. Visualising a few channels is a cheap check before a long run.

The bias shifts the threshold of a feature map. A large negative bias means the channel only fires for a very strong response. A large positive one means it fires almost everywhere. After batch norm the bias is often redundant, which is why layers that use it are sometimes created with bias=False.

Count the parameters before you train. A layer with 3 input channels, 32 output channels and a 3 by 3 kernel has 896, and if your printout says 864 you forgot the bias.

From layer to network

A convolutional network stacks these layers, inserts a nonlinearity after each one, and downsamples between stages. The early stages keep the resolution and learn local patterns. The later stages trade resolution for channels and learn combinations of patterns. A global average pool collapses the last feature map to one vector per channel, and a linear layer turns that into logits.

The receptive field, the parameter count and the output shape are the three numbers to track. If a stack loses too much resolution, small objects disappear. If the channel count grows too fast, the parameters and the memory follow. If the output shape is wrong, the error is usually one missing padding or one stride applied twice.

The next step is to train the same stack on a real dataset. CIFAR-10 is small enough to run on a laptop and varied enough to need augmentation, normalisation and a schedule. Everything in this course appears there: shapes, kernels, pooling, colour, augmentation, the loop and the metrics. The layer you built by hand is the one the framework runs.

Conv, ReLU, pool

Run the full stage and print the shape and parameter count at each step. The convolution produces 6 by 6 maps, ReLU keeps the positive responses, and pooling halves them to 3 by 3.

Output
Click "Run" to execute your code

Check what you learned

One question at a time. A wrong answer explains itself — take another go.

Part 1 of 5

A 64 by 64 input goes through Conv2d(3, 32, 3, padding=1). What is the output shape?