Residual Networks Explained

Amit Yadav
Biased-Algorithms
15 min readSep 8, 2024

--

Hi there! Have you tried using ChatGPT+ for your projects?

I’ve been using ChatGPT+ and it’s been amazing for my projects.

If you want to experience ChatGPT’s newest models but aren’t ready to commit financially, you’re welcome to use my accounts.

Click here to get free GPT + accounts.

Now let’s get back to the blog:

You know, when we talk about deep learning and neural networks, there’s this tendency to think that going deeper — adding more layers — automatically makes a model smarter and more powerful. But here’s the deal: more depth often leads to more problems. The deeper your network gets, the harder it becomes to train effectively. This is because of two pesky issues known as vanishing and exploding gradients. And trust me, these are not just buzzwords — they can absolutely cripple your model’s performance.

In this blog, I’m going to walk you through the solution to that problem: Residual Networks (ResNets). These networks revolutionized deep learning by allowing us to train much deeper networks without running into the same old issues. You’ll see how ResNets are designed, how they overcome challenges like vanishing gradients, and why they’re the go-to choice for some of the most complex tasks in AI, especially in computer vision — like image classification, object detection, and even segmentation.

Problems

Let’s break this down. If you’ve ever worked with deep networks, you’ve probably experienced how adding layers doesn’t always improve your model’s performance. In fact, things can get worse as your network goes deeper. This might surprise you, but deeper models often perform worse than their shallower counterparts. Why? It’s all about how information flows through the network. The further it travels, the more distorted it gets. This results in gradients becoming either too small (vanishing gradients) or blowing up entirely (exploding gradients), making it nearly impossible for the model to learn effectively.

Why Residual Networks are Important

So, how do ResNets fix this? They introduce a clever trick — skip connections. It’s as if ResNets say, “Hey, let’s make sure the important information isn’t lost as we go deeper. Let’s give it a shortcut.” And this one simple change allows us to build models with hundreds of layers — like ResNet-50 and ResNet-101 — without worrying about degradation.

Think of it this way: If traditional deep learning is like navigating through a dense forest, ResNets are like having a clear path that lets you skip the rough terrain. And this has made them a game-changer in AI. Whether it’s detecting objects in images or recognizing faces, residual networks set the stage for some of the most powerful models in AI today. In fact, they were responsible for a massive leap in performance in tasks like the ImageNet competition, where ResNets outshone traditional deep networks by a mile.

By the end of this blog, you’ll not only understand how ResNets work but also why they’re so crucial for modern AI applications. Let’s dive in.

Background: The Problem of Deep Neural Networks

You’ve probably heard the phrase, “the deeper, the better,” when it comes to neural networks. But, here’s where things get tricky: deep networks don’t always play by that rule. In fact, adding more layers can often cause more harm than good. Let me explain why.

Vanishing and Exploding Gradients

Imagine you’re teaching a group of students a complex topic. The further back a student sits, the harder it becomes for them to understand you — your message fades the farther it travels. This is what happens in deep neural networks with vanishing gradients. The signal, or gradient, that helps the network learn shrinks as it moves through each layer, making it nearly impossible for the early layers to learn anything meaningful.

On the flip side, sometimes this signal doesn’t shrink at all. Instead, it becomes enormous, like trying to hear someone shouting at the front of the classroom. This is the exploding gradient problem. Both of these issues can wreck your training process, leaving you with a network that doesn’t learn or, even worse, one that learns in all the wrong ways.

So, why does this happen? When you’re stacking layer after layer in a deep network, the gradients — the information that backpropagates through the layers — become unstable. They either get too small (vanishing) or too large (exploding). In both cases, the network fails to learn effectively, and you end up with poor results, no matter how much data you throw at it.

The Degradation Problem

Now, here’s the part that’s even more counterintuitive: degradation. You might think that making a network deeper will naturally improve performance. I mean, more layers should mean more capacity to learn, right? But what if I told you that deeper networks often perform worse than shallower ones? Yes, this is the degradation problem.

