← All tutorials

On this page

1 AlexNet 2 VGG 3 Inception 4 Batch normalization 5 ResNet 6 Training problems and fixes 7 References

Classic CNN Architectures: AlexNet to ResNet

Every network here reads an image and outputs class scores, and each is remembered for one block it repeats; each block makes the same running layer, a 3×3 convolution from 32 to 64 channels, cheaper, deeper or more stable.

This page builds on CNN Basics: Convolution, Stride and Pooling, which teaches kernels, stride, padding, pooling and layer cost, and on Receptive Fields, Dilation and Causal Convolutions, which teaches the receptive field and dilation.

2012AlexNet, deep and fast2014VGG, small kernels stacked2014Inception, kernels side by side2015Batch norm, stable channels2015ResNet, a shortcut per blocknext: Efficient CNNs: MobileNet and EfficientNet
Figure 1. Each box links to its section; the dashed box opens Efficient CNNs.
Weights of the running layer, a 3×3 convolution from 32 to 64 channels.
weights = 32 · 64 · 9 = 18,432
A layer’s weights are the numbers it learns, here one 3×3 kernel, 9 numbers, for each of the 32 · 64 pairs of input and output channel. Its multiply-adds are the work per image, its weights times its output positions (CNN Basics: Convolution, Stride and Pooling).

1 AlexNet

AlexNet (Krizhevsky et al. 2012) showed that a deep CNN can beat earlier image methods by a wide margin, and its ReLU activations (which keep positive values and set negative ones to zero) made such a network fast to train. It has 5 convolution layers and 3 fully connected layers, about 60 million weights, trained on ImageNet, a labeled photo set with 1,000 classes, and a variant of it won the 2012 ImageNet challenge (Figure 2). Top-5 error counts an image wrong when the true class is not among the model’s five best guesses; top-1 error counts it wrong unless the best guess is right.

AlexNet variant 15.3% next entry 26.2%
Figure 2. Top-5 test error in the 2012 ImageNet challenge (the AlexNet paper); lower is better.

It made ReLU the standard activation for deep CNNs (the name follows Nair and Hinton 2010). In the paper, a four-layer CNN with ReLU reached 25% training error on CIFAR-10 six times faster than the same network with tanh (Figure 3). It also used overlapping pooling, windows 3 wide that step by 2, so neighbors share a cell (Figure 4).

ReLU 1× tanh 6×
Figure 3. Time to 25% training error on CIFAR-10, relative to ReLU (the AlexNet paper).
① windows 2 wide, step 2② windows 3 wide, step 2error drop vs ①top-10.4top-50.3
Figure 4. ① No cell shared. ② Shaded cells shared; AlexNet’s error fell.

In PyTorch the two pools differ only in the window size.

import torch.nn as nn

# (window, stride)
overlap = nn.MaxPool2d(3, 2)
plain = nn.MaxPool2d(2, 2)

2 VGG

VGG (Simonyan and Zisserman 2015) builds a whole image classifier from one small block and asks how deep it should go. The block is the 3×3 convolution with stride 1 and padding 1; five 2×2 max pools and three fully connected layers finish the network, on 224×224 ImageNet images. Three 3×3 layers see a 7×7 patch, like one 7×7 layer, with fewer weights and two extra ReLUs, the same trade as two 3×3 layers against one 5×5 (Stacking small kernels, in Receptive Fields).

Weights of three stacked 3×3 layers and of one 7×7 layer, C channels in and out.
three 3×3 = 3 · 9C² = 27C²
A 3×3 layer gives every pair of input and output channels its own 9 weights, so with C channels in and C out it holds 9C², and the stack has three such layers. The cost grows with the square of the channel count, so wide layers dominate a network's size.
one 7×7 = 49C²
One 7×7 layer sees the same 7×7 window with 49 weights per channel pair. The ratio stays 49 to 27 at any C, because both counts scale with C², so the stack always uses 45% fewer weights, and it adds two ReLUs between its layers.

2.1 VGG depth and accuracy

To test how much depth helps, the paper trains configurations A (11 weight layers) to E (19) from the same parts and scores each by top-5 error on the ImageNet validation set, with images resized so the shorter side is 256 pixels for training and testing. A-LRN adds local response normalization, which rescales each value by its neighbors in nearby channels. C is B plus three 1×1 layers, and D puts 3×3 layers in those places.

