CS6910 · Deep Learning · IIT Madras

Convolutional neural networks: from the convolution operation to ResNet

A convolution slides a small filter over its input, and a convolutional network learns those filters by backpropagation instead of hand-coding them. This lecture works out layer sizes and parameter counts from first principles, then follows the ImageNet architectures from LeNet and AlexNet through ZFNet and VGGNet to GoogLeNet and ResNet.

Lecture 8 Instructor Prof. Mitesh M. Khapra About 115 min of video 8 modules

At a glance

  • Convolution slides a small array of weights, the filter, over the input and replaces each position by a weighted sum of its neighbourhood. One filter over an image gives one feature map; \(K\) filters give \(K\) maps.
  • A filter always spans the full depth of its input, so it moves only across width and height. For a \(W_1 \times H_1 \times D_1\) input, \(K\) filters of size \(F \times F\), stride \(S\) and padding \(P\): \(W_2 = (W_1 - F + 2P)/S + 1\), likewise \(H_2\), and \(D_2 = K\).
  • A CNN learns its filters with backpropagation instead of using hand-made edge detectors or SIFT/HOG features. Sparse connectivity and weight sharing keep it small: LeNet's first layer has 150 weights where a dense layer between the same sizes would need about 800,000. Pooling shrinks each map and has no parameters.
  • On ImageNet the error fell from 25.8% (2011, hand-crafted features) to 16.4% with AlexNet (8 layers, 27.55M parameters), then 11.7% (ZFNet), 7.3% (VGGNet) and 6.7% (GoogLeNet). In AlexNet and VGGNet most parameters sit in the fully connected layers.
  • GoogLeNet runs 1×1, 3×3 and 5×5 convolutions and max pooling in parallel (the Inception module), cuts depth with 1×1 convolutions, and replaces the big fully connected layer by average pooling: 12 times fewer parameters than AlexNet. ResNet adds identity skip connections, \(H(\mathbf{x}) = F(\mathbf{x}) + \mathbf{x}\), which let a 152-layer network train and reach 3.57%.

Convolution as a weighted average in 1-D

The short M1 video sets the plan: the convolution operation, pooling, full convolutional networks and their parameter counts, and the standard architectures from LeNet to ResNet. The lecture itself starts with a tracking problem. A laser sensor reports the position of an aeroplane at discrete time steps, say every few seconds on a flight from Chennai to Delhi. The sensor is noisy, so one reading is not trusted on its own. A better estimate of the position at time \(t\) averages several past readings, and because the plane keeps moving, recent readings should count for more than old ones. That is a weighted average:

\[ s_t = \sum_{a=0}^{\infty} x_{t-a}\, w_{-a} = (\mathbf{x} * \mathbf{w})_t \]

\(\mathbf{x}\) is the input, the array of weights \(\mathbf{w}\) is the filter (also called the kernel), and the operation is convolution, written \(\mathbf{x} * \mathbf{w}\). Each weight is indexed by how far back it looks: \(w_0\) multiplies the current reading, \(w_{-1}\) the previous one, and so on.

Readings from long ago tell us little about where the plane is now, so in practice the sum runs over a small window. Using the last 7 readings, \(a = 0, \dots, 6\), the filter has 7 entries. To get the next estimate, slide the filter one step to the right and repeat the multiply-and-add.

\[ s_t = \sum_{a=0}^{6} x_{t-a}\, w_{-a}, \qquad s_6 = x_6 w_0 + x_5 w_{-1} + x_4 w_{-2} + x_3 w_{-3} + x_2 w_{-4} + x_1 w_{-5} + x_0 w_{-6} \]
t01234567891011
Reading \(x_t\)1.001.101.201.401.701.801.902.102.202.402.502.70
Filter for \(s_6\)0.010.010.020.020.040.40.5
\(s_t\) on the slide1.801.962.112.162.282.42
\(s_t\) recomputed1.811.972.112.272.412.57

The filter, from \(w_{-6}\) to \(w_0\), is 0.01, 0.01, 0.02, 0.02, 0.04, 0.4, 0.5. Its entries add up to 1, so each \(s_t\) is a true weighted average, and 90% of the weight is on the two latest readings. For \(s_6\):

\[ \begin{aligned} s_6 &= 1.90(0.5) + 1.80(0.4) + 1.70(0.04) + 1.40(0.02) + 1.20(0.02) + 1.10(0.01) + 1.00(0.01) \\ &= 0.95 + 0.72 + 0.068 + 0.028 + 0.024 + 0.011 + 0.010 = 1.811 \end{aligned} \]

Estimates start at \(t = 6\), the first step with 7 readings behind it. The last row recomputes every \(s_t\) from the slide's \(\mathbf{w}\) and \(\mathbf{x}\): the first three match the slide to within 0.01, and the slide's last three are a little lower than these weights give. The idea is unaffected.

The same story works for a camera. An image is a 2-D input, and if we are unsure of a pixel's value we can re-estimate it from a weighted average of its neighbourhood. The filter is now a 2-D array of size \(m \times n\), one weight per neighbour (in practice square, \(m = n\)). The textbook formula looks at the neighbours before pixel \((i, j)\):

\[ S_{ij} = (I * K)_{ij} = \sum_{a=0}^{m-1} \sum_{b=0}^{n-1} I_{i-a,\; j-b}\; K_{a,b} \]

It has \(m \times n\) terms, one per neighbour, each with its own weight from the kernel matrix \(K\). For pixel \((4, 4)\) the term with \(a = b = 1\) uses \(I_{3,3}\). Nothing forces us to look backwards. Different packages use different conventions, and the most common one looks at the neighbours after the pixel instead:

\[ S_{ij} = \sum_{a=0}^{m-1} \sum_{b=0}^{n-1} I_{i+a,\; j+b}\; K_{a,b} \]

A toy example makes this concrete. Place a \(2 \times 2\) kernel on the top-left corner of a \(3 \times 4\) input, multiply entry by entry and add. Then slide it one column right and repeat, and so on along each row:

