【學習筆記】Pytorch深度學習-網絡層之池化層、線性層、激活函數層


池化層(Pooling Layer)


圖1 左-最大值池化、右-平均值池化

池化定義
池化運算是對信號進行“收集”並“總結”。由於池化操作類似蓄水池收集水資源,因此得名池化。
(1)收集
通過池化運算將信號由多變少,圖像尺寸由大變小的過程;
(2)總結
如圖1中左圖所示,1張\(\ 4 \times 4\) 的輸入圖像經過\(\ 2 \times 2\) 的池化窗口池化運算后,得到\(\ 2 \times 2\) 的輸出特征圖。原本具有16個像素的圖像變為4個像素進行表示,1個池化窗口內部用1個像素值來表示原本的4個像素值,這一過程就是總結。
在總結方法中,最常用的2種方法是最大值池化、平均值池化,如圖1所示。

Pytorch中池化實現

1、二維最大值池化

1.1 理論

nn.MaxPool2d(kernel_size,stride=None,
             padding=0,dilation=1,
             return_indices=False,
             ceil_mode=False)
功能:對二維信號(圖像)進行最大值池化
主要參數:kernel_size:池化核尺寸
stride:步長  
padding:填充個數
dilation:池化核間隔大小
ceil_mode:尺寸向上取整(Ture:向上;False:默認,向下)
return_indices:記錄池化像素索引

解釋:
(1)ceil_mode: 池化后,在計算輸出特征圖尺寸時,存在1個除法操作。如果除法不能整除時,可通過對ceil_mode進行設置選擇尺寸向上或向下取整;設置ceil_mode=True時,輸出特征圖尺寸采用向上取整;ceil_mode=False時,此為默認設置,輸出特征圖尺寸采用向下取整。
卷積、池化輸出特征圖尺寸簡化版公式:

\[\frac{Insize-kernelsize+2padding}{stride}+1= outsize\,. \]

(2)return_indices: 記錄下來的像素索引,通常會用於最大值反池化操作。早期自編碼器、圖像分割任務通常會利用最大值反池化來進行上采樣, return_indices在反池化中則起着至關重要的作用。
舉個例子:


圖2

圖3 前段-池化、后段-反池化

從圖2、3的網絡結構可以看出,紅色線划分的前段是1個 正常的最大值池化下采樣過程:\(\ 4 \times 4\) 輸入圖像池化得到\(\ 2\times 2\)的特征圖,對於第1個池化窗口首先記錄下最大像素值2的位置索引。該最大像素值經過中間一系列網絡層運算后,變為了3而后進入反池化上采樣環節,通過return_indices記錄的2的索引值把3放到\(\ 4 \times 4\) 圖像中,完成反池化。
總而言之,記錄最大值池化時像素點的索引值,反池化時,可通過該索引值將運算得來的新最大值放到相應的的位置。

1.2 實驗

代碼來自余老師
# ================ maxpool
# flag = 1
flag = 0
if flag:
//參數設置:
// kernel_size—2×2池化核、
// 步長—池化通常不重疊,步長與池化核參數相同;
// 其他均為默認設置
    maxpool_layer = nn.MaxPool2d((2, 2), stride=(2, 2))   # input:(i, o, size) weights:(o, i , h, w)
    img_pool = maxpool_layer(img_tensor)

2、二維平均值池化

2.1 理論

nn.AvgPool2d(kernel_size, stride=None
             padding=0,ceil_mode=False,
             count_include_pad=True,
             divisor_override=None)
功能:對二維信號(圖像)進行平均值池化
主要參數:kernel_size:池化核尺寸
stride:步長
padding:填充個數
ceil_mode:尺寸向上取整
count_include_pad:填充值用於計算(True-用於計算,False-不用於計算)
divisor_override:除法因子

解釋:
divisor_override除法因子:在進行平均值池化時,計算方法是:

\[\frac{池化窗所覆蓋像素點像素值之和}{被覆蓋的像素點個數}= 當前窗口平均值\,. \]

有了除法因子,就不再除以 被覆蓋的像素點個數,而是可以通過任意賦值(見實驗2.2)。

2.2 實驗

代碼來自余老師
#==================AvgPool
flag = 1
# flag = 0
if flag:
    img_tensor = torch.ones((1, 1, 4, 4)) //創建張量
    avgpool_layer = nn.AvgPool2d((2, 2), stride=(2, 2), divisor_override=3) //設置平均值池化中除法因子為3
    img_pool = avgpool_layer(img_tensor)

print("raw_img:\n{}\npooling_img:\n{}".format(img_tensor, img_pool))

實驗意味着,原本\(\ 4 \times 4\)的輸入圖像經過池化下采樣得到\(\ 2\times 2\)的特征圖。1個\(\ 2\times 2\)池化窗口內,像素值計算變為:

\[\frac{像素值之和:1+1+1+1}{除法因子3}= 當前窗口平均值1.3333...\,. \]


圖4 平均值池化:除法因子改變對池化結果的影響

