Bird
Raised Fist0
PyTorchml~20 mins

Why CNNs detect spatial patterns in PyTorch - Experiment to Prove It

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Experiment - Why CNNs detect spatial patterns
Problem:We want to understand why Convolutional Neural Networks (CNNs) are good at detecting spatial patterns in images. Currently, a simple CNN model is trained on a small image dataset, but it does not clearly show how spatial features are captured.
Current Metrics:Training accuracy: 85%, Validation accuracy: 80%, Loss: 0.45
Issue:The model works but it is not clear how spatial patterns are detected. The learner needs to see how convolution layers focus on local spatial features.
Your Task
Modify the CNN model to visualize and explain how convolutional layers detect spatial patterns in images. Show intermediate feature maps after convolution layers.
Use PyTorch framework
Keep the model simple (2 convolutional layers)
Use a small image dataset like CIFAR-10 or a subset
Do not change the dataset or overall training procedure
Hint 1
Hint 2
Hint 3
Solution
PyTorch
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt

# Define a simple CNN
class SimpleCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 6, kernel_size=3, padding=1)  # 3 input channels, 6 filters
        self.conv2 = nn.Conv2d(6, 12, kernel_size=3, padding=1) # 6 input channels, 12 filters
        self.pool = nn.MaxPool2d(2, 2)
        self.fc1 = nn.Linear(12 * 8 * 8, 120)
        self.fc2 = nn.Linear(120, 10)

    def forward(self, x):
        x = F.relu(self.conv1(x))  # After conv1 + relu
        self.feature_maps1 = x.detach()       # Save feature maps after first conv
        x = self.pool(x)  # Pooling after conv1
        x = F.relu(self.conv2(x))  # After conv2 + relu
        self.feature_maps2 = x.detach()       # Save feature maps after second conv
        x = self.pool(x)  # Pooling after conv2
        x = x.view(-1, 12 * 8 * 8)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

# Load CIFAR-10 dataset (small subset for speed)
transform = transforms.Compose([transforms.ToTensor()])
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=0)

# Initialize model, loss, optimizer
model = SimpleCNN()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# Train for 1 epoch to keep it simple
for images, labels in trainloader:
    optimizer.zero_grad()
    outputs = model(images)
    loss = criterion(outputs, labels)
    loss.backward()
    optimizer.step()
    break  # Only one batch for demonstration

# Visualize feature maps from first conv layer
feature_maps = model.feature_maps1[0]  # Take first image in batch
num_maps = feature_maps.shape[0]
fig, axes = plt.subplots(1, num_maps, figsize=(15, 5))
for i in range(num_maps):
    axes[i].imshow(feature_maps[i].cpu(), cmap='gray')
    axes[i].axis('off')
plt.suptitle('Feature maps after first convolution layer')
plt.show()

# Visualize feature maps from second conv layer
feature_maps2 = model.feature_maps2[0]
num_maps2 = feature_maps2.shape[0]
fig2, axes2 = plt.subplots(1, num_maps2, figsize=(20, 5))
for i in range(num_maps2):
    axes2[i].imshow(feature_maps2[i].cpu(), cmap='gray')
    axes2[i].axis('off')
plt.suptitle('Feature maps after second convolution layer')
plt.show()
Modified forward method to save feature maps before pooling layers for clearer spatial pattern visualization
Kept model simple with two convolution layers and pooling
Trained on one batch for quick demonstration
Visualized feature maps as grayscale images to show spatial patterns detected
Results Interpretation

Before: Model trained but no insight into spatial pattern detection.

After: Visual feature maps show how convolution filters highlight edges, textures, and shapes in local image regions.

Convolutional layers scan small image patches with filters that detect simple spatial features like edges. These features combine in deeper layers to recognize complex patterns. Visualizing feature maps helps understand this spatial detection ability of CNNs.
Bonus Experiment
Try adding more convolutional layers and visualize how feature maps evolve to detect more complex spatial patterns.
💡 Hint
Deeper layers capture more abstract features. Visualize feature maps after each conv layer to see this progression.

Practice

(1/5)
1. Why do CNNs use small filters that slide over an image?
easy
A. To detect local spatial patterns like edges and textures
B. To reduce the image size drastically in one step
C. To convert images into text data
D. To randomly change pixel colors

Solution

  1. Step 1: Understand the role of filters in CNNs

    Filters slide over small parts of the image to focus on local details like edges or shapes.
  2. Step 2: Connect filter behavior to spatial pattern detection

    By scanning the image locally, filters learn to recognize important spatial features that help in tasks like image recognition.
  3. Final Answer:

    To detect local spatial patterns like edges and textures -> Option A
  4. Quick Check:

    Filters detect local patterns = A [OK]