\[ \begin{bmatrix} a & b & c & d \\ e & f & g & h \\ i & j & k & \ell \end{bmatrix} * \begin{bmatrix} w & x \\ y & z \end{bmatrix} = \begin{bmatrix} aw + bx + ey + fz & bw + cx + fy + gz & cw + dx + gy + hz \\ ew + fx + iy + jz & fw + gx + jy + kz & gw + hx + ky + \ell z \end{bmatrix} \]

The output (\(2 \times 3\)) is smaller than the input (\(3 \times 4\)). Module 11.2 explains exactly by how much. For the rest of the lecture the kernel is centred on the pixel of interest, so it looks at neighbours on both sides M2 · 10:30:

\[ S_{ij} = (I * K)_{ij} = \sum_{a=-\lfloor m/2 \rfloor}^{\lfloor m/2 \rfloor} \;\; \sum_{b=-\lfloor n/2 \rfloor}^{\lfloor n/2 \rfloor} I_{i-a,\; j-b}\; K_{\lfloor m/2 \rfloor + a,\; \lfloor n/2 \rfloor + b} \]

Standard name (not in the lecture): the "succeeding neighbours" version, with no flipping of the kernel, is what deep learning libraries actually compute. Mathematicians call it cross-correlation. Since the kernel is learned, the flip makes no difference to what a network can represent.

Three \(3 \times 3\) kernels show what a convolution can do to an image:

\[ \underbrace{\begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix}}_{\text{blurs}} \qquad \underbrace{\begin{bmatrix} 0 & -1 & 0 \\ -1 & 5 & -1 \\ 0 & -1 & 0 \end{bmatrix}}_{\text{sharpens}} \qquad \underbrace{\begin{bmatrix} 1 & 1 & 1 \\ 1 & -8 & 1 \\ 1 & 1 & 1 \end{bmatrix}}_{\text{detects edges}} \]
  • Blur. Every pixel is replaced by (a multiple of) the average of its \(3 \times 3\) neighbourhood, so sharp transitions are smoothed away.
  • Sharpen. Take 5 times the pixel and subtract its four neighbours. Where the neighbours are similar they cancel and the pixel stands out more.
  • Edge detector. Add the 8 neighbours and subtract 8 times the pixel. If all neighbours equal the pixel the result is 0; it is nonzero only where something changes, which is along the boundaries of objects.

The blur and sharpen buttons of photo-editing software apply exactly such convolutions across the whole image, and many other visual effects come from some convolution.

Sliding a kernel over the image gives one output value per placement. The resulting array is called a feature map, because each output summarizes some feature of its neighbourhood. In the edge-detector map, a dark (zero) pixel records the feature "this pixel does not lie on a boundary". The weights need not form an average at all. With several different kernels (one blurring, one sharpening, one detecting edges, …) we get several feature maps of the same input.

Three-dimensional inputs

A 1-D filter slides over a 1-D input and a 2-D filter over a 2-D input. A colour image is 3-D: three channels (R, G, B) of size \(m \times n\). The filter then becomes a box with a width, a height and a depth, a volume. Throughout this lecture its depth equals the depth of the input. So the filter can slide along the width and the height but not along the depth, and each placement gives one number. In effect it is a 2-D convolution on a 3-D input, and the output of one filter is 2-D. \(K\) filters give \(K\) such 2-D maps.

filter F × F × D₁ (full depth) W₁ H₁ D₁ input, e.g. RGB with D₁ = 3 one filter → one map W₂ H₂ sum of F·F·D₁ products per cell K filters W₂ H₂ D₂ = K K maps stacked: the output volume
A volume filter on a volume input. The filter's depth equals the input's, so it moves only across width and height and each placement produces one number. One filter gives one 2-D feature map; \(K\) filters give \(K\) maps, which stack into an output volume of depth \(K\).

If the filter were shallower than the input (depth 2 on a depth-3 input, say), it would also have to slide along the depth and the output would be 3-D. The lecture mentions this only to set it aside; every CNN here uses full-depth filters.

The sizes of inputs, filters and outputs decide the shapes of the matrices in the network, how many parameters it has and how much memory it needs. Module 11.2 makes them precise. The quantities are:

  • the input's width \(W_1\), height \(H_1\) and depth \(D_1\) (3 for an RGB image);
  • the stride \(S\), defined below;
  • the number of filters \(K\);
  • the spatial extent \(F\) of each filter, always square, so \(F \times F\), with depth equal to \(D_1\);
  • the output volume \(W_2 \times H_2 \times D_2\), which is what we want to compute.

No padding

Take a \(7 \times 7\) input and a \(3 \times 3\) filter centred on each pixel in turn. On a border pixel the filter would stick out of the image, where the values are undefined, so the filter cannot be placed there. The output loses one row and one column on each side and is \(5 \times 5\). A \(5 \times 5\) filter cannot be placed within 2 pixels of the border, so the output is \(3 \times 3\), smaller still. In general a filter of size \(F\) loses \(\lfloor F/2 \rfloor\) columns on each side, \(F - 1\) in total:

\[ W_2 = W_1 - F + 1, \qquad H_2 = H_1 - F + 1 \]

Padding

To keep the output as large as the input, add a border of zeros around the input. This is padding: \(P = 1\) adds one row of zeros at the top and bottom and one column at the left and right, which is exactly the strip a \(3 \times 3\) filter could not reach. The filter can now be placed on every original pixel. Each unit of padding adds 2 to the width (one column on each side):

\[ W_2 = W_1 - F + 2P + 1, \qquad H_2 = H_1 - F + 2P + 1 \]

A \(5 \times 5\) filter needs \(P = 2\) to keep the size: \(W_1 - 5 + 4 + 1 = W_1\).

Stride

The stride is the interval at which the filter is applied. So far the filter moved one pixel at a time (\(S = 1\)). With \(S = 2\) it skips every second position, which roughly halves the output's width and height; \(S = 4\) cuts them to about a quarter.

The size formula, and two exercises

Dividing by the stride gives the final formula for width and height. The depth is simpler: each filter produces one 2-D map, so \(K\) filters produce a volume of depth \(K\).

Output volume of a convolution layer \[ W_2 = \frac{W_1 - F + 2P}{S} + 1, \qquad H_2 = \frac{H_1 - F + 2P}{S} + 1, \qquad D_2 = K \]

