深度學習(九)——神經網路:最大池化的作用

2023-07-21 21:00:54

一、 torch.nn中Pool layers的介紹

官網連結:

https://pytorch.org/docs/stable/nn.html

1. nn.MaxPool2d介紹

nn.MaxPool2d是在進行影象處理時,Pool layers最常用的函數

官方檔案:MaxPool2d — PyTorch 2.0 documentation

(1)torch.nn.MaxPool2d類

class torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)

(2)引數介紹

  • kernel_size(int or tuple): 用於設定一個取最大值的視窗,如設定為3,那麼會生成一個3×3的視窗

  • stride(int or tuple): 預設值為kernel_size,步幅,和折積層中的stride一樣

  • padding(int or tuple): 填充影象,預設填充的值為0

  • dilation(int): 空洞折積,即折積核之間的距離。如折積核的尺寸為3×3,dilation為1,那麼返回一個大小為5×5的折積核,折積核每個元素與上下左右的元素之間空一格

  • return_indices(bool): 一般用的很少,不做介紹

  • ceil_mode(bool): 預設為False。為True時,輸出的shape使用ceil格式(向上取整,即進一);為False時,輸出的shape使用floor格式(向下取整)。

二、最大池化操作

1. 最大池化操作舉例(理論介紹)

假設有一個5×5的影象和一個3×3的池化核(kenel_size=3),如下圖。池化過程就是將池化核與影象進行匹配。下面介紹最大池化的具體操作。

  • 首先用池化核覆蓋影象,如下圖。然後取到最大值,作為一個輸出。

  • 上圖為第一次最大池化操作,最大值為2。將2作為一個輸出,如下圖。

  • 由於本例未對stride進行設定,故stride採取預設值,即stride=kernel_size=3,池化核移動如下圖(移動方式與上上文中提到的折積核移動方式相同,不再贅述)。由於池化核移動已超出範圍,要不要取這3×2部分的最大值,取決於call_mode的值,若ceil_mode=True,則取最大值,即輸出3;若ceil_mode=False,則不取這部分的值,即這一步不進行池化操作。

    • 假設ceil_mode=True,經過最大池化操作後,輸出的結果如下圖。

    • 假設ceil_mode=False,經過最大池化操作後,輸出的結果如下圖。

2. 操作前後的影象大小計算公式

跟折積操作的計算公式一樣。具體如下:

引數說明:

  • N: 影象的batch_size

  • C: 影象的通道數

  • H: 影象的高

  • W: 影象的寬

計算過程:

  • Input:\( (N,C_{in}​,H_{in}​,W_{in}​)\) or \((C_{in}​,H_{in}​,W_{in}​)\)

  • Output: \((N,C_{out}​,H_{out}​,W_{out}​)\) or \((C_{out}​,H_{out}​,W_{out}​)\)

    • 其中有:

      \(H_{out}​=⌊\frac{H_{in}​+2×padding[0]−dilation[0]×(kernel\_size[0]−1)−1​}{stride[0]}+1⌋\)

      \(W_{out}​=⌊\frac{W_{in}​+2×padding[1]−dilation[1]×(kernel\_size[1]−1)−1​}{stride[1]}+1⌋\)

看論文的時候,有些比如像padding這樣的引數不知道,就可以用這條公式去進行推導

3. 最大池化操作程式碼舉例

依然選取上面的例子,進行程式設計。

import torch
from torch import nn
from torch.nn import MaxPool2d
input=torch.tensor([[1,2,0,3,1],
                    [0,1,2,3,1],
                    [1,2,1,0,0],
                    [5,2,3,1,1],
                    [2,1,0,1,1]],dtype=torch.float32)   #輸入影象資料;與折積操作不同的是,最大池化操作要求輸入的影象資料是浮點數,而不是整數(為整數第23行會報錯)
input=torch.reshape(input,(-1,1,5,5))     #構造影象資料,使其符合輸入標準,即分別為(輸入batch_size待定,1通道,大小為5×5)
print(input.shape)  #[Run] torch.Size([1, 1, 5, 5]);資料格式符合輸入標準

#構造神經網路
class Demo(nn.Module):
    def __init__(self):
        super(Demo,self).__init__()
        self.maxpool1=MaxPool2d(kernel_size=3,ceil_mode=True)  #設定最大池化函數,這裡以ceil_mode=True為例

    def forward(self,input):
        output=self.maxpool1(input)  #將輸入的資料(input)進行最大池化草子哦
        return output

demo=Demo()  #建立神經網路
output=demo(input)
print(output)
"""
[Run]
tensor([[[[2., 3.],
          [5., 1.]]]])

符合前面ceil_mode=True例子的輸出結果一致
"""

4. 為什麼要進行最大池化(最大池化的作用)

  • 最大程度地保留輸入特徵,並使資料量減小

  • 上述例子中輸入影象為5×5,經過最大池化操作之後變成了3×3,甚至為1×1。使得影象特徵得以保留,而資料量大大減少了,對整個網路來說引數減少了,運算速度也變快了

  • 打個比方,這就像看視訊的時候,高清(輸入影象)變(經過最大池化操作)標清(輸出資料)

使用具體圖片範例,介紹最大池化的作用:

from torch import nn
from torch.nn import MaxPool2d
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset=torchvision.datasets.CIFAR10("./dataset",train=False,download=True,transform=torchvision.transforms.ToTensor())
dataloder=DataLoader(dataset,batch_size=64)

#構造神經網路
class Demo(nn.Module):
    def __init__(self):
        super(Demo,self).__init__()
        self.maxpool1=MaxPool2d(kernel_size=3,ceil_mode=True)  #設定最大池化函數,這裡以ceil_mode=True為例

    def forward(self,input):
        output=self.maxpool1(input)  #將輸入的資料(input)進行最大池化草子哦
        return output

demo=Demo()  #建立神經網路

writer=SummaryWriter("logs_maxpool")
step=0

for data in dataloder:
    imgs,targets=data
    writer.add_images("input",imgs,step)
    output=demo(imgs)
    writer.add_images("output",output,step)
    step+=1
writer.close()

對比輸入輸出,可以看出影象更糊了