ConfigWeight layersTop-5 error
A1110.4%
A-LRN1110.5%
B139.9%
C169.4%
D168.8%
E199.0%

Top-5 error at a single test scale (the VGG paper, Table 3).

Error falls from A to D and rises at E. In the paper's words, "the error rate of our architecture saturates when the depth reaches 19 layers". At equal depth the all-3×3 D beats C, and LRN does not help.

top-5 val. error (%)

Figure 5. Top-5 error of configurations A to E; D is lowest.


3 Inception

The same cat can fill a quarter of the frame or all of it, so Inception (Szegedy et al. 2015) does not pick one kernel size. It runs 1×1, 3×3 and 5×5 branches and a pooling branch in parallel and joins their channels.

input1×11×13×31×15×5pool 3×31×1concatenate channels
Figure 6. One Inception block: four branches, channels joined.

3.1 1×1 convolution

A 1×1 kernel looks at one pixel, so it cannot find shapes; it only blends the channels at that pixel. The idea comes from Network in Network (Lin et al. 2014).

A 1×1 convolution blends the input channels at one pixel.
y[o] = Σc W[o,c] · x[c] + b
Each output channel y[o] at a pixel is a weighted sum of the input channels x[c] at that same pixel: Σc runs over the input channels, W[o,c] is how much channel c counts toward output o, and b is that output's bias. Every output is its own learned mix, so the layer can shrink, grow or recombine the channels. No neighboring pixel appears, so the receptive field does not grow.

The same blend runs at every pixel, so the map keeps its grid; flattening the map into a dense layer would lose the positions and need separate weights for every pixel. In the running example a 1×1 from 32 to 64 channels has 32 · 64 = 2,048 weights, against 18,432 (32 · 64 · 9) for the 3×3.

In PyTorch a 1×1 is an ordinary nn.Conv2d with kernel_size=1; the bias b is stored apart from W.

import torch
import torch.nn as nn

mix = nn.Conv2d(32, 64, 1)
print(mix.weight.shape)
# [64, 32, 1, 1]: W[o, c]
print(mix.weight.numel())
# 2048
x = torch.randn(1, 32, 56, 56)
print(mix(x).shape)
# [1, 64, 56, 56]
  1. 1Builds the 1×1 layer; its weight is the table W[o, c] of the card, 2,048 numbers.
  2. 2Runs it on a 56×56 map: same grid, 64 channels.

That cheapness is why Inception puts a 1×1 in front of its 3×3 and 5×5 branches: it shrinks the channel count first, so the large kernels stay affordable. torchvision builds each block as Inception(in, ch1x1, ch3x3red, ch3x3, ch5x5red, ch5x5, pool_proj), where each argument ending in red (reduce) is the 1×1 in front of its kernel. That version adds batch norm after every convolution, which the 2015 network did not have, and its “5×5” branch actually uses a 3×3 kernel, a known bug its source notes and keeps for the trained weights (torchvision googlenet.py).


4 Batch normalization

If one channel's values sit near 0.01 and another's near 100, no single step size suits both. Batch normalization, or batch norm (Ioffe and Szegedy 2015), rescales each channel to mean 0 and spread 1, then lets the network learn its own scale and shift:

Batch norm for one channel computes the mean and variance, normalizes, then scales and shifts.
μ = 1m Σ xi
The mean μ (mu) averages every value xi of this channel over the batch and all positions, and m counts them. Each channel gets its own mean, so each is centered on its own typical level.
σ² = 1m Σ (xi − μ)²
The variance σ² averages the squared distance of each value from μ. Squaring makes every distance positive and weights far values more, so the variance is large when the channel's values spread wide.
x̂i = xi − μ√σ² + ε
Subtracting μ centers the values on 0, and dividing by the spread, the square root of the variance, scales them to spread 1, so every channel lands in the same range whatever its raw size. x̂i is the normalized value, and the small constant ε (epsilon) keeps the division safe when a channel barely varies.
yi = γ · x̂i + β
The learned scale γ (gamma) and shift β (beta), one pair per channel, set the channel's final spread and center. With γ equal to the spread and β equal to μ, the layer undoes the normalization exactly, so normalizing never removes something the network needs.