Input \(W_1 \times H_1 \times D_1\); \(K\) filters, each \(F \times F \times D_1\); stride \(S\); zero padding \(P\) on every side.

The lecture notes that when \(W_1 - F + 2P\) is not a multiple of \(S\) the exact count involves a floor, and leaves the detail as an exercise. The usual convention (not stated in the lecture) is \(W_2 = \lfloor (W_1 - F + 2P)/S \rfloor + 1\): a last step that would cross the border is dropped.

ExerciseInputFiltersOutput
1\(227 \times 227 \times 3\)\(K = 96\), \(F = 11\), \(S = 4\), \(P = 0\)\(W_2 = H_2 = \frac{227 - 11}{4} + 1 = 55\), \(D_2 = 96\): 55 × 55 × 96
2\(32 \times 32 \times 1\)\(K = 6\), \(F = 5\), \(S = 1\), \(P = 0\)\(W_2 = H_2 = \frac{32 - 5}{1} + 1 = 28\), \(D_2 = 6\): 28 × 28 × 6

Neither exercise is random. The first is the first convolution layer of AlexNet and the second the first layer of LeNet-5; both networks come later in this lecture.

1 0
Output size W₂ × H₂–
(W₁ − F + 2P)/S + 1–
Current output–
Computed–
Sliding a filter over a 7 × 7 input. The input holds a bright square (6) and a dimmer band (2) on a dark background (0); dashed cells are zero padding. Each step places the kernel at the next position, multiplies entry by entry and adds, filling one output cell; click any output cell to jump to it. Change the stride and padding and the output size follows the formula above. The edge detector gives 0 on flat regions and inside the square, and large values along its boundary (with padding, the zeros outside the image also create edges at the border).

From hand-crafted features to learned filters

What does convolution have to do with neural networks? The lecture answers through image classification: assign an image to one of a few classes, here car, bus, monument and flower. There are three classical ways to set it up.

  1. Raw pixels. Flatten a \(20 \times 20\) image into a 400-dimensional vector and train any multi-class classifier on it.
  2. A hand-chosen filter. For these classes the shape of the object matters, while the sky, the lawn and the colour of the car do not. Running an edge detector first keeps the outlines and discards the rest, giving a more refined representation. The kernel was hand-coded from domain knowledge.
  3. Engineered features. Before 2012 the computer vision community designed ever better features. The most popular were SIFT and HOG, which describe how pixel gradients change across the image. Much work showed that they worked well on many image tasks.

In all three the feature extraction is static and deterministic. Learning happens only in the classifier on top, which is like training only the output (softmax) layer of a feedforward network. This is the machine learning recipe: engineer features, then learn a classifier.

An edge detector is just a small matrix, and a network is full of matrices that we learn. So the lecture asks a sequence of questions. Can we learn a meaningful kernel instead of hand-coding it? Can we learn several kernels, giving several representations of the input? Can we stack layers of kernels, each building a more abstract representation from the one below? The answer to all three is yes. Treat the kernels as parameters, alongside the classifier's weights, and train everything end to end with backpropagation on the classification loss (cross-entropy for this multi-class problem). Such a network is a convolutional neural network (CNN). In the lecture's framing, this is where deep learning parts from classical machine learning: the representation is learned, not hand-crafted.

How is a CNN different from a regular feedforward network? Take digit recognition (10 classes) on a tiny \(4 \times 4\) image. A feedforward network flattens it into 16 inputs, adds hidden layers and ends in 10 outputs. Every neuron in the first hidden layer, \(h_{11}\) for example, takes input from all 16 pixels: the connections are dense.

Now apply a \(2 \times 2\) convolution with stride 2. \(h_{11}\) is computed from pixels 1, 2, 5 and 6 only, and \(h_{12}\) from pixels 3, 4, 7 and 8. Only a few local inputs feed each output. This sparse connectivity uses what we know about images: the interactions between neighbouring pixels matter more than those between the top-left corner and the bottom-right corner. It also reduces the number of parameters.

Are we losing information by dropping interactions between distant pixels? Not really, because a CNN has several layers. With a window of 3 in the figure below, \(x_1\) and \(x_5\) do not meet in layer 1: no \(h\) depends on both. But \(g_3\) depends on \(h_2\), \(h_3\) and \(h_4\), which together depend on \(x_1, \dots, x_5\). So the two pixels interact one layer up. Early layers capture small neighbourhoods; later layers combine neighbourhoods of neighbourhoods, and eventually all pixels interact.

A 2 × 2 kernel, stride 2 1234 5678 9101112 13141516 h₁₁h₁₂h₂₁h₂₂ output h₁₁ uses pixels 1, 2, 5, 6; h₁₂ uses 3, 4, 7, 8. A dense layer would feed all 16 pixels to every h. Window of 3: interactions appear one layer up g₁g₂g₃g₄g₅ h₁h₂h₃h₄h₅ x₁x₂x₃x₄x₅ layer 2 layer 1 input x₁ and x₅ share no unit in layer 1, but both reach g₃ (via h₂ and h₄).
Local connections, global reach. Left: with a \(2 \times 2\) kernel and stride 2, each output depends on just 4 of the 16 pixels. Right (after the figure in Goodfellow et al., 2016, which the slide uses): each unit sees 3 units below it. Two pixels that never share a unit in layer 1 still combine in layer 2, so depth recovers the long-range interactions that sparsity removed.

Standard name (not in the lecture): the set of input pixels that can affect a unit is its receptive field. Here the receptive field of \(g_3\) is \(x_1, \dots, x_5\).

The second property of a CNN concerns the kernel's values. Suppose one \(2 \times 2\) kernel sits on pixels 1, 2, 5, 6 of the \(4 \times 4\) image and another on pixels 11, 12, 15, 16. Should their weights differ? Think about what a filter is for. A kernel that detects edges must have the same configuration wherever it is applied, since an edge looks the same in any part of the image. The blur, sharpen and edge kernels earlier were all applied unchanged at every location.

So a CNN uses the same kernel at every position. This is weight sharing, and it makes learning easier: the network does not have to learn the same weights again and again at different locations. (Lecture 6 met the general idea as parameter sharing; see Lecture 6.)

