ResNet helps deep learning models learn better by letting information skip some layers. This avoids problems when models get too deep.
ResNet and skip connections in Computer Vision
Start learning this pattern below
Jump into concepts and practice - no test required
def residual_block(x, filters): shortcut = x x = Conv2D(filters, (3,3), padding='same', activation='relu')(x) x = Conv2D(filters, (3,3), padding='same')(x) x = Add()([x, shortcut]) x = Activation('relu')(x) return x
The shortcut is the input that skips the convolution layers.
The Add() layer combines the shortcut and the processed input.
def simple_residual_block(x): shortcut = x x = Conv2D(64, (3,3), padding='same', activation='relu')(x) x = Conv2D(64, (3,3), padding='same')(x) x = Add()([x, shortcut]) x = Activation('relu')(x) return x
def residual_block_with_projection(x, filters): shortcut = Conv2D(filters, (1,1), padding='same')(x) x = Conv2D(filters, (3,3), padding='same', activation='relu')(x) x = Conv2D(filters, (3,3), padding='same')(x) x = Add()([x, shortcut]) x = Activation('relu')(x) return x
This code builds a small ResNet-like model using residual blocks with skip connections. It trains on MNIST digits for one epoch and prints test loss and accuracy.
import tensorflow as tf from tensorflow.keras.layers import Input, Conv2D, Add, Activation, Flatten, Dense from tensorflow.keras.models import Model # Define a simple residual block def residual_block(x, filters): shortcut = x x = Conv2D(filters, (3,3), padding='same', activation='relu')(x) x = Conv2D(filters, (3,3), padding='same')(x) x = Add()([x, shortcut]) x = Activation('relu')(x) return x # Build a small ResNet-like model inputs = Input(shape=(28,28,1)) x = Conv2D(32, (3,3), padding='same', activation='relu')(inputs) x = residual_block(x, 32) x = residual_block(x, 32) x = Flatten()(x) outputs = Dense(10, activation='softmax')(x) model = Model(inputs, outputs) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) # Load MNIST data (x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data() x_train = x_train[..., None] / 255.0 x_test = x_test[..., None] / 255.0 # Train for 1 epoch for demo history = model.fit(x_train, y_train, epochs=1, batch_size=64, validation_split=0.1) # Evaluate on test data loss, accuracy = model.evaluate(x_test, y_test) print(f"Test loss: {loss:.4f}") print(f"Test accuracy: {accuracy:.4f}")
Skip connections help the model learn identity functions easily, so deeper layers don't harm performance.
If input and output shapes differ, use a 1x1 convolution on the shortcut to match them.
ResNet models won many image recognition challenges because of this simple idea.
ResNet uses skip connections to let information flow directly across layers.
This helps train very deep networks without losing accuracy.
Skip connections add the input to the output of some layers, making learning easier.
Practice
Solution
Step 1: Understand skip connections role
Skip connections let the input bypass some layers and add directly to the output, helping information flow.Step 2: Connect to training deep networks
This helps avoid problems like vanishing gradients, making training deep networks easier and more accurate.Final Answer:
To allow information to flow directly across layers, helping training -> Option CQuick Check:
Skip connections improve training by direct flow [OK]
- Thinking skip connections reduce layers
- Confusing skip connections with input size changes
- Assuming skip connections replace convolution
x and output tensor out?Solution
Step 1: Recall skip connection operation
Skip connections add the input tensor to the output tensor element-wise.Step 2: Match with correct syntax
The addition operationout = x + outcorrectly implements the skip connection.Final Answer:
out = x + out -> Option DQuick Check:
Skip connection = addition [OK]
- Using multiplication instead of addition
- Using subtraction or division which breaks skip connection
- Confusing order of operands
import torch
import torch.nn as nn
class SimpleResBlock(nn.Module):
def __init__(self):
super().__init__()
self.conv = nn.Conv2d(3, 3, kernel_size=3, padding=1)
self.relu = nn.ReLU()
self.conv.weight.data.fill_(0.0)
self.conv.bias.data.fill_(1.0)
def forward(self, x):
out = self.conv(x)
out = self.relu(out)
out = out + x
return out
block = SimpleResBlock()
input_tensor = torch.ones(1, 3, 5, 5)
output = block(input_tensor)
print(output[0,0,0,0].item())What will be printed?
Solution
Step 1: Analyze convolution output
The convolution with kernel size 3 and padding 1 keeps the input size. Since input is all ones, convolution output will be some positive values (not zero).Step 2: Add input and apply ReLU
ReLU keeps positive values. Then adding input tensor (all ones) increases values. So output values > 1.Final Answer:
2.0 -> Option AQuick Check:
Output = conv + input > 1 [OK]
- Assuming output equals input without addition
- Ignoring padding effect on size
- Expecting zero or error due to shape mismatch
def forward(self, x):
out = self.conv(x)
out = self.relu(out)
out = out + x
return outThe error says: "The size of tensor a (64) must match the size of tensor b (128) at non-singleton dimension 1." What is the likely cause?
Solution
Step 1: Understand error message
The error says channel sizes differ (64 vs 128), so tensors can't be added element-wise.Step 2: Check convolution output channels
If convolution changes channels from 64 to 128, input and output shapes differ, causing addition error.Final Answer:
The convolution changes the number of channels, so shapes don't match for addition -> Option AQuick Check:
Channel mismatch causes addition error [OK]
- Blaming ReLU for shape errors
- Ignoring channel dimension mismatch
- Assuming addition works regardless of shape
Solution
Step 1: Identify shape mismatch
Input has 64 channels and size 32x32; output has 128 channels and size 16x16 due to stride 2.Step 2: Match shapes for addition
To add tensors, input must be transformed to 128 channels and 16x16 size, done by 1x1 convolution with stride 2.Final Answer:
Use a 1x1 convolution with stride 2 on the input to match shape before addition -> Option BQuick Check:
Match shape with 1x1 conv before skip add [OK]
- Adding tensors with different shapes directly
- Using pooling on output instead of input
- Skipping skip connection when channels differ
