What a convolution actually does
A 2-D convolution slides a small filter (e.g. 3×3 weights) across an input image and at each position computes a weighted sum of the local pixel patch. The same filter is reused at every position — that's the parameter sharing that makes CNNs efficient. A single 3×3 conv with 32 input channels and 64 output channels has 3*3*32*64 + 64 = 18496 parameters, regardless of image size.
You stack many filters per layer (the channel dimension) and many layers (the depth), with non-linearities between them. Early layers learn edge detectors and color blobs; mid layers learn textures and shape parts; deep layers learn object-shaped features.
nn.Conv2d as: 'apply N learned filters of size kxk across the spatial dimensions, with stride s and padding p, producing an output of shape [B, N, H_out, W_out].' The exact output shape comes from floor((H + 2p - k)/s) + 1.The hyperparameters that matter
- kernel_size — usually 3, sometimes 1 (channel-mix), sometimes 7 (early layers).
- stride — 1 (same spatial size) or 2 (downsample).
- padding — usually
k//2for 'same' padding (output same size as input when stride=1). - in_channels / out_channels — width of the network at this layer.
- groups — 1 (standard) or in_channels (depthwise, for efficient mobile architectures).
Why convolutions generalize
Two reasons. Translation equivariance: if you shift the input, the output shifts the same way — the model doesn't need to relearn features for every position. Parameter sharing: each filter is reused across the image, so you have far fewer parameters and they're each trained on far more data than they would be in a fully-connected layer.