Batch norm acts differently in training and at test time. On every training step it normalizes with that batch’s own mean and variance per channel, and also updates a running mean and variance per channel as a moving average that gives each new batch a share momentum of the weight. At test time (model.eval()) it uses the running values, so one image is normalized the same way every time, and the normalization becomes a fixed linear map that can be folded into the layer before it, so it costs nothing at inference.

Per channel it stores two learned numbers, γ and β, and two running values, and in training it adds one pass over the map for the statistics. Small batches make those statistics noisy. Group Norm (Wu and He 2018) normalizes within one image instead, so its error barely changes with the batch size (Figure 7).

242832363216842images per batcherror (%)batch normGroup Norm34.724.1① 10.6points
Figure 7. ResNet-50 on ImageNet (Group Norm paper, Table 2); ① the gap at 2 images.

A block may also end with dropout (Srivastava et al. 2014), which zeroes each value with probability p during training only (Regularization).

In a typical PyTorch block the convolution has no bias, because batch norm’s shift β does that job.

import torch
import torch.nn as nn

cfg = dict(padding=1, bias=False)
conv = nn.Conv2d(32, 64, 3, **cfg)
block = nn.Sequential(
    conv,
    nn.BatchNorm2d(64),
    nn.ReLU(),
    nn.Dropout2d(p=0.1),
)
x = torch.randn(8, 32, 56, 56)
y = block(x)
# train: batch stats, running
# stats updated in place
block.eval()
y = block(x)
# eval: running stats, no drop
bn = block[1]
print(bn.running_mean.shape)
# [64], one per channel
  1. 1A 3×3 convolution with no bias, then batch norm, ReLU and dropout; Dropout2d zeroes whole channels with probability p = 0.1.
  2. 2Training call: batch statistics, and the running statistics update.
  3. 3Test call: running statistics, dropout off.
  4. 4The running mean holds one value per channel.

4.1 Batch norm training speed

The batch norm paper trains Inception, the network from Section 3, and batch-normalized versions of it on ImageNet. BN-Baseline uses Inception's learning rate of 0.0015 (the step size, see optimizers); BN-x5 and BN-x30 use 5 and 30 times it; BN-x5-Sigmoid swaps ReLU for sigmoid. Batch norm reaches Inception's best accuracy, 72.2%, in 14 times fewer steps.

31.0M steps
40% 60% 80% 72.2% 0 10M 20M 31M steps
Figure 8. ① to ⑤ mark curve ends; ticks mark each 72.2% crossing.
40% 80% 72.2% 0 31M steps
Figure 9. A higher learning rate widens the gap (no plain curve at 5× or 30×).

5 ResNet

ResNet (He et al. 2016) adds each block's input back to the block's output, so networks with over a hundred layers still train. With this shortcut, a block that should change nothing only has to push its layers' output to zero, instead of learning an exact copy of its input:

A residual block outputs its input plus a learned change.
y = x + F(x)
The output y is the input x plus a change F(x), the residual, computed by the block's layers. The + is the skip connection: x passes through untouched, so a block whose layers output nothing still passes its input on, and gradients flow straight back through the + to earlier layers. Extra blocks can then only add changes, which is why very deep residual networks still train.
ResNet bottleneck blockin1×13×31×1
Figure 10. Bars are channel counts; the orange arc adds the input to the output.

ResNet-50 uses this bottleneck block: a 1×1 shrinks the channels, a 3×3 works on the narrow map, and a 1×1 widens it back. Its receptive field, 427 pixels in torchvision's layout, is worked out in Receptive Fields, Dilation and Causal Convolutions (receptive fields of real networks), and Transformer blocks use the same shortcut (the Transformer block).

A complete ResNet-50 bottleneck as torchvision builds it. Conv is Conv2d with bias=False, since batch norm follows every convolution; self.f is F(x) with i channels in and middle width m; the 3×3 carries the stride s, and the output is 4m wide.

import torch
import torch.nn as nn
from torch.nn import Conv2d
from functools import partial

Conv = partial(Conv2d, bias=False)