This happens because, as we add more layers, the network doesn’t just suffer from vanishing or exploding gradients — it also loses its ability to propagate useful information. Imagine you’re trying to send a message through a line of people. The more people in the line, the more likely your message gets garbled. Similarly, in deep networks, information is “garbled” by the time it reaches the end, making the network less effective.

What is a Residual Network (ResNet)?

So, how do we fix these problems? Enter Residual Networks (ResNets). They’re like the secret sauce that makes deep learning with very deep networks not only possible but highly effective.

Simple Definition

Let me put it simply: A Residual Network is a deep neural network that uses something called skip connections (or identity mappings) to solve the degradation problem. Instead of blindly adding layers and hoping for the best, ResNets introduce a shortcut where the input can bypass one or more layers and be added directly to the output.

Think of it like this: if traditional deep networks are like taking the long, winding road up a mountain, ResNets are like finding a secret tunnel that cuts straight through. By letting information “skip” some layers, ResNets ensure that the important signals don’t get lost along the way.

Key Concept — Skip Connections

Alright, let’s talk about these skip connections. You might be wondering, “What exactly is being skipped, and why does it matter?” In a traditional network, each layer is responsible for learning a new transformation of the input. But in ResNets, the network doesn’t need to reinvent the wheel at every step. Instead, it learns the residual — the part of the transformation that’s missing — while the original input is passed along untouched.

This is the breakthrough. Skip connections allow the network to keep the core information intact while learning only what’s necessary. The result? Deeper networks can now train more efficiently without running into the vanishing gradient problem or the degradation issue.

Imagine it like this: in a regular conversation, each person might repeat everything they hear before adding their own twist. But in ResNets, each person skips the repetition and focuses only on what’s new. The important message stays intact, while the nuances get added layer by layer.

By the time we get to networks like ResNet-50 or ResNet-101, these architectures can go deeper than ever before — sometimes over 100 layers deep — without breaking a sweat. And that’s why ResNets are such a game-changer in the world of deep learning.

So, how exactly do these skip connections work in practice? We’ll dive into the architecture in more detail, but here’s a preview: it’s all about letting the network learn what it doesn’t know rather than trying to force it to learn everything from scratch.

With this foundation in mind, we’re ready to explore the deeper layers (pun intended!) of how ResNets transform the landscape of AI.

How Residual Networks Work

Now that you’ve got a grip on the basic idea behind skip connections, it’s time to look under the hood and see how a Residual Network (ResNet) actually works. This is where we dive into the residual block architecture — the backbone of ResNets — and explore how these blocks make training deep networks not just possible, but efficient.

Residual Block Architecture

Let’s start with the building block of a ResNet: the residual block. At first glance, it might seem like just another layer in a neural network, but here’s what makes it special: instead of just learning a transformation of the input, a residual block learns the difference (or residual) between the input and the desired output.

Here’s the formula that defines a residual block:

y = F (x,{Wi}) + x

In plain terms, this means that the output yyy is the result of two things:

  1. The learned transformation F(x,{Wi})F(x, \{W_i\})F(x,{Wi​}), which applies some operations to the input xxx.
  2. The input xxx itself, which bypasses the transformation and gets added directly to the output.

This might sound technical, but think of it like this: imagine you’re learning how to play a musical instrument. Each lesson builds on what you already know, but instead of starting from scratch, you’re just adding to your previous knowledge. That’s what ResNets do — they let the network learn the differences from one layer to the next rather than relearning everything each time. This way, the core information remains intact, and the network only learns what it doesn’t know yet.

Making Training More Efficient

Here’s the beauty of this approach: by letting the input xxx skip certain layers, ResNets make training much more efficient. In traditional deep networks, each layer tries to transform the input into something new. But in a ResNet, layers don’t have to transform everything. Instead, they focus on learning the residual — what’s missing from the input — while still keeping the original input in the mix.

