Skip to content
  • CNN Architectures & ResNet · Deep Learning

CNN Architectures & ResNet

LearnViaNotes @learnvianotes· 3 min read

The classic CNNs trace how the field learned to go deeper: bigger datasets and GPUs (AlexNet), small stacked filters (VGG), and finally skip connections (ResNet) that made 100+ layers trainable.

ModelYearKey ideaDepth / params
LeNet-51998Conv → pool → conv → pool → dense; read handwritten digits5 layers, 60 K
AlexNet2012ReLU, dropout, data augmentation, trained on GPUs — won ImageNet by a wide margin8 layers, 60 M
VGG-162014Only 3×3 convs, stacked deep; simple and uniform16 layers, 138 M
GoogLeNet / Inception2014Parallel 1×1, 3×3, 5×5 branches; 1×1 convs to cut channels22 layers, 7 M
ResNet2015Residual connections y = F(x) + x18–152 layers, 11–60 M
MobileNet / EfficientNet2017–19Depthwise-separable convs; scaling width/depth/resolution togetherFew M, for phones
ConvNeXt, ViT2020–22Transformer ideas for vision: patches + attention (ViT), modernised CNNs—

A small CNN, shape by shape

Python
import torch
from torch import nn

torch.manual_seed(0)
model = nn.Sequential(
    nn.Conv2d(1, 16, 3, padding=1), nn.BatchNorm2d(16), nn.ReLU(),   # 28×28
    nn.MaxPool2d(2),                                                  # → 14×14
    nn.Conv2d(16, 32, 3, padding=1), nn.BatchNorm2d(32), nn.ReLU(),
    nn.MaxPool2d(2),                                                  # → 7×7
    nn.AdaptiveAvgPool2d(1), nn.Flatten(),                            # → 32 numbers
    nn.Linear(32, 10),                                                # → 10 class logits
)
x = torch.randn(4, 1, 28, 28)             # a batch of 4 MNIST-sized images
shapes = []
for layer in model:
    x = layer(x)
    if isinstance(layer, (nn.MaxPool2d, nn.Flatten, nn.Linear)):
        shapes.append(tuple(x.shape))
print(shapes)                             # [(4, 16, 14, 14), (4, 32, 7, 7), (4, 32), (4, 10)]
print(sum(p.numel() for p in model.parameters()))   # 5226

The pattern — conv/BN/ReLU blocks, downsampling that halves the resolution while channels double, global pooling, a linear head — describes most CNNs.

Residual connections

x → conv → BN → ReLU → conv → BN = F(x) → F(x) + x → ReLU

Python
import torch
from torch import nn

class ResidualBlock(nn.Module):
    def __init__(self, channels):
        super().__init__()
        self.body = nn.Sequential(
            nn.Conv2d(channels, channels, 3, padding=1, bias=False), nn.BatchNorm2d(channels), nn.ReLU(),
            nn.Conv2d(channels, channels, 3, padding=1, bias=False), nn.BatchNorm2d(channels),
        )

    def forward(self, x):
        return torch.relu(self.body(x) + x)          # the skip connection

torch.manual_seed(0)
block = ResidualBlock(8)
x = torch.randn(2, 8, 16, 16)
print(block(x).shape)                                # torch.Size([2, 8, 16, 16]) ← shape preserved so x can be added

nn.init.zeros_(block.body[4].weight)                 # zero the last BN's scale → F(x) = 0
print(torch.allclose(block(x), torch.relu(x)))       # True ← the block passes x straight through

Why it works: the gradient of F(x) + x with respect to x is ∂F/∂x + 1. The +1 path carries gradients straight back through any number of blocks, so early layers keep learning. When the shapes differ (more channels, stride 2), the shortcut uses a 1×1 conv to match them.

Why do residual connections help train very deep networks?

What does a 1×1 convolution do?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report