With a single shared \(2 \times 2\) kernel, layer 1 would have only 4 weights, far too few: the model would underfit. The fix is to use many kernels, each shared across all locations. With \(K\) kernels the layer has \(4K\) weights and produces \(K\) feature maps.

A CNN layer differs from a dense layer in two ways: each output sees only a local window (sparse connectivity), and every window uses the same kernel (weight sharing).

A full CNN: convolution, pooling, fully connected

A complete network for handwritten character recognition (LeNet-5, next section) shows the overall pattern. The 2-D input image goes through a convolution layer with 6 filters, giving 6 feature maps. A pooling layer shrinks each map. The 6 shrunken maps form a volume, which is the input to the next convolution layer: 16 full-depth filters give 16 maps, one 2-D map per filter. Another pooling layer follows, and finally a few fully connected layers lead to the output. Each stage's output is the next stage's input, as with hidden layers in a feedforward network.

So a CNN alternates convolution and pooling layers. A pooling layer works on one feature map at a time. Max pooling with a \(2 \times 2\) filter and stride 2 looks at each \(2 \times 2\) block and keeps only its largest value. Each block becomes one number, which halves both width and height (a quarter of the values survive). With stride 1 the windows overlap and the map shrinks less. Average pooling keeps the mean of the window instead of the maximum.

One 4 × 4 feature map 1421 5834 7645 1312 2 × 2, stride 2 2 × 2, stride 1 8475 2 × 2 output each block keeps its max: width and height halve 884 885 765 3 × 3 output windows overlap, so it shrinks less
Max pooling, the slide's example. The highlighted top-left window \(\{1, 4, 5, 8\}\) gives 8 in both outputs. With stride 2 the four blocks tile the map and give rows (8, 4) and (7, 5); with stride 1 the window visits 9 overlapping positions.

Pooling has no parameters: there is no weight matrix and no \(\mathbf{w}^\top\mathbf{x}\), just a fixed max (or average). It also leaves the depth unchanged, since it never takes a max across feature maps.

LeNet-5 (from around 1997–98, already the fifth version) recognizes handwritten characters from a \(32 \times 32\) grey-scale image. Work out each layer with the size formula; a convolution filter has \(F \times F \times D_1\) weights, where \(D_1\) is the depth of that layer's input.

LayerSettingsOutput volumeParametersHow
Input32 × 32 × 1–
Conv 1K = 6, F = 5, S = 1, P = 028 × 28 × 61506 × (5 × 5 × 1)
Pool 1max, F = 2, S = 214 × 14 × 60no weights
Conv 2K = 16, F = 5, S = 1, P = 010 × 10 × 162,40016 × (5 × 5 × 6)
Pool 2max, F = 2, S = 25 × 5 × 160no weights
FC 1flatten 5 × 5 × 16 = 400 → 12012048,120400 × 120 + 120 biases
FC 2120 → 848410,164120 × 84 + 84
Output84 → 101085084 × 10 + 10
  • Depth counts. In class the first answer for Conv 2 was \(16 \times 25 = 400\). That forgets that each \(5 \times 5\) filter also spans the 6 maps of its input, so it has \(5 \times 5 \times 6 = 150\) weights, and 16 of them make 2,400.
  • Slide corrections. The slide lists the pooling layers with \(S = 1\); to go from 28 to 14 the stride must be 2, as the lecturer points out. The slide's output layer has 10 units; for alphabet recognition it would be 26, giving \(84 \times 26 + 26\) parameters. The convolution counts on the slide leave out biases; the fully connected counts include them.
  • A fully connected layer flattens the \(5 \times 5 \times 16\) volume into one 400-vector and connects every entry to every one of the 120 units, as in an ordinary feedforward network.

Compare Conv 1 with a dense layer between the same sizes. The input has \(32 \times 32 = 1024\) values and the output \(28 \times 28 = 784\), so a fully connected layer would need \(1024 \times 784 = 802{,}816\) weights against 150 here. Sparse connectivity and weight sharing together make the difference. This is why CNNs with 4 or 5 layers could be trained even before the deep learning revival of 2006 (Lecture 7): they had far fewer parameters than dense networks.

The table also shows a pattern that returns in every network below: the fully connected layers dominate. The convolution layers have hundreds or thousands of parameters; the first fully connected layer alone has 48,120.

For any CNN, you should be able to say for each layer: the input volume, the output volume, the number of filters and the number of parameters.

Training a CNN with backpropagation

Backpropagating through a convolution looks daunting, but a CNN can be written as a feedforward network in which only a few weights are active and the rest are fixed at zero. Take a \(3 \times 3\) input and a \(2 \times 2\) kernel:

\[ l = bw + cx + ey + fz, \qquad m = cw + dx + fy + gz, \qquad n = ew + fx + hy + iz, \qquad o = fw + gx + iy + jz \]
Input bcdefghij Kernel wxyz l = bw + cx + ey + fz, and likewise for m, n, o lmno bcdefghij w x y z each weight is used 4 times
A convolution is a sparse, weight-tied feedforward layer. Each output connects to only 4 of the 9 inputs; the 20 missing edges are weights fixed at zero. The 16 edges that exist carry just 4 distinct values, one line style per kernel weight. Backpropagation runs on this network exactly as on any other.

Seen this way, nothing new is needed. Training a network with some connections switched off is familiar from dropout (Lecture 6), and backpropagation (Lecture 4) applies unchanged, with some careful coding to keep the absent weights out. In practice nobody builds the dense version, which would waste exactly the computation that sparse connections save. Instead the convolution and its derivative are defined directly, and frameworks such as TensorFlow and PyTorch compute the backward pass automatically from the forward convolution. Conceptually it is still the same backpropagation algorithm.

Completing the idea (not worked out in the lecture): because \(w\) multiplies a different input in each of the four outputs, its gradient adds up the four contributions, \(\dfrac{\partial \mathcal{L}}{\partial w} = b\,\dfrac{\partial \mathcal{L}}{\partial l} + c\,\dfrac{\partial \mathcal{L}}{\partial m} + e\,\dfrac{\partial \mathcal{L}}{\partial n} + f\,\dfrac{\partial \mathcal{L}}{\partial o}\). A shared weight always collects gradient from every place it is used.

