Poolningslager: Spatial nedsampling och invarians
Ni kommer att lägga till MaxPool2d efter konvolutionslager, beräkna utdatadimensioner och förstå hur poolning ger positionstolerans och minskar beräkningskostnaden.
Poolningslager: Spatial nedsampling och invarians är en gratis lektion i Machine Learning Academy på CoddyKit. Detta är lektion 2 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Machine Learning Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Machine Learning Academy innehåller totalt 4 lektioner.
Varför poolinglager finns
Poolinglager minskar feature maps spatiala dimensioner, vilket minskar beräkning och minnesanvändning samtidigt som representationerna blir mer kompakta. De introducerar också en grad av spatial invarians — små förflyttningar av ett särdrag i indata ger samma poolade utdata. Utan pooling (eller konvolutioner med stride 2) skulle de spatiala dimensionerna förbli konstanta genom alla lager, vilket skulle göra nätverket orimligt beräkningskrävande för stora bilder.
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: att ta maximumvärdet
MaxPool2d delar upp inputens feature map i överlappningsfria fönster och tar det största värdet i varje fönster. Maximumvärdet motsvarar filteraktiveringen med högst styrka på någon position i fönstret — det fångar om särdraget förekom någonstans i området, oavsett exakt position. En 2x2-maxpooling med stride 2 halverar höjd och bredd och minskar den totala spatiala storleken fyra gånger.
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 jämfört med max pooling
AvgPool2d beräknar medelvärdet av värdena i varje poolingfönster i stället för maximumvärdet. Average pooling jämnar ut feature map och bevarar information från alla aktiveringar, medan max pooling kastar bort de svagare aktiveringarna. Max pooling föredras i klassificeringsnätverk där förekomsten av ett särdrag är viktigare än dess genomsnittliga styrka. Average pooling används ofta för global pooling i slutet av ett CNN för att reducera de spatiala dimensionerna.
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) reducerar hela den spatiala dimensionen till ett enda värde per kanal genom att beräkna medelvärdet över alla spatiala positioner. För en feature map med formen (B, C, H, W) ger GAP (B, C) — en vektor med C värden som representerar den genomsnittliga aktiveringen för varje filter över hela bilden. GAP ersätter flatten + stora fullständigt anslutna lager högst upp i klassiska CNN:er (VGG), minskar antalet parametrar drastiskt och fungerar som en kraftfull regulariserare. Det används i ResNet, MobileNet och 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)Beräkning av utdimensioner
Det är enkelt att beräkna de spatiala utdimensionerna efter pooling: output_size = floor((input_size - kernel_size) / stride) + 1. För en 2x2-pooling med stride 2 på en indata med storleken 28x28 blir utdata 14x14. Felbedömning av dimensioner är en vanlig källa till shape-fel. AdaptiveMaxPool2d och AdaptiveAvgPool2d löser detta genom att ta emot önskad utdimension direkt och automatiskt beräkna nödvändigt kernel och stride — idealiskt när Ni vill ha en fast utstorlek oavsett indatans storlek.
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 för translationsinvarians
Pooling ger lokal translationsinvarians: om ett särdrag förflyttas några pixlar hamnar det sannolikt fortfarande i samma poolingfönster och ger samma maximumaktivering. Det innebär att nätverket känner igen en katt oavsett om den befinner sig något till vänster eller höger i bilden. Pooling är dock bara lokalt invariant — stora förflyttningar ger fortfarande andra utdata. Dataaugmentering (slumpmässiga beskärningar och speglingar) behövs för att uppnå global translationsinvarians.
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 jämfört med konvolutioner med stride 2
Moderna CNN-arkitekturer (ResNet, EfficientNet) använder i allt högre grad konvolutioner med stride 2 i stället för separata maxpoolinglager. Fördelen är att konvolutioner med stride 2 är lärbara — nätverket avgör hur nedsamplingen ska göras och kan därmed bevara mer användbar information än den fasta maxoperationen. Max pooling används fortfarande i klassiska arkitekturer (VGGNet, AlexNet) och på grund av sin beräkningsmässiga enkelhet. Båda metoderna uppnår samma mål: att minska den spatiala upplösningen med en faktor 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 har inga lärbara parametrar
En viktig egenskap hos poolinglager är att de inte har några lärbara parametrar. Max pooling väljer helt enkelt maximumvärdet, medan average pooling beräknar medelvärdet. Det gör poolinglager mycket snabba och minnessnåla — de bidrar inte till antalet parametrar. Avsaknaden av parametrar innebär också att pooling inte kan överanpassa. Därför är global average pooling i slutet av ett nätverk en kraftfull regulariserare — den tvingar nätverket att koda information i varje kanals medelvärde, inte i spatiala positioner.
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) # 4128Typisk CNN-arkitektur med pooling
En standardarkitektur för CNN växlar mellan konvolutionsblock (Conv+BN+ReLU) och poolinglager, och minskar gradvis de spatiala dimensionerna samtidigt som antalet kanaler ökar. Efter konvolutionsblocken reducerar global average pooling de spatiala dimensionerna, och ett linjärt lager mappar till klasspoäng. Detta mönster ger ett nätverk med hanterbart antal parametrar, god generalisering och stark prestanda vid bildklassificering.
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)Fraktionell och adaptiv pooling
AdaptiveMaxPool2d(output_size) beräknar automatiskt den kernelstorlek och det stride som behövs för att skapa de angivna utdimensionerna, oavsett indatans storlek. Detta är ovärderligt när Ni vill ha en vektor med fast storlek för klassificeraren men indatabilderna har varierande storlek (till exempel vid objektdetektering och datamängder med varierande upplösning). FractionalMaxPool2d använder slumpmässiga poolingområden för att tillföra stokasticitet och fungerar i vissa arkitekturer som ytterligare en regulariserare.
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)Visualisering av poolingens effekt
För att visuellt förstå vad pooling gör: en feature map före max pooling visar filtrets råa respons vid varje pixel. Efter pooling är utdata spatialt grövre — varje värde representerar den starkaste responsen i sitt närområde. Feature map blir mer abstrakt och mindre beroende av position. Djupt inne i ett nätverk, efter många poolingssteg, täcker varje neurons receptiva fält större delen av den ursprungliga bilden, vilket möjliggör global mönsterigenkänning.
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)Snabb kontroll
Testa Er förståelse av begreppen Machine Learning with Python från den här lektionen.
Sammanfattning av lektionen
I den här lektionen lärde Ni Er att MaxPool2d och AvgPool2d minskar de spatiala dimensionerna genom att ta maximumvärdet eller medelvärdet i varje poolingfönster, vilket ger kompakta representationer och lokal translationsinvarians, att AdaptiveAvgPool2d skapar en fast utdimension oavsett indatans dimensioner (och används som Global Average Pooling), samt att pooling inte har några lärbara parametrar, vilket gör den snabb och fri från överanpassning. Härnäst bygger och tränar vi ett komplett CNN på CIFAR-10.
Lär dig Python med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 30
- Lektioner
- 120
Vanliga frågor
Är lektionen ”Poolningslager: Spatial nedsampling och invarians” gratis?
Ja – hela texten till ”Poolningslager: Spatial nedsampling och invarians” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Machine Learning Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i Machine Learning Academy innehåller totalt 4 lektioner.
Vad lär jag mig i ”Poolningslager: Spatial nedsampling och invarians”?
Ni kommer att lägga till MaxPool2d efter konvolutionslager, beräkna utdatadimensioner och förstå hur poolning ger positionstolerans och minskar beräkningskostnaden. Ni övar på Machine Learning Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Machine Learning Academy?
Du behöver inga förkunskaper. Utbildningen i Machine Learning Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”Poolningslager: Spatial nedsampling och invarians”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Machine Learning Academy-lektionen?
Ja. Varje Machine Learning Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Konvolution och filter: Upptäcka kanter och mönster
- Poolningslager: Spatial nedsampling och invarians
- Bygga och träna ett CNN på CIFAR-10
- Dataaugmentering: Transformer för robusthet