ResNet: Deep Residual Learning
ResNet (Deep Residual Network) is a convolutional neural network architecture introduced by He et al. in 2015 that uses shortcut connections to learn residual mappings rather than direct input-output transformations, enabling stable training of networks with hundreds or thousands of layers. It matters because it solved the degradation problem — the counterintuitive observation that adding more layers to a network made it worse even on training data, not just test data — and it sparked the modern era of ultra-deep architectures. The counterintuitive fact: a 1000-layer ResNet can be trained stably, yet a plain 20-layer network outperforms a plain 56-layer network on the same task.
Instead of asking each layer to learn a complete mapping from input to output, ResNet asks each layer to learn only what needs to change — the residual. If the optimal transformation is close to the identity, it is far easier to push the residual toward zero than to fit an identity mapping through a stack of nonlinear layers. The shortcut connection carries the original input forward and adds it back after the transformation, so the gradient can flow directly backward through these identity paths without vanishing. This single structural change unlocked networks of depth 50, 101, 152, and beyond, transforming computer vision permanently.
How It Works
The Degradation Problem
In a vanilla deep network (no shortcuts), stacking more layers should never hurt: at worst, the extra layers could learn the identity function and match the shallower network's performance. In practice, optimizers fail to learn this — training loss increases with depth. This is not overfitting; it is an optimization problem.
The Residual Formulation
Let be the input to a residual block and be the mapping learned by the stacked layers. The block's output is:
Explanation: The block's output is the learned residual correction plus the original input, so the layers only need to model what changes rather than the full transformation. Here is the skip-connected input, represents two or three convolutional layers with batch normalization and ReLU, and is passed through a final ReLU before becoming the next block's input.
Gradient Flow Through Shortcuts
Consider the loss and a deep network with layers. With shortcut connections the activations at any shallow layer can be expressed in terms of any deeper layer :
Explanation: The deep activation equals the shallow activation plus a sum of residuals, meaning information from any depth is directly accessible at any other depth. The gradient at layer follows directly:
Explanation: The gradient at any shallow layer receives a direct copy of the deep gradient (the "1" term), preventing it from vanishing even through hundreds of layers. The term is the gradient from the loss, and the "1" in the parenthesis is the contribution of the identity shortcut — it guarantees the gradient can never fully vanish as long as the loss gradient itself is nonzero.
Dimension Matching with Projection Shortcuts
When the input and output dimensions differ (e.g., when stride=2 halves spatial resolution or channel depth doubles), a projection shortcut is used:
Explanation: The learnable projection matrix (implemented as a 1×1 convolution) reshapes the shortcut signal to match the residual branch's output dimensions before addition. is a convolution with stride matching the residual branch, with no activation applied to the shortcut path itself.
BasicBlock vs. Bottleneck
For ResNet-18/34, each block uses two convolutions (BasicBlock). For ResNet-50/101/152, a Bottleneck design reduces computation:
Explanation: The bottleneck block uses 1×1 convolutions to compress channels by 4× before and expand after the expensive 3×3 convolution, cutting FLOPs by roughly 8× compared to two 3×3s at full width. Here is the full channel width, the factor is the bottleneck dimension, and the three stages are: compress → spatial-mix → expand.
PyTorch Implementation
```python import torch import torch.nn as nn class BasicBlock(nn.Module): expansion = 1 def __init__(self, in_channels: int, out_channels: int, stride: int = 1): super().__init__()
# Main residual branch self.conv1 = nn.Conv2d(in_channels, out_channels, 3, stride=stride, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(out_channels) self.relu = nn.ReLU(inplace=True) self.conv2 = nn.Conv2d(out_channels, out_channels, 3, stride=1, padding=1, bias=False) self.bn2 = nn.BatchNorm2d(out_channels)
# Projection shortcut (only when dimensions change) self.shortcut = nn.Sequential() if stride != 1 or in_channels != out_channels: self.shortcut = nn.Sequential( nn.Conv2d(in_channels, out_channels, 1, stride=stride, bias=False), nn.BatchNorm2d(out_channels) ) def forward(self, x: torch.Tensor) -> torch.Tensor: identity = self.shortcut(x) # ← shortcut path out = self.relu(self.bn1(self.conv1(x))) out = self.bn2(self.conv2(out)) out = self.relu(out + identity) # ← residual addition return out
class Bottleneck(nn.Module): expansion = 4 # output channels = base_width × 4 def __init__(self, in_channels: int, base_width: int, stride: int = 1): super().__init__() out_channels = base_width * self.expansion self.conv1 = nn.Conv2d(in_channels, base_width, 1, bias=False) self.bn1 = nn.BatchNorm2d(base_width) self.conv2 = nn.Conv2d(base_width, base_width, 3, stride=stride, padding=1, bias=False) self.bn2 = nn.BatchNorm2d(base_width) self.conv3 = nn.Conv2d(base_width, out_channels, 1, bias=False) self.bn3 = nn.BatchNorm2d(out_channels) self.relu = nn.ReLU(inplace=True) self.shortcut = nn.Sequential() if stride != 1 or in_channels != out_channels: self.shortcut = nn.Sequential( nn.Conv2d(in_channels, out_channels, 1, stride=stride, bias=False), nn.BatchNorm2d(out_channels) ) def forward(self, x: torch.Tensor) -> torch.Tensor: identity = self.shortcut(x) out = self.relu(self.bn1(self.conv1(x))) # compress out = self.relu(self.bn2(self.conv2(out))) # spatial mix out = self.bn3(self.conv3(out)) # expand return self.relu(out + identity) ```
Kaiming He completed his PhD at The Chinese University of Hong Kong and later joined Microsoft Research Asia, where he led the team that produced ResNet. His 2015 paper "Deep Residual Learning for Image Recognition" won Best Paper at CVPR 2016 and became one of the most cited papers in all of science. Remarkably, He also invented the Kaiming (He) weight initialization scheme in the same year, which is specifically designed for ReLU networks and is the default initializer in PyTorch's `nn.Conv2d` today.
Jian Sun was a principal researcher at Microsoft Research Asia and the senior author on the ResNet paper, leading the broader research program that produced a series of breakthroughs in deep feature learning. He guided the experimental strategy that validated residual networks across ImageNet classification, COCO detection, and PASCAL segmentation simultaneously — an unusually broad validation for a single architecture paper. Sun later moved to industry, joining Megvii (Face++) as VP of Research, where residual architectures formed the backbone of their commercial vision systems.
Intuition
Think of climbing a mountain in thick fog, where at each step you have two options: (1) decide exactly where you want to stand on the entire mountain, or (2) decide only how much to move from where you already are. Option 2 is obviously easier — small corrections are simpler to learn than absolute positions. ResNet's residual blocks are option 2: every block asks "how should I adjust what I already have?" rather than "what should the output be from scratch?" A useful secondary analogy: think of a residual block as a surgeon making small corrections to a draft document. The draft (identity shortcut) flows straight through, and the surgeon (residual branch) adds only the minimum necessary edits. If no edits are needed, the surgeon adds nothing (pushes residuals to zero) — the draft is perfect as-is. In contrast, a plain network is like asking each surgeon to rewrite the entire document from scratch at every revision step. The gradient flow interpretation: imagine the backpropagation gradient as water flowing backward through a pipe network. In a plain deep network, every layer is a narrow constriction — the gradient (water pressure) drops at every bend. In ResNet, the shortcut connections are bypass pipes of unlimited width running in parallel. Water can always flow backward through the bypass, so pressure never drops to zero, no matter how many constrictions are in the main pipe.