The lecture raises one more point and leaves it open: is everything in a CNN differentiable? In particular, how does the gradient pass through a max pooling layer?

Not in the lecture: max is differentiable almost everywhere. Within each window, the output equals one input (the largest), so the gradient flows back to that input unchanged and the other inputs in the window get zero. For average pooling each input in the window gets \(1/F^2\) of the gradient.

The competition that made CNNs famous in 2012 is the ImageNet Large Scale Visual Recognition Challenge (ILSVRC). It uses 1000 categories of the ImageNet data set, with roughly a million training images. In 2010 and 2011 the entries were classical: extract SIFT or HOG features, train classifiers on top, and add ensembles and other tricks. An error of 28.2% means about 282 mistakes on 1000 test images.

error (%) 0 10 20 30 28.225.816.411.77.36.73.57 2010201120122013201420142015 shallowshallowAlexNetZFNetVGGGoogLeNetResNet 8 layers8 layers19 layers22 layers152 layers
ILSVRC winning error by year, as on the slide (grey: hand-crafted features; violet: CNNs). AlexNet cut the winning error from 25.8% to 16.4%; the lecture notes it was 8 to 9 points ahead of the next-best entry that year. Networks then grew deeper every year, from 8 layers to 152.

The rest of the lecture walks through these winners: AlexNet, ZFNet and VGGNet in this module, GoogLeNet and ResNet in the next. ResNet's 3.57% is what prompted claims that CNNs beat humans at this task. A person shown the same 1000 images would also make more than about 3.5% errors, since some images are blurred and some classes, such as dog breeds, are hard to tell apart.

Not in the lecture: these are the challenge's top-5 error rates. A prediction counts as correct if the true label is among the model's five highest-scoring classes.

AlexNet takes a \(227 \times 227 \times 3\) RGB image. The first layer is Exercise 1 from Module 11.2. The slides compute every layer with the size formula; the parameter count of a convolution layer is \((F \times F \times D_1) \times K\), biases left out.

LayerSettingsOutput volumeParameters (slide)
Input227 × 227 × 3–
Conv 1K = 96, F = 11, S = 4, P = 055 × 55 × 96(11 × 11 × 3) × 96 = 34K
Max pool 1F = 3, S = 227 × 27 × 960
Conv 2K = 256, F = 5, S = 1, P = 023 × 23 × 256(5 × 5 × 96) × 256 = 0.6M
Max pool 2F = 3, S = 211 × 11 × 2560
Conv 3K = 384, F = 3, S = 1, P = 09 × 9 × 384(3 × 3 × 256) × 384 = 0.8M
Conv 4K = 384, F = 3, S = 1, P = 07 × 7 × 384(3 × 3 × 384) × 384 = 1.327M
Conv 5K = 256, F = 3, S = 1, P = 05 × 5 × 256(3 × 3 × 384) × 256 = 0.8M
Max pool 3F = 3, S = 22 × 2 × 2560
FC 1flatten 2 × 2 × 256 = 1024 → 40964096(2 × 2 × 256) × 4096 = 4M
FC 24096 → 409640964096 × 4096 = 16M
FC 34096 → 1000 classes10004096 × 1000 = 4M
Total27.55M
  • Shrinking width, growing depth. From \(227 \times 227 \times 3\) the maps shrink to \(27 \times 27 \times 96\) after the first pooling, while the depth grows because more filters capture more patterns. Pooling leaves depth unchanged and has no parameters.
  • Eight layers. AlexNet is called an 8-layer network although the table has 12 rows. Only layers with parameters are counted: 5 convolution layers and 3 fully connected layers.
  • Where the parameters are. About 24M of the 27.55M (4M + 16M + 4M) are in the fully connected layers.
  • Why shrink at all? Pooling and large strides bring \(227 \times 227\) down to \(2 \times 2\) before the fully connected layers. Without them we would be left with maps of order \(200 \times 200\), and a fully connected layer on top would be infeasible, throwing away the savings of sparse connectivity and weight sharing. (Fully convolutional networks with no max pooling also work, the lecture adds; VGGNet below uses long runs of convolutions with few pooling layers.)
  • Why this configuration? Nobody really knows. The kernel sizes and filter counts are hyperparameters, presumably chosen by trying many settings on a validation set. Some choices look sensible: large filters on the full image, smaller ones once it has shrunk. Others, such as three convolution layers back to back, have no clear rationale.
  • Engineering. Every convolution is followed by a ReLU, applied to each entry of the feature map. The lecture credits AlexNet with bringing ReLU to CNNs in place of sigmoid or tanh (see Lecture 7). Training it in 2012 took many tricks, including splitting the network across GPUs, which is part of why it came two years after the challenge began.

Arithmetic check (not in the lecture): Conv 3 and Conv 5 each have \(3 \times 3 \times 256 \times 384 = 884{,}736 \approx 0.88\)M weights. The slide's 27.55M is the sum of the rounded per-layer figures; the exact products add up to about 28.8M. Also, the published AlexNet pads some of its convolutions, so its later maps are larger than these; the lecture's version uses \(P = 0\) throughout.

ZFNet is AlexNet with a few changes, so the lecture presents it as a layer-by-layer diff. The slide numbers the layers 1 to 10 from Conv 1 to FC 2, pooling layers included. The input is the same \(227 \times 227 \times 3\).

LayerChange from AlexNetDifference in parameters
1 (Conv 1)F = 11 → 7\((11^2 - 7^2) \times 3 \times 96 = 20.7\)K fewer
2–4none–
5 (Conv 3)K = 384 → 512\((3 \times 3 \times 256) \times (512 - 384) = 0.29\)M more
6 (Conv 4)K = 384 → 1024\(3 \times 3 \times (512 \times 1024 - 384 \times 384)\); slide: 0.8M
7 (Conv 5)K = 256 → 512\(3 \times 3 \times (1024 \times 512 - 384 \times 256)\); slide: 0.36M
8–10none–
Total1.45M more (slide)

