RoboticsUnit 2 · Deep learning explosion · Day 11

Multi-Scale Context Aggregation by Dilated Convolutions

Space out a 3×3 filter's taps instead of shrinking the image. Each layer can see exponentially further while the output keeps full resolution, which is exactly what pixel-level prediction needs.

AuthorsFisher Yu (Princeton), Vladlen Koltun (Intel Labs)
Year / venue2016 · ICLR
Core ideaDilated convs for dense prediction
Study time2–4 h

Original: arXiv:1511.07122 · Code, notebook and exercises: 30u30 Day 11

Start here (no maths needed)

By spreading out the points a small filter looks at, a network can see a big area of the picture while still giving an answer for every single pixel.

Think of it like this

Imagine checking a big field for weeds through a cardboard tube. You only see a small circle. One way to see more is to stand further back, but then you miss small details. Another way is to look at nine points spread far apart, like a wider net. Do that in several rounds, each time with the points further apart, and soon you have covered the whole field without losing detail.

How it works

  1. A normal filter looks at a small 3-by-3 square of neighbouring pixels.
  2. A dilated filter looks at the same nine points, but with gaps between them.
  3. Layer after layer, the gaps double: 1, 2, 4, 8, 16.
  4. So the area each output pixel "sees" grows very fast, while the number of settings to learn grows slowly.
  5. The picture is never shrunk, so the network can label every pixel: road, person, car, and so on.

Why robots care

To pick up an object, a robot needs to know exactly which pixels belong to it, not just that it is "somewhere in the picture". Labelling every pixel is called segmentation. Good segmentation means the gripper closes on the cup, not on the table next to it.

Try it

Words to know

Pixel
One tiny dot of colour in a picture.
Receptive field
The patch of the input picture that one output pixel can "see".
Dilation
How far apart the filter's points are spread.
Segmentation
Giving every pixel in a picture a label.
Context
The surroundings that help you work out what something is.

Going deeper: everything below is the full version, with some maths. On a first read, skim the headings and the "Why it matters for robotics" box, and come back for the rest later.

1. Summary

TL;DR

Classification networks pool and stride until the whole image is one vector. Semantic segmentation needs a label for every pixel, so that lost resolution has to be recovered somehow. This paper avoids losing it. It uses dilated convolutions: the same 3×3 weights, applied to inputs spaced l pixels apart. Stack layers with dilation 1, 2, 4, 8, … and the receptive field grows exponentially while the parameter count grows only linearly, with no pooling at all. The authors build a plug-in context module from these layers. They also show that a VGG-16 with its last two pooling layers removed is simpler and more accurate for segmentation than the earlier adaptations.

2. The core idea

An ordinary discrete convolution and its dilated version, for a 2-D feature map F and a filter k:

(F ∗ k)(p)   = Σ_{s + t = p}     F(s) · k(t)
(F ∗_l k)(p) = Σ_{s + l·t = p}   F(s) · k(t)        # l = dilation factor

stacking 3×3 filters with dilation 2^i:
  F_{i+1} = F_i ∗_{2^i} k_i     →  receptive field of F_{i+1} = (2^{i+2} − 1)²

The paper notes that this operator appears in the wavelet "algorithme à trous", and explains why it prefers the name "dilated convolution": no dilated filter is ever stored.

3. Deep dive

Receptive fields, made concrete

Interactive: receptive field of a stack of 3×3 layers

The grid shows which input pixels feed the centre output pixel after the first n layers. Darker means more paths through the network. Pick a dilation schedule and step through its layers.

Receptive field
–
Pixels covered
–
Weights / channel pair
–

With the paper's schedule the receptive field after each layer is 3, 5, 9, 17, 33, 65 and 67 pixels wide, matching Table 1. Every pixel inside it is covered. Seven plain 3×3 layers reach only 15 pixels with the same 63 weights per channel pair. Repeating dilation 2 samples only every second row and column, so about 72% of its 17×17 field never contributes. This is the gridding problem, and it is why schedules start at dilation 1 and grow.

Why not just pool and upsample?

Pooling throws away where things are, and segmentation needs exactly that. Earlier systems either pooled hard and then learned to upsample, or ran the network on several rescaled copies of the image. Dilation gives large context and full resolution at once. The front end applies the same idea to VGG-16. The last two pooling and striding layers are deleted, and the convolutions after each deleted pool get dilation 2 (then 4). That keeps the pretrained weights usable and gives 64×64 output maps. The paper also removed padding of intermediate feature maps, another leftover from classification.

Making the context module train

The module maps C feature maps to C feature maps, so it can drop into any dense-prediction network. Random initialisation didn't work. The fix was to initialise every layer to pass its input straight through: the filter's centre tap is 1 on the matching channel and every other weight is 0. Backprop then learns to add context on top. This is the same "start at the identity" idea as ResNet (Day 09, Day 10), arrived at independently for a different reason.

Limitations, and what came after

4. Why it matters for robotics

5. How to study it

  1. Read the paper (8 pages, about 1 h). Sections 2 and 3 plus Table 1 are the core. Section 4 is the front-end cleanup.
  2. Use the demo above to predict each row of Table 1 before checking it.
  3. In the 30u30 Day 11 folder, read implementation.py: the dilated conv block, the context module, the receptive-field analyser and the ASPP head. Run train_minimal.py.
  4. Work through notebook.ipynb, then the exercises: receptive-field exploration, building the context module, ASPP, an ablation against pooling plus upsampling, and a WaveNet-style audio model.
  5. Stretch: train the context module with random init and with identity init, and compare. You should reproduce the paper's finding that random init struggles.

6. Self-check

How many weights does a 3×3 filter with dilation 4 have, and what span does it cover?

Still 9 weights per channel pair. It spans 9×9 pixels: 1 + 2·4.

What is the receptive field after 3×3 layers with dilations 1, 2, 4, 8?

1 + 2·(1 + 2 + 4 + 8) = 31 pixels across.

Why is dilation better than pooling for segmentation?

It grows context without lowering resolution, so you don't need to recover lost spatial detail with upsampling later.

What goes wrong with dilations 2, 2, 2, 2?

Only every second pixel is ever sampled, so the receptive field has holes. This is gridding.

Why identity initialisation?

Random init left the module unable to improve on its input. Starting from pass-through means the module begins harmless and learns to add context.

7. Further reading