Pooling-Schichten: Räumliches Downsampling und Invarianz
Lernende fügen nach Faltungsschichten MaxPool2d hinzu, berechnen die Ausgabeabmessungen und verstehen, wie Pooling Positionsunabhängigkeit ermöglicht und den Rechenaufwand reduziert.
Pooling-Schichten: Räumliches Downsampling und Invarianz ist eine kostenlose Machine Learning Academy-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Machine Learning Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Machine Learning Academy-Kurs umfasst insgesamt 4 Lektionen.
Teile dieser Lektion wurden noch nicht übersetzt und werden auf Englisch angezeigt.
Why Pooling Layers Exist
Pooling layers reduce the spatial dimensions of feature maps, decreasing computation and memory while making representations more compact. They also introduce a degree of spatial invariance — small translations of a feature in the input produce the same pooled output. Without pooling (or stride-2 convolutions), the spatial dimensions would remain constant through all layers, making the network computationally prohibitive for large images.
import torch
import torch.nn as nn
# Without pooling: feature map grows in channels but not reduced
conv1 = nn.Conv2d(3, 32, 3, padding=1) # (B, 32, H, W)
conv2 = nn.Conv2d(32, 64, 3, padding=1) # (B, 64, H, W)
# With pooling: spatial dims are halved each time
pool = nn.MaxPool2d(kernel_size=2, stride=2)
x = torch.randn(4, 3, 32, 32)
out = pool(torch.relu(conv1(x)))
print(out.shape) # (4, 32, 16, 16) -- halved!Max Pooling: Taking the Maximum
MaxPool2d divides the input feature map into non-overlapping windows and takes the maximum value in each window. The maximum corresponds to the strongest activation of the filter at any position in that window — it captures whether the feature was present anywhere in the region, regardless of its exact position. A 2x2 max pool with stride 2 reduces height and width by half, cutting the total spatial size by 4x.
import torch
import torch.nn as nn
pool = nn.MaxPool2d(kernel_size=2, stride=2)
# Simple 4x4 feature map
x = torch.tensor([[[[ 1., 3., 2., 4.],
[ 5., 6., 7., 8.],
[ 9., 2., 1., 3.],
[ 4., 5., 6., 7.]]]])
out = pool(x)
print(out.shape) # (1, 1, 2, 2)
print(out)
# Max of top-left 2x2: max(1,3,5,6)=6
# Max of top-right 2x2: max(2,4,7,8)=8
# Max of bottom-left 2x2: max(9,2,4,5)=9
# Max of bottom-right 2x2: max(1,3,6,7)=7Average Pooling vs Max Pooling
AvgPool2d takes the average of values in each pooling window instead of the maximum. Average pooling smooths the feature map and retains information from all activations, while max pooling discards the weaker activations. Max pooling is preferred in classification networks where the presence of a feature matters more than its average strength. Average pooling is commonly used for global pooling at the end of a CNN to collapse spatial dimensions.
import torch
import torch.nn as nn
x = torch.tensor([[[[ 1., 3., 2., 4.],
[ 5., 6., 7., 8.],
[ 9., 2., 1., 3.],
[ 4., 5., 6., 7.]]]])
max_pool = nn.MaxPool2d(2, stride=2)
avg_pool = nn.AvgPool2d(2, stride=2)
print('MaxPool:', max_pool(x))
# tensor([[[[6., 8.], [9., 7.]]]])
print('AvgPool:', avg_pool(x))
# tensor([[[[3.75, 5.25], [5.00, 4.25]]]])Global Average Pooling
Global Average Pooling (GAP) collapses the entire spatial dimension to a single value per channel by averaging all spatial positions. For a feature map of shape (B, C, H, W), GAP produces (B, C) — a vector of C values representing the average activation of each filter across the entire image. GAP replaces the flatten + large fully connected layers at the top of classic CNNs (VGG), drastically reducing parameters and acting as a powerful regulariser. It is used in ResNet, MobileNet, and EfficientNet.
import torch
import torch.nn as nn
# Global Average Pooling (AdaptiveAvgPool2d to any output size)
gap = nn.AdaptiveAvgPool2d(output_size=(1, 1))
x = torch.randn(8, 512, 7, 7) # typical final feature map
out = gap(x)
print(out.shape) # (8, 512, 1, 1)
# Flatten to (B, C) for the classifier
flat = out.view(out.size(0), -1)
print(flat.shape) # (8, 512)
# Then: nn.Linear(512, num_classes)Computing Output Dimensions
Computing the output spatial dimensions after pooling is straightforward: output_size = floor((input_size - kernel_size) / stride) + 1. For a 2x2 pool with stride 2 on a 28x28 input, the output is 14x14. Misjudging dimensions is a common source of shape errors. AdaptiveMaxPool2d and AdaptiveAvgPool2d solve this by accepting the desired output size directly, automatically computing the required kernel and stride — ideal when you want a fixed output regardless of input size.
import torch
import torch.nn as nn
# Classic fixed-size pooling
x = torch.randn(1, 32, 28, 28)
pool = nn.MaxPool2d(kernel_size=2, stride=2)
print(pool(x).shape) # (1, 32, 14, 14)
# Adaptive pooling: specify desired output size
adaptive_pool = nn.AdaptiveAvgPool2d((4, 4))
print(adaptive_pool(x).shape) # (1, 32, 4, 4) -- any input
# Works even with irregular input sizes:
x2 = torch.randn(1, 32, 17, 23)
print(adaptive_pool(x2).shape) # (1, 32, 4, 4) -- still 4x4!Pooling for Translation Invariance
Pooling provides local translation invariance: if a feature shifts by a few pixels, it likely still falls within the same pooling window and produces the same maximum activation. This means the network recognises a cat whether it is slightly to the left or right in the image. However, pooling is only locally invariant — large translations still produce different outputs. Data augmentation (random crops, flips) is needed to achieve global translation invariance.
import torch
import torch.nn as nn
pool = nn.MaxPool2d(2, 2)
# Feature map with an 'activated' pixel at position (1,1)
fm1 = torch.zeros(1, 1, 4, 4)
fm1[0, 0, 1, 1] = 1.0 # activation at (1,1)
# Shift by 1 pixel to (1,2)
fm2 = torch.zeros(1, 1, 4, 4)
fm2[0, 0, 1, 2] = 1.0
# Both fall in the same 2x2 window -> same pool output
print(torch.allclose(pool(fm1), pool(fm2))) # True!Pooling vs Stride-2 Convolutions
Modern CNN architectures (ResNet, EfficientNet) increasingly use stride-2 convolutions instead of separate max pooling layers. The advantage is that stride-2 convolutions are learnable — the network decides how to downsample, potentially preserving more useful information than the fixed max operation. Max pooling is still used in classic architectures (VGGNet, AlexNet) and for its computational simplicity. Both approaches achieve the same goal: reducing spatial resolution by a factor of 2.
import torch
import torch.nn as nn
# Option 1: Conv + explicit MaxPool
block_maxpool = nn.Sequential(
nn.Conv2d(32, 64, 3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2, 2) # separate pooling
)
# Option 2: Stride-2 Conv (learnable downsampling)
block_stride = nn.Sequential(
nn.Conv2d(32, 64, 3, padding=1, stride=2), # stride=2
nn.ReLU()
)
x = torch.randn(4, 32, 16, 16)
print(block_maxpool(x).shape) # (4, 64, 8, 8)
print(block_stride(x).shape) # (4, 64, 8, 8) -- same!Pooling Has No Learnable Parameters
An important property of pooling layers is that they have no learnable parameters. Max pooling simply selects the maximum; average pooling computes the mean. This makes pooling layers very fast and memory-free — they do not contribute to the parameter count. The lack of parameters also means pooling cannot overfit. This is why global average pooling at the end of a network is a strong regulariser — it forces the network to encode information in each channel's average, not in spatial positions.
import torch.nn as nn
pool = nn.MaxPool2d(2, 2)
avg_pool = nn.AvgPool2d(2, 2)
# Count parameters
max_params = sum(p.numel() for p in pool.parameters())
avg_params = sum(p.numel() for p in avg_pool.parameters())
print('MaxPool parameters:', max_params) # 0
print('AvgPool parameters:', avg_params) # 0
# Compare with a Conv2d layer
conv = nn.Conv2d(32, 32, 2, stride=2) # similar operation
conv_params = sum(p.numel() for p in conv.parameters())
print('Conv2d (stride-2) parameters:', conv_params) # 4128Typical CNN Architecture with Pooling
A standard CNN architecture alternates between convolutional blocks (Conv+BN+ReLU) and pooling layers, progressively reducing spatial dimensions while increasing channel count. After the convolutional blocks, global average pooling collapses spatial dimensions, and a linear layer maps to class scores. This pattern produces a network with manageable parameter count, good generalisation, and strong image classification performance.
import torch
import torch.nn as nn
class SimpleCNN(nn.Module):
def __init__(self, num_classes=10):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 32, 3, padding=1), nn.ReLU(),
nn.MaxPool2d(2), # 32->16
nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(),
nn.MaxPool2d(2), # 16->8
nn.Conv2d(64, 128, 3, padding=1), nn.ReLU(),
)
self.pool = nn.AdaptiveAvgPool2d((1, 1)) # GAP
self.classifier = nn.Linear(128, num_classes)
def forward(self, x):
x = self.features(x)
x = self.pool(x).view(x.size(0), -1)
return self.classifier(x)
model = SimpleCNN()
x = torch.randn(4, 3, 32, 32)
print(model(x).shape) # (4, 10)Fractional and Adaptive Pooling
AdaptiveMaxPool2d(output_size) automatically computes the kernel size and stride needed to produce the specified output dimensions, regardless of input size. This is invaluable when you want a fixed-size vector for the classifier but the input images have varying sizes (e.g., object detection, variable-resolution datasets). FractionalMaxPool2d uses randomised pooling regions to add stochasticity, acting as an additional regulariser in some architectures.
import torch
import torch.nn as nn
# Adaptive pooling: always produces 3x3 output
adaptive = nn.AdaptiveMaxPool2d((3, 3))
sizes = [(32, 32), (48, 64), (100, 100)]
for h, w in sizes:
x = torch.randn(2, 64, h, w)
out = adaptive(x)
print(f'Input {h}x{w} -> Output {out.shape[2]}x{out.shape[3]}')
# Always 3x3 regardless of input!
# Fractional max pooling (randomised pooling regions)
frac = nn.FractionalMaxPool2d(kernel_size=2, output_size=(6, 6))
x = torch.randn(2, 32, 12, 12)
print('Fractional pool:', frac(x).shape) # (2, 32, 6, 6)Visualising the Effect of Pooling
To understand what pooling does visually: a feature map before max pooling shows the raw filter response at each pixel. After pooling, the output is spatially coarser — each value represents the strongest response in its neighbourhood. The feature map becomes more abstract and position-independent. Deep in a network, after many rounds of pooling, each neuron's receptive field covers most of the original image, enabling global pattern recognition.
import torch
import torch.nn as nn
# Simulate pooling effect on a feature map
pool2 = nn.MaxPool2d(2, 2)
pool4 = nn.MaxPool2d(4, 4)
x = torch.randn(1, 1, 16, 16)
print('Before pooling:', x.shape) # (1,1,16,16)
print('After 2x2 pool:', pool2(x).shape) # (1,1,8,8)
print('After 4x4 pool:', pool4(x).shape) # (1,1,4,4)
# After 3 rounds of 2x2 pooling on 32x32 input:
pool_3x = nn.Sequential(
nn.MaxPool2d(2), nn.MaxPool2d(2), nn.MaxPool2d(2)
)
print('After 3x 2x2 pool:', pool_3x(torch.randn(1,1,32,32)).shape)
# (1, 1, 4, 4)Quick Check
Test your understanding of Machine Learning with Python concepts from this lesson.
Lesson Recap
In this lesson you learned: MaxPool2d and AvgPool2d reduce spatial dimensions by taking the max or average in each pooling window, providing compact representations and local translation invariance, AdaptiveAvgPool2d produces a fixed output size regardless of input dimensions (used as Global Average Pooling), and pooling has no learnable parameters, making it fast and non-overfitting. Next up we build and train a complete CNN on CIFAR-10.
Häufig gestellte Fragen
Ist die Lektion „Pooling-Schichten: Räumliches Downsampling und Invarianz“ kostenlos?
Ja — der vollständige Text von „Pooling-Schichten: Räumliches Downsampling und Invarianz“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Machine Learning Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Machine Learning Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Pooling-Schichten: Räumliches Downsampling und Invarianz“?
Lernende fügen nach Faltungsschichten MaxPool2d hinzu, berechnen die Ausgabeabmessungen und verstehen, wie Pooling Positionsunabhängigkeit ermöglicht und den Rechenaufwand reduziert. Du übst Machine Learning Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Machine Learning Academy zu starten?
Keine Vorkenntnisse erforderlich. Machine Learning Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.
Wie lange dauert die Lektion „Pooling-Schichten: Räumliches Downsampling und Invarianz“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Machine Learning Academy-Lektion Code schreiben und ausführen?
Ja. Jede Machine Learning Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Faltung und Filter: Kanten und Muster erkennen
- Pooling-Schichten: Räumliches Downsampling und Invarianz
- Ein CNN auf CIFAR-10 erstellen und trainieren
- Datenaugmentation: Transformationen für Robustheit