3、二維最大值反池化

3.1、理論

nn.MaxUnpool2d(kernel_size,stride=None,
               padding=0)
功能:對二維信號(圖像)進行最大值反池化(池化上采樣)
主要參數:kernel_size:池化核尺寸
stride:步長
padding:填充個數

forward(self,input,indices,output_size=None)

解釋:
后段進入【反池化層】,從\(\ 2\times 2\)輸入圖像上采樣到\(\ 4\times 4\)輸出特征圖,涉及到像素點放在哪里的問題。這一步就可依靠【最大值池化層】中的return_indices來記錄索引,【最大值池化層】中最大像素值的索引傳入到【反池化層】中,如反池化層中紅色標注的各個像素點,將當前\(\ 2\times 2\)輸入圖像中的像素點放在對應的位置上。因此,【最大反池化】參數與【最大值池化】參數類似,只是在forward時需要多傳入indices索引參數。


圖5 第1層:輸入圖像 第2層:最大值池化特征圖 ....一系列網絡層..... 第3層:輸入特征圖 第4層:反池化層

3.2、實驗

# ================ max unpool
flag = 1
# flag = 0
if flag:
    # pooling【最大值池化】
    img_tensor = torch.randint(high=5, size=(1, 1, 4, 4), dtype=torch.float) //隨機初始化1個尺寸為4*4的圖像
    maxpool_layer = nn.MaxPool2d((2, 2), stride=(2, 2), return_indices=True) //設置最大值池化參數,記錄索引
    img_pool, indices = maxpool_layer(img_tensor)

    # unpooling【最大值反池化】
    img_reconstruct = torch.randn_like(img_pool, dtype=torch.float)
     //這一步形如圖5中第3層,其參數應與第二層輸出特征圖一樣,
    //因此用randn_like(img_pool)進行初始化
    maxunpool_layer = nn.MaxUnpool2d((2, 2), stride=(2, 2))
    img_unpool = maxunpool_layer(img_reconstruct, indices)

    print("raw_img:\n{}\nimg_pool:\n{}".format(img_tensor, img_pool))
    print("img_reconstruct:\n{}\nimg_unpool:\n{}".format(img_reconstruct, img_unpool))

結果:


圖6 實驗結果

圖7 第1層:輸入圖像 第2層:最大值池化特征圖 ....一系列網絡層..... 第3層:輸入特征圖 第4層:最大值反池化層

線性層(Linear Layer)

線性層定義
線性層又稱為全連接層,其每個神經元與上一層所有神經元相連,實現對前一層的線性組合,線性變換。
線性層功能
在卷積神經網絡進行分類時,輸出分類結果前,通常采用全連接層對特征進行處理。Pytorch中全連接層又稱為Linear線性層,因為如果不考慮激活函數的非線性性質,那么全連接層就是對輸入數據進行線性組合,因此而得名"線性層"。

以圖8為例,觀察2層全連接網絡:
(1)連接方式:每個神經元與上一層所有神經元相連
(2)運算方式:每個神經元的輸出結果是對上一層輸入值的加權求和,即采用前一層的輸入乘以權值、相加然后輸出。
例如,圖8中看到隱藏層第1個神經元有3個箭頭指向它,說明有3個輸入。這3個輸入 乘以對應權值並求和得到該神經元的輸出結果:

\[\ 1\times 1 +2 \times 1+3 \times 1= 6\, \]

以此類推,通過矩陣乘法得到隱藏層的全部輸出值。


圖8 線性層運算原理
**Pytorch中線性層實現-nn.Linear** ``` nn.Linear(in_features,out_features,bias=True) 功能:對一維信號(向量)進行線性組合 主要參數:in_features:輸入結點數 out_features:輸出結點數 bias:是否需要偏置 ``` **nn.Linear計算公式**$\ y=X\mathbf{W}^\mathrm{T}+bias$ 注意:由於計算過程中,會自動將權值矩陣$\ W$進行轉置$\mathbf{W}^\mathrm{T}$,因此輸入的權值矩陣應當注意形狀和數值(見實驗)

nn.Linear實驗

# ================ linear
# flag = 1
flag = 0
if flag:
    inputs = torch.tensor([[1., 2, 3]])
    linear_layer = nn.Linear(3, 4)  
    linear_layer.weight.data = torch.tensor([[1., 1., 1.],
                                             [2., 2., 2.],
                                             [3., 3., 3.],
                                             [4., 4., 4.]])
 //形狀變為4×3的權值矩陣
    linear_layer.bias.data.fill_(0.5)
    output = linear_layer(inputs)
    print(inputs, inputs.shape)
    print(linear_layer.weight.data, linear_layer.weight.data.shape)
    print(output, output.shape)

可以看到代碼中,權值矩陣\(\ W\)變為\(\ 4\times 3\)的,這是因為計算過程中會自動將其轉置為\(\ 3\times 4\)再運算。


圖9 Pytorch中線性層運算機制

激活函數層( Activation Layer)