def conv_bn(i, o, k, s=1):
    c = Conv(i, o, k, s, k // 2)
    bn = nn.BatchNorm2d(o)
    return nn.Sequential(c, bn)

class Bottleneck(nn.Module):
    def __init__(self, i, m, s=1):
        super().__init__()
        o = 4 * m
        self.f = nn.Sequential(
            conv_bn(i, m, 1),
            nn.ReLU(),
            conv_bn(m, m, 3, s),
            nn.ReLU(),
            conv_bn(m, o, 1))
        # default: 1×1 projection
        skip = conv_bn(i, o, 1, s)
        if s == 1 and i == o:
            skip = nn.Identity()
        self.skip = skip

    def forward(self, x):
        h = self.f(x)  # F(x)
        y = h + self.skip(x)
        return torch.relu(y)

block = Bottleneck(64, 64)
x = torch.randn(1, 64, 56, 56)
print(block(x).shape)
# [1, 256, 56, 56]
  1. 1A convolution with no bias followed by batch norm, used for every layer.
  2. 2F(x), the bars of Figure 10: 1×1 narrow, 3×3 with the stride, 1×1 back to 4m.
  3. 3The shortcut: the identity when shapes match, otherwise a 1×1 projection.
  4. 4Adds the shortcut, y = x + F(x) from the card, then ReLU.
  5. 5The first block of stage 1: 64 channels in, 256 out.

The shortcut runs on every forward pass and adds no weights when shapes match, only one addition per value; inside the block the 3×3 holds half the weights (Figure 11). ResNet-50 stacks such blocks in four stages (Figure 12). torchvision’s zero_init_residual option starts each block’s last batch norm γ at 0, so every block begins as the identity; its source credits this with 0.2 to 0.3 points of accuracy. torchvision puts the stride on the 3×3, the layout often called ResNet v1.5; the original paper put it on the first 1×1 (torchvision resnet.py).

1×1 narrow4,0963×336,864 ①1×1 widen16,3841×1 shortcut16,38473,728 in all; about 231 million multiply-adds at 56×56
Figure 11. Weights per convolution of the code’s block; ① the 3×3 holds half.
mapchannels3 blocks56×562564 blocks28×285126 blocks14×141,0243 blocks7×72,048
Figure 12. ResNet-50 has 16 blocks in four stages, about 25.6 million weights (torchvision).

6 Training problems and fixes

Most of these failures come from a block on this page used in the wrong setting.

SymptomLikely causeFix
Accuracy drops with batches of 2 to 4 imagesStatistics from so few images are noisyGroup Norm, which normalizes each image on its own
Test results change with the batchBatch norm still in training modeCall model.eval()
A deeper plain network trains worseNo shortcut around the blocksResidual blocks

ResNet-50 holds about 25.6 million weights (Figure 12); how do you keep its accuracy on a phone with a fraction of them? Efficient CNNs: MobileNet and EfficientNet answers that.


7 References

  1. Krizhevsky, A., et al. (2012). ImageNet Classification with Deep Convolutional Neural Networks. NeurIPS.
  2. Nair, V., and Hinton, G. E. (2010). Rectified Linear Units Improve Restricted Boltzmann Machines. ICML.
  3. Simonyan, K., and Zisserman, A. (2015). Very Deep Convolutional Networks for Large-Scale Image Recognition. ICLR. arXiv:1409.1556.
  4. Lin, M., et al. (2014). Network in Network. ICLR.
  5. Szegedy, C., et al. (2015). Going Deeper with Convolutions. CVPR. arXiv:1409.4842.
  6. Ioffe, S., and Szegedy, C. (2015). Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift. ICML. arXiv:1502.03167. Figures 8 and 9 trace the paper's Figure 2; steps to 72.2% and each maximum come from the paper's Figure 3.
  7. He, K., et al. (2016). Deep Residual Learning for Image Recognition. CVPR. arXiv:1512.03385.
  8. Wu, Y., and He, K. (2018). Group Normalization. ECCV.
  9. Srivastava, N., et al. (2014). Dropout: A Simple Way to Prevent Neural Networks from Overfitting. JMLR 15, 1929 to 1958. jmlr.org.