FromZero2AI
CoursesPlaygroundBlogContact
Support on Ko-fi
Neural Networks & Deep Learning • Module B: Seeing the World (Computer Vision)Lesson 4: Convolutional Neural Networks (CNNs)
PreviousNext

Lesson 4: Convolutional Neural Networks (CNNs)

Learn how filters and pooling layers extract visual features from images.

By Bishwambhar Sen • Last updated October 13, 2026

Built with AI for beginners. Free forever.

Support on Ko-fi•About•Contact•Blog•Privacy Policy•Terms of Service

Standard fully connected networks fail when processing high-dimensional data like images because they ignore spatial relationships. Convolutional Neural Networks (CNNs) solve this by looking at local pixel blocks.

The Convolutional Layer

The core of a CNN is the Convolutional Layer. Instead of connecting every pixel to every neuron, a sliding matrix called a Kernel (or filter) traverses the image. As it slides, it performs dot products on local region matrices, highlighting spatial features like edges, textures, or shapes.

Kernel Properties: Stride and Padding

  • Kernel Size: The spatial dimensions of the filter (commonly 3×3 or 5×5).
  • Stride: The step size of the kernel as it slides across the image. A stride of 1 moves the kernel one pixel at a time; a stride of 2 skips one pixel, shrinking the output dimensions.
  • Padding: Adding border pixels (usually zeros) around the image to allow the kernel to inspect edge pixels without shrinking the output image size.
Interactive: Sliding Kernel Simulator
Output size formula:
O = ((I − K + 2·P) / S) + 1 = ((5 − 3 + 2·0) / 1) + 1 = 3
Output feature map: 3 × 3
Input 5×5
2
7
3
1
5
0
4
8
6
2
9
1
5
3
7
4
6
0
8
1
3
2
9
4
6
Kernel 3×3
Click cells to edit
Output 3×3
·
·
·
·
·
·
·
·
·

Downsampling with Pooling

Pooling layers reduce the spatial size of representation matrices to cut down parameters and computational load. The most popular method is Max Pooling, which slides a filter across the output and selects the maximum value from each block, keeping only the most dominant features.

Interactive: Max Pooling Visualizer

A 2×2 pooling window with stride 2 slides across the 4×4 input, selecting the maximum value in each region.

Input 4×4
6
3
2
8
1
9
4
5
7
2
6
1
3
8
0
4
→
Output 2×2
·
·
·
·

Why Not Just Use a Dense Network?

A fully connected layer connects every input to every neuron. For a modest 224 x 224 colour image there are 224 x 224 x 3 = 150,528 input values; a single dense layer with 1,000 neurons would need over 150 million weights, and it would learn nothing about the fact that neighbouring pixels belong together. Worse, a cat in the top-left corner and the same cat in the bottom-right would look like entirely different inputs. CNNs fix both problems with two ideas: local connectivity (each output looks at a small neighbourhood) and weight sharing (the same small kernel is reused at every position). A 3 x 3 kernel has just 9 weights regardless of image size, and because it is applied everywhere, a feature it detects is detected wherever it appears.

Worked Example: One Convolution Step

Take a 3 x 3 patch of pixel brightness and a vertical-edge kernel (a Sobel-style filter). The output value is the sum of element-wise products:

patch  = [[10, 10, 0],       kernel = [[-1, 0, 1],
         [10, 10, 0],                  [-2, 0, 2],
         [10, 10, 0]]                  [-1, 0, 1]]

output = (10*-1 + 10*0 + 0*1)
       + (10*-2 + 10*0 + 0*2)
       + (10*-1 + 10*0 + 0*1)
       = -10 - 20 - 10 = -40

The large-magnitude result signals a strong vertical edge: bright on the left, dark on the right. On a flat region where all pixels are equal, the positive and negative columns cancel and the output is 0. Sliding the kernel over the whole image produces a feature map showing where that pattern occurs. In a CNN you do not design these kernels; the network learns their values by gradient descent. (Strictly speaking, deep learning libraries compute cross-correlation, which does not flip the kernel; since the kernel is learned, the distinction does not matter in practice.)

Output Size, Step by Step

The formula from the exercise, O = floor((I - K + 2P) / S) + 1, deserves a few more cases:

  • 32 x 32 input, 3 x 3 kernel, stride 1, padding 0: (32 - 3) / 1 + 1 = 30. The image shrinks by K - 1.
  • Same, with padding 1: (32 - 3 + 2) / 1 + 1 = 32. Padding of (K - 1) / 2 keeps the size, often called "same" padding.
  • Stride 2, padding 0: (32 - 3) / 2 + 1 = 15.5, which is floored to 15. Frameworks round down, so the last row and column are not covered.
  • 5 x 5 input, 3 x 3 kernel, stride 1, padding 0: 3, the 3 x 3 output you can step through in the simulator above.