激活函數層功能
激活函數對特征進行非線性變換,賦予多層神經網絡具有深度的意義。


神經網絡中通常會采用全連接層進行疊加,例如Lenet輸出分類結果時,采用了3個全連接層進行疊加;同時在每個全連接層輸出時添加1個非線性激活函數層,它賦予了多層神經網絡具有深度的意義


分析


圖10 不具有激活函數的多層神經網絡

\[\ output=X\times W 等價於 H_1=X\times W_1 \, \]

由圖可以看出,多層神經網絡由於矩陣乘法的結合性退化成了單層。 如果加入了非線性激活函數,那么多個矩陣相乘的公式就不成立了:

\[\ W\ne W_1*W_2*W_3\, \]

多層神經網絡也就不會退化。

1、激活函數sigmoid()—nn.sigmoid


圖11 sigmoid()函數
計算公式 \(\ y= \frac{1}{1+e^{-x} \quad}\)
梯度公式 \(\ y^{'}= y*(1-y)\)
特性 1、輸出值在(0,1),符合概率
2、導數范圍是[0,0.25],易導致梯度消失
3、輸出為非0均值,破壞數據分布

分析
由圖11可知,
(1)符合概率:藍色曲線為sigmoid函數值。其函數值在(0,1),符合概率值的區間,sigmoid()因此也常用作二分類輸出的激活函數;在循環神經網絡RNN中,也作為各種門控單元的激活函數用來控制信息的流動。
(2)梯度消失:黃色曲線為導函數。導函數有2個飽和區,易導致梯度消失, 若神經元落入到飽和區,梯度幾乎為0,就無法反向傳播梯度、更新權重了。
(3)破壞數據分布:由曲線圖可以看出,sigmoid函數值都是大於0的,形成非0均值的數據分布。

2、雙曲正切函數Tanh()—nn.Tanh

計算公式 \(\ y=\frac{sinx}{cosx}= \frac{e^x-e^{-x}\quad }{e^x+e^{-x}\quad}=\frac {2}{1+e^{-x}\quad}+1\)
梯度公式 \(\ y^{'}= 1-y^{2}\)
特性 1、輸出值在(-1,1),數據分布符合0均值
2、導數范圍是(0,1),易導致梯度消失

圖12 Tanh()函數

分析
由圖12可知,
(1)破壞數據分布現象有所"減緩":藍色曲線為輸出函數,其范圍為(-1,1),均值控制在0均值。
(2)梯度消失:黃色曲線為導函數,范圍為()導函數仍有2個飽和區,雖然數值有所增大,但仍易導致梯度消失。

為什么上述兩種激活函數都會導致梯度消失?


3、線性修正單元ReLU()—nn.ReLU
為了解決sigmoid和Tanh飽和激活函數的梯度消失這一問題,就提出了線性修正單元ReLU以解決。


圖13 ReLU修正線性單元
計算公式 \(\ y=max(0,x)\)
梯度公式 \(\ y = \begin{cases} 1, & x > 0 \\undefined, & x=0\\0,& x<0 \end{cases}\)
特性 1、輸出值均為正數,負半軸導致死神經元
2、導數是1,緩解梯度消失,但是引發梯度爆炸

分析
由圖13可知,
(1)何為修正?正半軸輸出函數值 \(\ y=x\),但負半軸不再服從線性關系,輸出為0,因此稱為修正線性單元
(2)導函數值:正半軸梯度為1,鏈式求導每次乘以1不會改變梯度尺度,不會造成梯度消失。但隨着梯度不斷相乘,也有可能造成梯度不斷變大而造成梯度爆炸的問題。
(3)函數值:負半軸輸出函數值均為0,導致死神經元現象,導致經過激活函數后沒有輸出。
針對負半軸死神經元而引起的一系列問題,有很多改進。

3種改進的ReLU修正線性單元
針對負半軸死神經元而引起的一系列問題,有很多改進。


圖14 3種激活函數曲線

(1)nn.LeakyReLU(negative_slope):負半軸增加了1個很小的斜率,該斜率一旦設置就是固定的(如圖所示曲線是增加了0.01的斜率);
(2)nn.PReLU(init):P表示斜率是可學習的參數,init用來設置可學習斜率的初始化值(如圖所示初始化為0.25,隨着網絡的迭代更新,該斜率值是會變化的);
(3)nn.RReLU(lower均勻分布下限/upper均勻分布上限):R表示每一次的斜率都是隨機的從1個均勻分布中采樣得到的(如圖綠色曲線所示,每一次斜率都有變化)。

關於激活函數可查閱:
激活函數的更多資料

總結
1、池化層:最大值池化、平均值池化、最大值反池化上采樣
2、線性層:分析了如果沒有非線性激活函數的加入,再多的線性層的疊加都等價於1層。
3、常用的激活函數sigmoid、Tanh,但這兩類飽和激活函數會引發梯度消失,可采用非飽和激活函數ReLU進行替換,針對ReLU在負半軸導致死神經元的一系列問題,有一些變種函數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM