一、池化層概述
在卷積神經網絡中,池化層是核心組件之一,主要作用是逐步降低特征圖的空間尺寸即寬和高,從而減少計算量、控制過擬合并增強模型的魯棒性。
核心作用
- 降維與減少計算量
壓縮特征圖的尺寸,顯著減少后續層的參數數量和計算負擔。 - 引入平移不變性
對微小位置變化不敏感。如輸入圖像中目標物體稍微移動后,池化層仍能提取相同特征。 - 抑制噪聲與保留主要特征
通過取局部區域的最大值或平均值,保留顯著特征并過濾細節噪聲。 - 擴大感受野
使后續層能融合更廣闊區域的上下文信息。
1. 最大池化
原理:取滑動窗口內的最大值。
例子:對 4×4 特征圖進行 2×2 窗口 + 步長2 的最大池化:
可以使用torch.nn.MaxPool2d構造最大池化層:
maxpool_layer = torch.nn.MaxPool2d(kernel_size, # 池化窗口的大小stride=None, # 池化操作的步長,默認等于窗口大小padding=0, # 零像素的邊緣填充數量dilation=1, # 擴張元素的數量return_indices=False, # 返回池化取值的索引,并通過nn.MaxUnpool2d()進行反池化ceil_mode=False # 在輸出尺寸中是否使用向上取整代替向下取整)
輸入特征圖(4×4):
[[1, 2, 5, 3],[4, 9, 6, 8],[7, 1, 4, 2],[3, 5, 2, 6]]池化操作:
| 1 2 | 5 3 | → 取 max(1,2,4,9)=9 | 取 max(5,3,6,8)=8
| 4 9 | 6 8 |
-------------------
| 7 1 | 4 2 | → 取 max(7,1,3,5)=7 | 取 max(4,2,2,6)=6
| 3 5 | 2 6 |輸出特征圖(2×2):
[[9, 8],[7, 6]]
效果:保留邊緣、紋理等顯著特征。
2. 平均池化
原理:取滑動窗口內的平均值。
例子:相同輸入,進行 2×2 平均池化:
可以使用torch.nn.AvgPool2d構造平均池化層:
avgpool_layer = torch.nn.AvgPool2d(kernel_size, # 池化窗口的大小stride=None, # 池化操作的步長,默認等于窗口大小padding=0, # 零像素的邊緣填充數量ceil_mode=False # 在輸出尺寸中是否使用向上取整代替向下取整count_include_pad=True, # 計算均值時是否考慮填充像素divisor_override=None # 若指定將用作平均操作中的除數)
| 1 2 | 5 3 | → 平均 = (1+2+4+9)/4 = 4 | (5+3+6+8)/4 = 5.5
| 4 9 | 6 8 |
-------------------
| 7 1 | 4 2 | → 平均 = (7+1+3+5)/4 = 4 | (4+2+2+6)/4 = 3.5輸出特征圖(2×2):
[[4.0, 5.5],[4.0, 3.5]]
適用場景:全局信息平滑如圖像分類的背景區域。
應用:
- 目標檢測:最大池化保留物體的關鍵特征如貓的耳朵,即使位置輕微變化仍能被識別。
- 減少過擬合:通過降低特征圖尺寸,強制網絡學習更泛化的模式。
- 加速訓練:減少全連接層的參數如將 200×200 特征圖池化為 100×100,后續計算量減少75%。
改進:
- 趨勢:部分網絡(如ResNet)用步長>1的卷積層替代池化層,在降維的同時學習特征。
- 全局平均池化(Global Average Pooling):將整個特征圖池化為一個值(替代全連接層),極大減少參數(如用于Inception、SqueezeNet)。
二、卷積層參數如何計算
2.1 參數數量計算
#例子
class CNN(nn.Module):def __init__(self, activation="relu"):super(CNN, self).__init__()self.activation = F.relu if activation == "relu" else F.selu#輸入通道數,圖片是灰度圖,所以是1,圖片是彩色圖,就是3,輸出通道數,就是卷積核的個數(32,1,28,28)self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, padding=1)#輸入x(32,32,28,28) 輸出x(32,32,28,28)self.conv2 = nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=1)self.pool = nn.MaxPool2d(2, 2) #池化核大小為2(2*2),步長為2self.conv3 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=1)self.conv4 = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, padding=1)self.conv5 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, padding=1)self.conv6 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, padding=1)self.pool2 = nn.MaxPool2d(2, 2) #輸入(128,7,7) 輸出(128,3,3)self.flatten = nn.Flatten()# input shape is (28, 28, 1) so the fc1 layer in_features is 128 * 3 * 3self.fc1 = nn.Linear(128 * 3 * 3, 128)self.fc2 = nn.Linear(128, 10) #輸出尺寸(32,10)self.init_weights()
1. **卷積層 **
參數數量 = (in_channels × out_channels × kernel_height × kernel_width) + out_channels
- 權重參數:
in_channels × out_channels × kernel_size2
- 偏置參數:
out_channels
(每個輸出通道一個偏置)
2. **全連接層 **
參數數量 = (in_features × out_features) + out_features
- 權重參數:
in_features × out_features
- 偏置參數:
out_features
3. 池化層/ Flatten 層
參數數量 = 0
(無訓練參數)
以下是CNN模型中每一層的參數數量計算和輸出尺寸變化的詳細說明(輸入為 (batch_size, 1, 28, 28)
):
- Conv1 層
- 輸入尺寸:
(batch_size, 1, 28, 28)
- 輸出尺寸:
(batch_size, 32, 28, 28)
- Padding=1 保持空間尺寸不變(
(28 + 2 - 3)/1 + 1 = 28
)。
- Padding=1 保持空間尺寸不變(
- 參數數量:
- 權重:
1 × 32 × 3 × 3 = 288
- 偏置:
32
- 總計:
288 + 32 = 320
- 權重:
- Conv2 層
- 輸入尺寸:
(batch_size, 32, 28, 28)
- 輸出尺寸:
(batch_size, 32, 28, 28)
- Padding=1 保持尺寸不變。
- 參數數量:
- 權重:
32 × 32 × 3 × 3 = 9,216
- 偏置:
32
- 總計:
9,216 + 32 = 9,248
- 權重:
- Pool 層(MaxPool2d, kernel=2, stride=2)
- 輸入尺寸:
(batch_size, 32, 28, 28)
- 輸出尺寸:
(batch_size, 32, 14, 14)
- 下采樣公式:
(28 - 2)/2 + 1 = 14
。
- 下采樣公式:
- 參數數量:
0
(池化層無參數)
- Conv3 層
- 輸入尺寸:
(batch_size, 32, 14, 14)
- 輸出尺寸:
(batch_size, 64, 14, 14)
- Padding=1 保持尺寸不變。
- 參數數量:
- 權重:
32 × 64 × 3 × 3 = 18,432
- 偏置:
64
- 總計:
18,432 + 64 = 18,496
- 權重:
- Conv4 層
- 輸入尺寸:
(batch_size, 64, 14, 14)
- 輸出尺寸:
(batch_size, 64, 14, 14)
- 參數數量:
- 權重:
64 × 64 × 3 × 3 = 36,864
- 偏置:
64
- 總計:
36,864 + 64 = 36,928
- 權重:
- Pool 層(再次使用,kernel=2, stride=2)
- 輸入尺寸:
(batch_size, 64, 14, 14)
- 輸出尺寸:
(batch_size, 64, 7, 7)
- 下采樣:
(14 - 2)/2 + 1 = 7
。
- 下采樣:
- 參數數量:
0
- Conv5 層
- 輸入尺寸:
(batch_size, 64, 7, 7)
- 輸出尺寸:
(batch_size, 128, 7, 7)
- Padding=1 保持尺寸不變。
- 參數數量:
- 權重:
64 × 128 × 3 × 3 = 73,728
- 偏置:
128
- 總計:
73,728 + 128 = 73,856
- 權重:
- Conv6 層
- 輸入尺寸:
(batch_size, 128, 7, 7)
- 輸出尺寸:
(batch_size, 128, 7, 7)
- 參數數量:
- 權重:
128 × 128 × 3 × 3 = 147,456
- 偏置:
128
- 總計:
147,456 + 128 = 147,584
- 權重:
- Pool2 層(MaxPool2d, kernel=2, stride=2)
- 輸入尺寸:
(batch_size, 128, 7, 7)
- 輸出尺寸:
(batch_size, 128, 3, 3)
- 下采樣:
(7 - 2)/2 + 1 = 3
(向下取整)。
- 下采樣:
- 參數數量:
0
- Flatten 層
- 輸入尺寸:
(batch_size, 128, 3, 3)
- 輸出尺寸:
(batch_size, 128 × 3 × 3) = (batch_size, 1,152)
- 參數數量:
0
- FC1 層(全連接層)
- 輸入尺寸:
(batch_size, 1,152)
- 輸出尺寸:
(batch_size, 128)
- 參數數量:
- 權重:
1,152 × 128 = 147,456
- 偏置:
128
- 總計:
147,456 + 128 = 147,584
- 權重:
- FC2 層(全連接層)
- 輸入尺寸:
(batch_size, 128)
- 輸出尺寸:
(batch_size, 10)
- 參數數量:
- 權重:
128 × 10 = 1,280
- 偏置:
10
- 總計:
1,280 + 10 = 1,290
- 權重:
完整計算流程(輸入 (1, 28, 28))
層 | 輸出尺寸 | 參數計算 | 參數數量 |
---|---|---|---|
Conv1 | (32, 28, 28) | (1×32×3×3) + 32 | 320 |
Conv2 | (32, 28, 28) | (32×32×3×3) + 32 | 9,248 |
Pool1 | (32, 14, 14) | 無參數 | 0 |
Conv3 | (64, 14, 14) | (32×64×3×3) + 64 | 18,496 |
Conv4 | (64, 14, 14) | (64×64×3×3) + 64 | 36,928 |
Pool2 | (64, 7, 7) | 無參數 | 0 |
Conv5 | (128, 7, 7) | (64×128×3×3) + 128 | 73,856 |
Conv6 | (128, 7, 7) | (128×128×3×3) + 128 | 147,584 |
Pool3 | (128, 3, 3) | 無參數 | 0 |
Flatten | (1152,) | 無參數 | 0 |
FC1 | (128,) | (1152×128) + 128 | 147,584 |
FC2 | (10,) | (128×10) + 10 | 1,290 |
總計 | - | - | 435,306 |
2.2 每層輸出尺寸變換原理
卷積輸出尺寸公式:
假設輸入尺寸為 Hin×Win
卷積核尺寸 K,步長 S,填充 P,輸出尺寸 Hout×Wout 為:
Hout=?Hin+2P?KS?+1
Hout= \left\lfloor \frac{H_{in} + 2P - K}{S} \right\rfloor + 1
Hout=?SHin?+2P?K??+1
Wout=?Win+2P?KS?+1 Wout=\left\lfloor \frac{W_{in} + 2P - K}{S} \right\rfloor + 1 Wout=?SWin?+2P?K??+1
默認設置(最常見):
- kernel_size = 3
- stride = 1
- padding = 1
則:
Hout=Hin,Wout=WinH
即 尺寸不變
當卷積核尺寸 K=2,步長 S=2.填充 P=1時
這個操作會讓圖像尺寸縮小一半:
簡化為:
Hout=?HinS?
Hout= \left\lfloor \frac{H_{in} }{S} \right\rfloor
Hout=?SHin???
例如:
- 輸入
28×28
→14×14
- 輸入
14×14
→7×7
- 輸入
7×7
→3×3
Flatten 展平層
將形如 (batch_size, C, H, W)
的張量展平成 (batch_size, C × H × W)
,準備送入全連接層。
總結
層 | 輸入尺寸 | 操作 | 輸出尺寸 | 說明 |
---|---|---|---|---|
conv1 | 1×28×28 | Conv2d(3, p=1) | 32×28×28 | 尺寸不變,通道變為 32 |
conv2 | 32×28×28 | Conv2d(3, p=1) | 32×28×28 | 尺寸不變 |
pool1 | 32×28×28 | MaxPool2d(2,2) | 32×14×14 | 高寬縮小一半 |
conv3 | 32×14×14 | Conv2d(3, p=1) | 64×14×14 | 通道增加 |
conv4 | 64×14×14 | Conv2d(3, p=1) | 64×14×14 | 通道不變 |
pool2 | 64×14×14 | MaxPool2d(2,2) | 64×7×7 | 再次縮小 |
conv5 | 64×7×7 | Conv2d(3, p=1) | 128×7×7 | 通道增加 |
conv6 | 128×7×7 | Conv2d(3, p=1) | 128×7×7 | 通道不變 |
pool3 | 128×7×7 | MaxPool2d(2,2) | 128×3×3 | 尺寸變為最終 |
flatten | 128×3×3 | Flatten | 1152 | 送入全連接層 |
fc1 | 1152 | Linear(1152→128) | 128 | 隱藏層 |
fc2 | 128 | Linear(128→10) | 10 | 輸出分類結果 |