This dramatically reduces the risk of vanishing gradients because the network doesn’t “lose” information as it goes deeper. In fact, those skip connections act like lifelines, ensuring that the signal flows smoothly from the earlier layers to the later ones. So, the more layers you add, the better the network can fine-tune its understanding without losing track of the bigger picture.

Building Deeper Networks

This brings us to the core advantage of ResNets: depth. As we’ve mentioned before, traditional deep networks hit a wall when they become too deep. But with ResNets, you can stack residual blocks one after the other, creating extremely deep networks — sometimes hundreds of layers deep — without running into the usual problems like vanishing gradients or performance degradation.

You might be wondering, “Why does depth matter?” Well, deeper networks can capture more complex patterns in the data, allowing them to outperform shallower networks in tasks like image classification, where understanding fine-grained details makes all the difference. In fact, ResNets with 50, 101, or even 152 layers have become the standard for many computer vision tasks. And because of the skip connections, training these deep networks is not only feasible, but incredibly effective.

Forward and Backpropagation in ResNets

Now, let’s get a bit more technical and talk about how forward pass and backpropagation work in ResNets. Don’t worry — I’ll walk you through it step by step.

During the forward pass, each residual block computes a transformation F(x)F(x)F(x) based on the input xxx, and then adds the input xxx back to the output. This addition ensures that the original input is always carried forward through the network, so the deeper layers still have access to the core information from earlier layers.

But the real magic happens during backpropagation. In a traditional deep network, gradients can become very small as they move backward through the layers, which causes the vanishing gradient problem. However, in a ResNet, the skip connections allow gradients to bypass some layers entirely. This means the gradients don’t shrink to nothing as they move backward; they stay intact because they can “skip” over problematic layers.

Here’s how it works: when you compute the gradient of the loss function with respect to the weights, the skip connection ensures that the gradient flows through both the residual function F(x)F(x)F(x) and the input xxx. In other words, the gradient has two paths to follow — one through the layers and one through the skip connections — so it’s much less likely to vanish.

This might sound like a minor tweak, but it’s a game-changer. By allowing gradients to flow more easily, ResNets can train very deep networks without suffering from the usual challenges, like vanishing gradients or training degradation. And this is why ResNets are able to go much deeper than traditional neural networks while still delivering exceptional performance.

ResNet Variants and Architectures

When it comes to Residual Networks, it’s not just about understanding the basic concept — you also need to know about the different variants that exist. Let me introduce you to some of the most popular versions: ResNet-50, ResNet-101, and ResNet-152. These numbers, as you might have guessed, represent the number of layers in each network, and each version has its own strengths depending on the task at hand.

ResNet-50, ResNet-101, ResNet-152: What’s the Difference?

You might be wondering, “Why does the number of layers matter?” Here’s the deal: deeper networks can capture more complex patterns. But, of course, the deeper the network, the more computationally expensive it becomes. ResNet-50, for instance, is a popular choice for applications where a balance between accuracy and computational cost is needed. It’s used in tasks like image classification and object detection. For example, ResNet-50 is widely known for its exceptional performance in competitions like ImageNet, a benchmark for image classification models.

ResNet-101 and ResNet-152, on the other hand, take depth to the next level. These deeper versions allow the network to learn even more intricate patterns, making them ideal for fine-grained tasks like semantic segmentation or image generation. In state-of-the-art models, these architectures are often employed when higher accuracy is required, and computational resources aren’t as big of a concern.

In practical terms, if you’re working on a resource-constrained project, you’d likely opt for ResNet-50, as it provides a great trade-off between depth and computational efficiency. But if you’re working on something like medical image analysis, where every pixel matters, ResNet-101 or even ResNet-152 could give you that extra layer of detail you need to make accurate predictions.

Bottleneck Design: The Key to Deeper ResNets

