Dilated Convolution Widens View Without Weights
Dilation spreads a small kernel over a wider area by skipping cells, so one layer sees far without extra weights and without shrinking the image.
Why Does This Exist?
Dense tasks such as segmentation need two things at once: wide context (is this pixel road or sidewalk depends on the whole street) and full resolution (the boundary must land on the exact pixel). Pooling gives width by shrinking the map, which destroys the boundaries the task must output. Larger kernels give width by adding weights quadratically.
Dilation gives width for free. A kernel with dilation rate spaces its taps pixels apart, covering pixels per side with the same 9 weights. This page covers that mechanism and its artifacts. Basic size arithmetic lives in basic CNN operations and field growth in receptive fields.
Think of It Like This
Reading every second fence slat
You stand before a long fence and need its full width without walking. Reading every slat covers little ground. Skipping one slat between reads covers twice the fence with the same number of glances, but you miss whatever hid behind the skipped slats.
Dilation is the skipping. The coverage doubles while the glance count stays fixed, and the missed slats are exactly the gridding artifact described below.
How It Actually Works
Effective kernel span for size and rate is . A kernel at rate 1 spans 3, at rate 2 spans 5, at rate 4 spans 9. Weight count never moves: regardless of rate, where and are the input and output channel counts.
Stacked dilations add like ordinary kernels: each layer extends the running field by its span minus one. Segmentation backbones use this to hold output stride at 8 instead of 32, keeping maps on a 224 input where plain pooling would leave .
The price is gridding: rate 2 samples a checkerboard, so adjacent output units read disjoint input sets and fine checkerboard detail falls through the gaps. The standard fix stacks coprime rates such as 1, 2 and 5, or ends with two rate-1 layers that fill the holes.
Worked example
Take three layers at rates 1, 2 and 4. Their spans are , , and . Start from a field of 1 pixel and add each layer's reach beyond its center: . So one output unit sees a 15-pixel stretch of the input while the network holds full resolution and pays for only weights per channel pair instead of a dense .
Code
The point of this snippet is to reproduce the worked example's spans and stacked field, so the arithmetic above can be checked rather than trusted.
def span(k, r): return (k - 1) * r + 1
print([span(3, r) for r in (1, 2, 4)])# -> [3, 5, 9]
# stacked receptive field of rates 1, 2, 4 with 3x3 kernelsfield = 1 + sum(span(3, r) - 1 for r in (1, 2, 4))print(field)# -> 15Watch Out For
Stacking one dilation rate until gridding appears
Three rate-2 layers in a row sample the same checkerboard at every depth, and thin structures one pixel wide can vanish. The symptom is striped or dotted segmentation on fine detail. Vary rates across layers and finish with rate-1 layers.
Using dilation where downsampling plus a skip would do
Dilation keeps full-resolution maps through the whole network, which costs memory: a map holds 16 times the activations of a map. When only the final output needs resolution, a strided encoder with a decoder and skips is cheaper than dilating every stage.
The Quick Version
- Dilation spaces kernel taps apart so a 3x3 at rate 2 spans 5x5 with the same nine weights.
- Span follows effective size (k minus 1) times r plus 1, and stacked fields add.
- Segmentation uses it to hold output stride at 8 with wide context and exact boundaries.
- Repeated single rates cause gridding artifacts that skip fine detail; vary rates and end with rate 1.
- Full-resolution maps cost memory, so dilate the late stages rather than the whole network.