Convolutional Neural Networks
Convolutional Neural Networks (CNNs) are a class of deep learning models designed to process grid-structured data — most famously images — by applying learned filters that detect local patterns such as edges, textures, and shapes. They matter enormously in modern AI because they power nearly every computer vision system in production today, from medical imaging to self-driving cars. The counterintuitive fact: a CNN trained on cats and dogs spontaneously learns to detect edges in its first layer and fur textures in its second — nobody told it to; it discovered these features entirely on its own.
The key insight is that images have local structure — a pixel is most related to its neighbors, not to a pixel on the opposite side of the image. Instead of connecting every pixel to every neuron (which would be astronomically expensive), a CNN slides a small window called a filter across the image and applies the same learned weights everywhere. This means the network learns to recognize a feature — say, a vertical edge — in the top-left corner, and that same detector automatically works in the bottom-right corner too. This property is called translation equivariance, and it's why CNNs can generalize so efficiently from so few parameters.
How It Works
A CNN processes an image through a sequence of operations. The two most important are convolution and pooling.
The Convolution Operation
A filter (also called a kernel) is a small grid of learnable weights — typically 3×3 or 5×5. It slides across the input image and at each position computes a dot product between the filter weights and the patch of pixels underneath.
Explanation: At output position (i,j), multiply each weight in kernel K by the corresponding input pixel, then sum them all up to get a single number.
Symbols:
- — the output value at row , column
- — the input pixel at the corresponding shifted position
- — the filter weight at position
- — indices that iterate over the filter's height and width
Adding a Bias and Activation
In practice, a bias term is added and the result is passed through an activation function (almost always ReLU in modern CNNs):
Explanation: Shift the convolution output by a learned bias b, then clip any negative values to zero, introducing the non-linearity the network needs to learn complex patterns.
Symbols:
- — a scalar bias term, one per filter
- — Rectified Linear Unit; outputs 0 for negatives, unchanged for positives
Output Size After Convolution
Explanation: The output width depends on the input width, filter size, how much zero-padding you add around the border, and how many pixels you skip between each filter position.
Symbols:
- — input width in pixels
- — filter size (e.g. 3 for a 3×3 filter)
- — padding (zeros added around the border; often 1 to keep size the same)
- — stride (step size between filter positions; usually 1 or 2)
Quick Python Example
```python import torch import torch.nn as nn
# A minimal CNN for 28x28 grayscale images (e.g., MNIST) class SimpleCNN(nn.Module): def __init__(self): super().__init__()
# 1 input channel (grayscale), 32 filters, each 3x3 self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, padding=1) self.relu = nn.ReLU()
# Halves spatial dimensions: 28x28 -> 14x14 self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
# Flatten then classify into 10 digit classes self.fc = nn.Linear(32 14 14, 10) def forward(self, x): # x shape: (batch, 1, 28, 28) x = self.pool(self.relu(self.conv1(x))) # -> (batch, 32, 14, 14) x = x.view(x.size(0), -1) # flatten -> (batch, 6272) return self.fc(x) # -> (batch, 10) model = SimpleCNN() print(model) ```
Max Pooling
After convolution, a pooling layer reduces the spatial size of feature maps. Max pooling takes the largest value in each small window: ```python
# Visualizing what max pooling does on a tiny example import numpy as np feature_map = np.array([[1, 3, 2, 4], [5, 6, 1, 2], [3, 1, 4, 7], [2, 8, 3, 5]])
# 2x2 max pool with stride 2
# Top-left 2x2 window -> max(1,3,5,6) = 6
# Top-right 2x2 window -> max(2,4,1,2) = 4
# Bottom-left 2x2 window -> max(3,1,2,8) = 8
# Bottom-right 2x2 window -> max(4,7,3,5) = 7 pooled = np.array([[6, 4], [8, 7]]) print("After 2x2 max pool:\n", pooled) ``` Pooling achieves two things: it shrinks the feature map (reducing computation) and makes detections slightly robust to small shifts in position.
Yann LeCun, a French-American computer scientist, developed the first practically successful CNN — LeNet-5 — while at AT&T Bell Labs in 1989, applying it to handwritten digit recognition for the US Postal Service and eventually for reading bank checks. His work demonstrated that gradient-based learning could train multi-layer convolutional architectures end-to-end, a radical idea at the time when most researchers believed neural networks could not scale. Remarkably, LeNet was processing over ten percent of all checks in the United States by the late 1990s, making CNNs one of the earliest deep learning technologies deployed at massive commercial scale.
Intuition
Imagine you are trying to identify a handwritten letter "A" in a photograph, and your only tool is a small magnifying glass that you slide across the image. At each position, you ask: "Does this patch look like a diagonal line going up-left? Does it look like a crossbar?" You don't need to look at the whole image at once — you collect local evidence patch by patch, then combine those clues. That's exactly what a CNN filter does. Now imagine you have 32 different magnifying glasses, each trained to notice a different micro-pattern — one for horizontal edges, one for color blobs, one for curves. Stack several rounds of this process (each layer looking at increasingly large-scale patterns), and by the final layer your network has assembled micro-clues into parts ("this looks like a pointy top and two legs") and then into a full object ("that's an 'A'"). The magic is that nobody labeled which magnifying glass should detect which feature — the training data and gradient descent sorted that out automatically.