Now, if you’ve made it this far, you might be thinking, “How can ResNet-101 or ResNet-152 be so deep without becoming computational monsters?” Great question! This is where the concept of the bottleneck design comes into play, and trust me, it’s an incredibly smart trick.

Here’s the thing: as we add more layers to a network, the amount of computation skyrockets. To mitigate this, deeper ResNets (like ResNet-50, ResNet-101, and ResNet-152) use a three-layer bottleneck block instead of a simple two-layer block. The bottleneck design reduces the number of computations while still allowing the network to be incredibly deep.

Let me explain this with an example: instead of passing all the data through large, complex filters, the bottleneck block uses 1x1 convolutions to first reduce the number of channels (or features), then applies the heavier computations, and finally uses another 1x1 convolution to restore the number of channels. This reduces the overall workload while keeping the depth and capacity of the network intact.

Imagine it like this: if you’re packing for a trip, you don’t need to stuff your entire closet into the suitcase. Instead, you pack only the essentials, and once you arrive, you can spread everything out again. That’s what the bottleneck does — it compresses the data temporarily, does the necessary work, and then restores it, all without losing crucial information.

The three-layer bottleneck design looks like this:

  1. 1x1 convolution: Reduces the number of features (compression).
  2. 3x3 convolution: Applies the heavy computational work.
  3. 1x1 convolution: Expands the features back to their original size.

This smart design allows ResNets to go deeper without becoming computationally overwhelming, and that’s why models like ResNet-101 and ResNet-152 are still manageable, even though they have so many layers.

In a nutshell, the choice between ResNet-50, ResNet-101, and ResNet-152 depends on your specific needs — whether you need a balance of speed and accuracy or the ability to capture extremely fine details. And thanks to the bottleneck design, these deeper networks are able to stay computationally efficient while delivering state-of-the-art results.

Next, we’ll dive into how these architectures are being used in real-world applications. Whether it’s self-driving cars, medical imaging, or even video analysis, ResNets are at the forefront of cutting-edge AI research and deployment. Stay tuned!

Residual Networks in Practice: Implementation

So, you’ve learned how Residual Networks (ResNets) work and why they’re game-changers in deep learning. But let’s be real — none of that means much unless you can actually implement these networks yourself, right? Whether you’re working with PyTorch or TensorFlow, I’ve got you covered with code snippets that will take you from theory to practice.

PyTorch Code Example

Let’s start with PyTorch, one of the most popular deep learning frameworks for research and production.

import torch
import torch.nn as nn

# Basic Residual Block
class ResidualBlock(nn.Module):
def __init__(self, in_channels, out_channels, stride=1):
super(ResidualBlock, self).__init__()

# Layers within the residual block
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(out_channels)

# Skip connection
self.shortcut = nn.Sequential()
if stride != 1 or in_channels != out_channels:
self.shortcut = nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),
nn.BatchNorm2d(out_channels)
)

def forward(self, x):
out = torch.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out += self.shortcut(x) # Adding the skip connection (identity mapping)
out = torch.relu(out)
return out

# Example: building a ResNet block
block = ResidualBlock(64, 128, stride=2)

Let’s break it down:

  • Convolutional Layers: You’ll notice that the block starts with two convolutional layers, each followed by batch normalization. The first convolution layer has a stride of 1 or more, depending on whether you’re shrinking the input dimensions.
  • Skip Connection (shortcut): The magic happens with self.shortcut, which either passes the input along unchanged or uses a 1x1 convolution to match dimensions before adding it back to the output. This ensures that the residual connection stays intact.
  • Forward Function: This is where the skip connection comes into play. The input xxx is processed by the convolution layers, but also “skips” them via the shortcut. Then, the result is added back to the transformed output.

This simple Residual Block is the building block of larger networks, like ResNet-50 or ResNet-101. In a full model, you’d stack these blocks to build a deep, powerful network.

TensorFlow (Keras) Code Example

If you prefer working with TensorFlow (or Keras), implementing a residual block is just as straightforward.