Padding does two jobs: it preserves spatial size so you can stack many layers, and it lets border pixels take part in as many windows as interior pixels.

Channels and Filters

Real images have channels (3 for RGB), and a convolutional layer has many filters. Each filter spans all the input channels and produces one output channel, so a layer with 16 filters turns a 3-channel image into a 16-channel stack of feature maps. The number of learnable parameters in a convolutional layer is (K x K x C_in + 1) x C_out, where the +1 is each filter's bias. For 3 x 3 kernels mapping 3 channels to 16 that is (27 + 1) x 16 = 448 parameters, tiny compared with the dense layer above.

A Hierarchy of Features

Stacking layers builds up abstraction. Early filters tend to respond to edges and colour blobs; middle layers combine them into textures and parts such as corners or eyes; deep layers respond to whole objects. This works because each successive layer sees a larger region of the original image, called its receptive field. Two stacked 3 x 3 convolutions see a 5 x 5 region, and pooling grows the receptive field faster still.

Putting It Together in PyTorch

A classic small CNN for 28 x 28 greyscale digits alternates convolution, a non-linearity and pooling, then flattens into a dense classifier. Tracking shapes is the key skill:

import torch
import torch.nn as nn

model = nn.Sequential(
    nn.Conv2d(1, 8, kernel_size=3, padding=1),   # (N,1,28,28) -> (N,8,28,28)
    nn.ReLU(),
    nn.MaxPool2d(2),                             # -> (N,8,14,14)
    nn.Conv2d(8, 16, kernel_size=3, padding=1),  # -> (N,16,14,14)
    nn.ReLU(),
    nn.MaxPool2d(2),                             # -> (N,16,7,7)
    nn.Flatten(),                                # -> (N,784)
    nn.Linear(16 * 7 * 7, 10),                   # -> (N,10) class scores
)

x = torch.randn(4, 1, 28, 28)    # a batch of 4 fake images
print(model(x).shape)            # torch.Size([4, 10])
print(sum(p.numel() for p in model.parameters()))   # 9098

The parameter count is 80 (first conv) + 1,168 (second conv) + 7,850 (the linear layer) = 9,098. Notice that the final dense layer holds most of the weights, and that PyTorch expects image batches in the order (batch, channels, height, width).

Pooling Revisited

Max pooling keeps the strongest response in each window. It has no learnable parameters, halves the height and width when the window and stride are both 2, and gives a small degree of translation tolerance: if a feature moves by one pixel inside a window, the pooled output often stays the same. The price is that precise position information is discarded, which is acceptable for classification but is why tasks like segmentation use architectures that recover resolution. Average pooling takes the mean instead and is often used as a global pooling step at the end of a network.

Common Pitfalls

  • Wrong flatten size. The input size of the first Linear layer must equal channels x height x width after the last pooling. Print the shape or run a dummy batch to find it.
  • Shrinking too fast. Many unpadded convolutions plus pooling can reduce a small image to 1 x 1 before you have enough layers.
  • Channel order confusion. PyTorch uses channels-first; many image libraries load channels-last, so tensors need permuting.
  • Forgetting normalization. Scale pixel values (for example to 0 to 1, then standardize) before training; raw 0 to 255 inputs slow learning.
  • Ignoring augmentation. Small datasets overfit; random flips and crops give the network more varied examples.

Recap

  • CNNs exploit local structure and share weights, so they need far fewer parameters than dense networks on images.
  • A kernel slides over the input computing dot products; output size is floor((I - K + 2P) / S) + 1.
  • Each layer has many filters, one output channel per filter; parameters are (K x K x C_in + 1) x C_out.
  • Early layers detect edges, deeper layers detect parts and objects.
  • Pooling downsamples without parameters, trading position detail for efficiency.

Exercise: Convolutional Math

Calculate the output spatial size (O) for a convolution operation with the following settings:

Input size (I): 32 × 32
Kernel size (K): 3 × 3
Stride (S): 1
Padding (P): 0
Formula: O = ((I − K + 2·P) / S) + 1
  • 32 × 32
  • 30 × 30
  • 28 × 28

Next, we will apply convolutional concepts in a project where we train a model on real images!