The reasoning behind the first change: an \(11 \times 11\) neighbourhood is more than needed, though \(3 \times 3\) may be too small, so \(7 \times 7\) is a compromise. It also removes a few parameters. The deeper layers get more filters (512, 1024, 512 instead of 384, 384, 256), so ZFNet has more parameters than AlexNet overall. The error fell from 16.4% to 11.7%. The pooling and fully connected layers are unchanged, and like AlexNet it has 8 layers with parameters.

Arithmetic check (not in the lecture): the slide writes the layer 6 and 7 differences as AlexNet minus ZFNet and evaluates them to 0.8M and 0.36M. The products actually come to \(9 \times 376{,}832 \approx 3.39\)M and \(9 \times 425{,}984 \approx 3.83\)M, so the convolution layers add about 7.5M, not 1.45M. Two side effects of the changes are also missing from the slide: with \(F = 7\) and \(S = 4\) the formula gives \((227 - 7)/4 + 1 = 56\), not 55; and with 512 maps of size \(2 \times 2\) at the end, FC 1 would have \(2048 \times 4096\) weights, twice AlexNet's.

VGGNet's distinctive choice is to use \(3 \times 3\) kernels in every convolution layer, from the first to the last, and to stack them in runs between max pooling layers. The slide's figure takes a \(224 \times 224 \times 3\) input. The convolutions keep the width and height (so they must use padding \(P = 1\)), and each max pooling halves them.

BlockLayersMaps after the convolutionsAfter max pooling
12 × conv 3×3, 64 filters224 × 224 × 64112 × 112 × 64
22 × conv 3×3, 128 filters112 × 112 × 12856 × 56 × 128
33 × conv 3×3, 256 filters56 × 56 × 25628 × 28 × 256
43 × conv 3×3, 512 filters28 × 28 × 51214 × 14 × 512
53 × conv 3×3, 512 filters14 × 14 × 5127 × 7 × 512
FC4096, 4096, then 1000-way softmaxinput: 7 × 7 × 512 flattened

That is 13 convolution layers and 3 fully connected layers, 16 layers with parameters: VGG-16. A later variant with 19 such layers is VGG-19. As with AlexNet, there is little intuition for why 16; the architecture is whatever gave the best ImageNet accuracy.

VGGNet's parameters (slide) \[ \underbrace{\sim 16\text{M}}_{\text{non-FC layers}} \qquad \underbrace{(512 \times 7 \times 7 \times 4096) + (4096 \times 4096) + (4096 \times 1024) \approx 122\text{M}}_{\text{FC layers}} \]

Most of it, about 102M, is in the first fully connected layer.

The first fully connected layer is the problem. AlexNet and ZFNet ended with a \(2 \times 2 \times 256\) volume, a 1024-vector. VGGNet ends with \(7 \times 7 \times 512 = 25{,}088\) values, about 25 times more, and connecting each of them to 4096 units costs over 100 million weights. A very deep stack of convolutions holds far fewer parameters than this one layer.

The slide writes the last factor as 1024; with 1000 output classes it is \(4096 \times 1000\). The three terms are about 102.8M, 16.8M and 4.1M, so either way the total is near 123M.

Trained CNNs as feature extractors

The short M7 video adds a point used in the next lecture. Once a network such as AlexNet or VGGNet has been trained on ImageNet (cross-entropy tracked over epochs until the training error is satisfactory), the output of any of its layers, flattened into a vector, is an abstract representation of the input image. So it is common to pass a new image through a network trained on ImageNet, take the vector from a fully connected layer (an "fc representation") or a convolution layer (a "conv representation"), and use it for some other image task. Lecture 9 looks inside these representations.

Consider the output volume at some layer in the middle of a CNN. Next we could apply max pooling, or a \(1 \times 1\), \(3 \times 3\) or \(5 \times 5\) convolution. Every network so far made one uniform choice per layer. But interactions may matter at several scales at once, so GoogLeNet asks: why choose? Apply all of them in parallel and concatenate the resulting feature maps.

Done naively this is expensive. With \(P = 0\) and \(S = 1\), convolving a \(W \times H \times D\) input with an \(F \times F \times D\) filter gives a \((W - F + 1) \times (H - F + 1)\) map, and each entry needs \(O(F \times F \times D)\) multiply-adds:

\[ \underbrace{(W - F + 1)(H - F + 1)}_{\text{entries per filter}} \;\times\; \underbrace{O(F \times F \times D)}_{\text{work per entry}} \]

1×1 convolutions

The fix is the 1×1 convolution. On a single pixel it might seem to do nothing, but remember a filter spans the full depth: a \(1 \times 1\) filter is really \(1 \times 1 \times D\), and it combines the \(D\) values at one location into one number. It aggregates along the depth. Using \(D_1 < D\) such filters (\(S = 1\), \(P = 0\)) turns a \(W \times H \times D\) volume into \(W \times H \times D_1\): the width and height stay, the depth shrinks. A following \(F \times F\) convolution then costs \(O(F \times F \times D_1)\) per entry instead of \(O(F \times F \times D)\).

The 3×3 and 5×5 branches may want different reductions, so each gets its own set of \(1 \times 1\) filters, \(D_1\) before the \(3 \times 3\) and \(D_2\) before the \(5 \times 5\). That adds a little computation, but the trade-off is acceptable. Add a \(3 \times 3\) max pooling branch followed by its own \(1 \times 1\) convolutions, and a plain \(1 \times 1\) branch, and concatenate the four outputs along the depth. This block is the Inception module. Each branch is padded so that all four outputs have the same width and height and can be stacked. Earlier networks were purely serial; an Inception module runs several operations in parallel inside a serial chain.

filter concatenation 28 × 28 × (64 + 128 + 32 + 32) = 28 × 28 × 256 1×1 conv, 64 3×3 conv, 128 on reduced input 5×5 conv, 32 on reduced input 1×1 conv, 32 reduce depth 1×1 conv, 96 reduce depth 1×1 conv, 16 reduce depth 3×3 max pool stride 1, padded previous layer: 28 × 28 × 192 641283232
Inception module 3a of GoogLeNet, with the slide's numbers. Four branches see the same input. The 1×1 convolutions in front of the 3×3 and 5×5 branches cut the depth from 192 to 96 and 16, so the expensive filters run on thin volumes. The four outputs keep the 28 × 28 size and are stacked to depth 256.

Worked numbers (not in the lecture): for the 5×5 branch of module 3a, 32 filters of size \(5 \times 5 \times 192\) on the \(28 \times 28\) map cost \(784 \times 32 \times 4800 \approx 120\)M multiplications. With 16 reducing \(1 \times 1\) filters first, the cost is \(784 \times 16 \times 192 \approx 2.4\)M for the reduction plus \(784 \times 32 \times 400 \approx 10\)M for the 5×5, about 12M in all: ten times less.

The lecture stresses that only two ideas here are profound: apply filters of several sizes in parallel, and use \(1 \times 1\) convolutions to keep the computation manageable. The rest is bookkeeping.

GoogLeNet (also called Inception Net) chains many Inception modules. On the slide's figure, an RGB input (229 × 229 on the slide; the lecture says 227 or 229) passes through:

  1. GoogLeNet, as on the slide
  2. Convolution with 64 filters → 112 × 112 × 64, then max pooling → 56 × 56 × 64.
  3. Convolution with 192 filters → 56 × 56 × 192, then max pooling → 28 × 28 × 192.
  4. Inception 3a (→ 256) and 3b (→ 480) at 28 × 28, then max pooling → 14 × 14 × 480.
  5. Inception 4a, 4b, 4c (→ 512 each), 4d (→ 528) and 4e (→ 832) at 14 × 14, then max pooling → 7 × 7 × 832.
  6. Inception 5a (→ 832) and 5b (→ 1024) at 7 × 7.
  7. Average pooling over each 7 × 7 map → 1024 values, dropout (40%), a fully connected layer to 1000 units, softmax.
Module1×11×1 reduce → 3×31×1 reduce → 5×5pool → 1×1Output depth
3a6496 → 12816 → 3232256
3b128128 → 19232 → 9664480
4a19296 → 20816 → 4864512
4b160112 → 22424 → 6464512
4c128128 → 25624 → 6464512
4d112144 → 28832 → 6464528
4e256160 → 32032 → 128128832
5a256160 → 32032 → 128128832
5b384192 → 38448 → 1281281024

The output depth of each module is the sum of its four branches, for example \(128 + 192 + 96 + 64 = 480\) for 3b. As with the earlier networks, the lecture sees little intuition behind these particular numbers; they are presumably what worked best.

Getting rid of the big fully connected layer

The last Inception module outputs \(7 \times 7 \times 1024\). Flattening it and connecting it to 1000 output units would take \(7 \times 7 \times 1024 \times 1000 = 50{,}176{,}000\) weights (49M on the slide), the same blow-up as in VGGNet. Instead, GoogLeNet averages each of the 1024 feature maps over its \(7 \times 7\) grid, which leaves a 1024-dimensional vector. The output weight matrix becomes \(W \in \mathbb{R}^{1024 \times 1000}\), and the input to the dense layer is 49 times smaller.

GoogLeNet vs AlexNet (slide)

12× fewer parameters, 2× more computation.

Most of the saving comes from dropping the fully connected layer. The Inception modules themselves add parameters; removing the dense layer is what makes them affordable. Twice AlexNet's computation is an acceptable price for a much deeper network: the lecturer counts 14 stages in the figure, each Inception module itself a split layer with parallel branches, and the chart above lists 22 layers. GoogLeNet was also more accurate than AlexNet, ZFNet and VGGNet (6.7% against VGGNet's 7.3%).

Three takeaways from GoogLeNet: filters of several sizes in parallel, 1×1 convolutions to cut computation, and average pooling to avoid a huge fully connected layer.

Suppose a shallow network (shallow is relative: say 8 layers) trains well, reaching near-zero training error and reasonable test accuracy. Now insert a few more layers. Intuitively the deeper network should do at least as well, because one of its possible solutions copies the shallow one: let the new layers compute the identity. The solution space of the shallow network is a subset of the deeper network's.

In practice this does not happen. On CIFAR-10, plain networks of 20, 32, 44 and 56 layers get worse as they get deeper: the 56-layer network has the highest error, on both the training set and the test set. The lecture points to the training error: the deeper networks fit even the training data worse. The argument above relied on the network finding the identity mapping, but that is one solution among a huge number, a needle in a haystack. Obvious to us, it is not easy for gradient-based training to land on.

So make the identity explicit. Two stacked convolution layers take \(\mathbf{x}\) and learn some function \(H(\mathbf{x})\). Instead, let them learn only a residual \(F(\mathbf{x})\), and add the input back through a direct connection:

Residual block \[ H(\mathbf{x}) = F(\mathbf{x}) + \mathbf{x} \]

The identity (skip) connection carries a copy of the input past every two layers (or three), so the network always retains it.

Plain: learn H(x) directly x conv layer relu conv layer relu H(x) the layers must build H(x) from scratch Residual: learn F(x), add x x conv layer relu conv layer F(x) relu identity: x + H(x) = F(x) + x
A plain block and a residual block, after the slide. With the skip connection, the two layers only have to model the difference between the desired output and the input. If the best thing these layers can do is nothing, they only need to drive \(F(\mathbf{x})\) towards zero.

This follows the earlier argument: a deeper copy of a working shallow network should be fine if its new layers can pass the input through, and the identity connection hands them that copy. With these skip connections the authors trained networks of 152 layers. The last sentence of the figure caption is the standard intuition, not stated in this form in the lecture: pushing a residual towards zero is easier for an optimizer than assembling an identity map from scratch.

ResNet took first place in all five main tracks of the 2015 ImageNet and COCO challenges:

  • ImageNet classification: "ultra-deep" 152-layer networks, 3.57% error;
  • ImageNet detection: 16% better than the second-best system;
  • ImageNet localization (finding where the object is): 27% better;
  • COCO detection: 11% better; COCO segmentation: 12% better.

The downside is a very deep network that takes a long time to train, affordable mainly with very large computing resources.

The bag of tricks

The paper's training details, as listed on the slide (most were covered in earlier lectures):

  • batch normalization after every convolution layer (Lecture 7);
  • "Xavier/2" initialization, which is He initialization (Lecture 7);
  • plain SGD with momentum 0.9, no Adam or Adagrad (Lecture 5);
  • learning rate 0.1, divided by 10 whenever the validation error plateaus;
  • mini-batch size 256;
  • weight decay of \(10^{-5}\), that is, L2 regularization with \(\lambda = 10^{-5}\) (Lecture 6);
  • no dropout.

These are hyperparameters, separate from the model's parameters. The lecture's advice for reading deep learning papers: study the experimental section where such details are given. Without them you will often fail to reproduce a paper's results even with the architecture coded correctly; with them the chances are much better, though still not guaranteed.

The ImageNet networks side by side

NetworkILSVRCErrorLayersParameters (slides)Key idea
AlexNet201216.4%827.55M, ~24M in FCa deep CNN with ReLU; 11×11 filters, stride 4
ZFNet201311.7%8more than AlexNet7×7 first filters; more filters in deeper layers
VGGNet20147.3%16 / 19~16M + ~122M in FC3×3 filters throughout, many layers
GoogLeNet20146.7%2212× fewer than AlexNetInception modules, 1×1 reductions, average pooling
ResNet20153.57%152not givenresidual (skip) connections

Key terms

Convolution
Sliding a filter over the input and taking, at each position, the sum of entry-wise products with the window under it.
Filter (kernel)
The small array of weights that is slid over the input; in a CNN its values are learned.
Feature map
The 2-D output of one filter over the whole input; \(K\) filters give \(K\) maps.
Volume filter
A filter of size \(F \times F \times D_1\) spanning the input's full depth, so it slides over width and height only.
Stride \(S\)
The step between successive placements of the filter; larger strides shrink the output.
Padding \(P\)
Rings of zeros around the input so the filter can also be placed on border pixels.
Output size
\(W_2 = (W_1 - F + 2P)/S + 1\), same for \(H_2\), and \(D_2 = K\).
Sparse connectivity
Each output depends only on a small local window of the input, not on every input.
Weight sharing
The same kernel weights are used at every location of the input.
Max / average pooling
A parameter-free layer that replaces each window of a feature map by its maximum or mean, map by map.
Fully connected layer
A dense layer on the flattened volume; in AlexNet and VGGNet it holds most of the parameters.
1×1 convolution
A \(1 \times 1 \times D\) filter that combines values across depth; \(D_1 < D\) of them reduce the depth.
Inception module
Parallel 1×1, 3×3, 5×5 convolutions and max pooling, with 1×1 reductions, concatenated along depth.
Residual connection
A skip connection that adds a block's input to its output: \(H(\mathbf{x}) = F(\mathbf{x}) + \mathbf{x}\).

Test yourself

Q1A \(64 \times 64 \times 3\) input goes through 16 filters of size \(5 \times 5\) with stride 1 and padding 2. What is the output volume, and how many weights does the layer have (ignoring biases)?

\(W_2 = H_2 = (64 - 5 + 4)/1 + 1 = 64\) and \(D_2 = K = 16\), so \(64 \times 64 \times 16\). Each filter is \(5 \times 5 \times 3 = 75\) weights, so \(16 \times 75 = 1200\) in all.

Q2With stride 1, how much padding keeps the output the same size as the input for a \(7 \times 7\) filter?

We need \(W_1 - 7 + 2P + 1 = W_1\), so \(2P = 6\) and \(P = 3\). In general \(P = (F - 1)/2\) for odd \(F\).

Q3Apply \(2 \times 2\) max pooling with stride 2 to the map with rows \((2, 0, 1, 3)\), \((4, 6, 5, 1)\), \((0, 1, 2, 2)\), \((3, 7, 1, 0)\). How many parameters does the layer have?

The four blocks are \(\{2, 0, 4, 6\}\), \(\{1, 3, 5, 1\}\), \(\{0, 1, 3, 7\}\), \(\{2, 2, 1, 0\}\), so the output is \(\begin{bmatrix} 6 & 5 \\ 7 & 2 \end{bmatrix}\). Pooling applies a fixed max, so it has no parameters.

Q4In LeNet-5, the second convolution layer has 16 filters of size \(5 \times 5\). Why does it have 2,400 weights and not 400?

Its input is the \(14 \times 14 \times 6\) output of the first pooling layer, and every filter spans the full depth. So each filter is \(5 \times 5 \times 6 = 150\) weights, and \(16 \times 150 = 2400\).

Q5Each unit sees 3 adjacent units in the layer below. Do inputs \(x_1\) and \(x_5\) ever influence the same unit, and if so, where?

Not in layer 1: a unit there covers 3 consecutive inputs, and \(x_1\) to \(x_5\) span 5. In layer 2, \(g_3\) sees \(h_2, h_3, h_4\), which together cover \(x_1, \dots, x_5\). Sparse connections lose nothing once the network is deep enough.

Q6Why does VGGNet's first fully connected layer have about 102M parameters, while AlexNet's has about 4M?

VGGNet's last pooled volume is \(7 \times 7 \times 512 = 25{,}088\) values, against AlexNet's \(2 \times 2 \times 256 = 1024\). Each value connects to 4096 units: \(25{,}088 \times 4096 \approx 102.8\)M versus \(1024 \times 4096 \approx 4.2\)M.

Q7What does a layer of 16 \(1 \times 1\) convolutions do to a \(28 \times 28 \times 192\) volume, and how many weights does it have?

Each filter is \(1 \times 1 \times 192\) and combines the 192 values at one location into one number. The output is \(28 \times 28 \times 16\): same width and height, depth cut from 192 to 16. It has \(16 \times 192 = 3072\) weights. A following \(5 \times 5\) convolution then costs \(5 \times 5 \times 16\) instead of \(5 \times 5 \times 192\) per output.

Q8Deeper plain networks got higher training error than shallower ones. How does a residual block address this?

A deeper network could in principle copy a shallower one by making its extra layers the identity, but training rarely finds that solution. A residual block computes \(F(\mathbf{x}) + \mathbf{x}\), so the identity is built in through the skip connection, and the layers only learn a correction. This let ResNet train 152 layers and reach 3.57% on ImageNet.