import tensorflow as tf
from tensorflow.keras import layers

# Basic Residual Block
def residual_block(x, filters, kernel_size=3, stride=1):
shortcut = x

# First convolution layer
x = layers.Conv2D(filters, kernel_size, strides=stride, padding='same')(x)
x = layers.BatchNormalization()(x)
x = tf.nn.relu(x)

# Second convolution layer
x = layers.Conv2D(filters, kernel_size, strides=1, padding='same')(x)
x = layers.BatchNormalization()(x)

# Shortcut layer if needed (for dimension matching)
if stride != 1:
shortcut = layers.Conv2D(filters, kernel_size=1, strides=stride)(shortcut)
shortcut = layers.BatchNormalization()(shortcut)

# Adding the skip connection
x = layers.Add()([x, shortcut])
x = tf.nn.relu(x)

return x

# Example: building a residual block in TensorFlow
input_tensor = tf.random.normal([32, 64, 64, 3]) # Batch of 32 images of size 64x64 with 3 channels
output_tensor = residual_block(input_tensor, filters=64, stride=2)

Let’s break this one down:

  • Convolution and Batch Normalization: The structure is similar to PyTorch, with two convolutional layers followed by batch normalization.
  • Skip Connection: The key here is the layers.Add() function, which combines the transformed input with the shortcut. If the input dimensions don’t match the output (due to stride changes), we use a 1x1 convolution in the shortcut to fix that.
  • Activation: After adding the skip connection, we apply a ReLU activation to introduce non-linearity.

This implementation shows how easy it is to build residual blocks in Keras, and just like in PyTorch, you can stack these blocks to form deeper architectures like ResNet-50 or ResNet-101.

Tips for Training ResNets

Now that you’ve got the code, let’s talk about training. Deep networks like ResNets require some special care to train effectively, especially as they grow in size.

  1. Learning Rate: When training ResNets, you’ll want to use an adaptive learning rate schedule. I recommend starting with a higher learning rate (e.g., 0.1) and then decaying it gradually. Use something like learning rate annealing or cosine annealing to ensure stable convergence. A dynamic learning rate can prevent overfitting and underfitting as your network goes deeper.
  2. Regularization: Deep networks are prone to overfitting, especially if you’re working with smaller datasets. Using weight decay (L2 regularization) is a common practice to prevent your model from becoming overly complex. You can also experiment with dropout for additional regularization, though it’s less common in ResNets due to batch normalization.
  3. Batch Normalization: Speaking of batch normalization, this is a must for training ResNets. It normalizes the input to each layer, speeding up convergence and improving generalization. Make sure batch normalization is applied after each convolutional layer, as we saw in both PyTorch and TensorFlow code examples.
  4. Data Augmentation: If you’re working with image data, data augmentation is your friend. Techniques like random cropping, flipping, and color jittering will artificially expand your dataset and help your ResNet generalize better to unseen data.
  5. Gradient Clipping: As ResNets get deeper, gradients can still occasionally blow up, even with skip connections. One trick you can use is gradient clipping, which caps the maximum value of gradients during backpropagation to avoid instability.
  6. Transfer Learning: If you don’t have a huge dataset, consider using a pre-trained ResNet model (e.g., from ImageNet) and fine-tuning it on your specific task. Transfer learning allows you to leverage the powerful features learned by deep ResNets without having to train from scratch.

Final Thoughts

At the end of the day, Residual Networks are all about making deep learning smarter, not harder. They allow you to go deep without losing track of what matters, making them a cornerstone of modern AI. If you haven’t already, I encourage you to dive into the code, experiment with different ResNet architectures, and see firsthand why they’ve become such a powerful tool in the deep learning toolbox.

Happy coding, and good luck with your next deep learning project!

--

--

Amit Yadav
Biased-Algorithms

Proven track record in deploying predictive models executing data processing pipelines,and leveraging ML algorithm to tackle intricate business challenges.