Hint: Filters scan small areas to find edges and shapes [OK]
Common Mistakes:
  • Thinking filters change image size drastically in one step
  • Believing CNNs convert images to text directly
  • Assuming filters randomly alter pixel colors
2. Which PyTorch code correctly creates a 2D convolutional layer with a 3x3 filter?
easy
A. torch.nn.Conv2d(in_channels=1, out_channels=10, kernel_size=3)
B. torch.nn.Conv1d(in_channels=1, out_channels=10, kernel_size=3)
C. torch.nn.Linear(in_features=3, out_features=10)
D. torch.nn.Conv2d(in_channels=1, out_channels=10, kernel_size=5)

Solution

  1. Step 1: Identify the correct convolution layer type

    For images, 2D convolution (Conv2d) is used, not Conv1d or Linear layers.
  2. Step 2: Check the kernel size matches 3x3

    kernel_size=3 means a 3x3 filter, so torch.nn.Conv2d(in_channels=1, out_channels=10, kernel_size=3) is correct; torch.nn.Conv2d(in_channels=1, out_channels=10, kernel_size=5) uses 5x5.
  3. Final Answer:

    torch.nn.Conv2d(in_channels=1, out_channels=10, kernel_size=3) -> Option A
  4. Quick Check:

    Conv2d with kernel_size=3 = D [OK]
Hint: Use Conv2d and kernel_size=3 for 3x3 filters [OK]
Common Mistakes:
  • Using Conv1d instead of Conv2d for images
  • Confusing Linear layers with convolution layers
  • Setting wrong kernel size for the filter
3. Given this PyTorch code snippet, what is the output shape after the convolution?
import torch
conv = torch.nn.Conv2d(1, 1, kernel_size=3)
input = torch.randn(1, 1, 5, 5)
output = conv(input)
print(output.shape)
medium
A. torch.Size([1, 1, 5, 5])
B. torch.Size([1, 3, 3, 3])
C. torch.Size([1, 1, 7, 7])
D. torch.Size([1, 1, 3, 3])

Solution

  1. Step 1: Understand convolution output size formula

    Output size = Input size - Kernel size + 1 (assuming stride=1, padding=0). Here, 5 - 3 + 1 = 3.
  2. Step 2: Apply formula to each spatial dimension

    Both height and width become 3, so output shape is (1 batch, 1 channel, 3 height, 3 width).
  3. Final Answer:

    torch.Size([1, 1, 3, 3]) -> Option D
  4. Quick Check:

    Output size = 5-3+1 = 3 [OK]
Hint: Output size = input - kernel + 1 if no padding [OK]
Common Mistakes:
  • Assuming output size equals input size without padding
  • Confusing batch and channel dimensions
  • Misapplying kernel size in output calculation
4. What is wrong with this PyTorch code for a convolutional layer?
conv = torch.nn.Conv2d(in_channels=3, out_channels=6, kernel_size=3)
input = torch.randn(1, 1, 28, 28)
output = conv(input)
print(output.shape)
medium
A. Output channels must be less than input channels
B. Kernel size is too large for the input
C. Input channels do not match the layer's in_channels
D. Batch size must be greater than 1

Solution

  1. Step 1: Check input and layer channel compatibility

    The layer expects 3 input channels, but input has only 1 channel, causing a mismatch error.
  2. Step 2: Confirm other parameters are valid

    Kernel size 3 is valid for 28x28 input, output channels can be any positive number, batch size 1 is allowed.
  3. Final Answer:

    Input channels do not match the layer's in_channels -> Option C
  4. Quick Check:

    Input channels mismatch = A [OK]
Hint: Input channels must match Conv2d in_channels [OK]
Common Mistakes:
  • Ignoring channel mismatch errors
  • Thinking kernel size is invalid for input
  • Believing batch size must be >1
5. How does using multiple convolutional layers help CNNs detect complex spatial patterns?
hard
A. Layers randomly shuffle pixels to create new patterns
B. Each layer learns higher-level features by combining simpler patterns from previous layers
C. Multiple layers reduce the image size to zero quickly
D. Each layer independently detects the same simple edges

Solution

  1. Step 1: Understand feature hierarchy in CNNs

    Early layers detect simple features like edges; later layers combine these to form complex shapes and objects.
  2. Step 2: Explain how multiple layers build complexity

    Stacking layers lets the network learn spatial patterns at increasing levels of abstraction, improving recognition.
  3. Final Answer:

    Each layer learns higher-level features by combining simpler patterns from previous layers -> Option B
  4. Quick Check:

    Layer stacking builds complex features = C [OK]
Hint: Layers build complexity by combining simpler features [OK]
Common Mistakes:
  • Thinking layers just reduce image size quickly
  • Believing layers shuffle pixels randomly
  • Assuming all layers detect the same simple edges