您當前的位置:首頁 > 文化

深度學習之殘差神經網路(ResNet)

作者:由 Apache 發表于 文化時間:2022-02-04

寫在前面

自2012年AlexNet在ImageNet圖片分類比賽中大獲成功以來,關於深度神經網路的研究又一次如火如荼般進行,在2015年ResNet奪魁到達頂峰。此後的無數卷積神經網路,似乎都有了ResNet的影子,例如DenseNet等等。那麼ResNet究竟有何神奇之處?本文將基於何愷明等人的論文

Deep Residual Learning for Image Recognition

和其他相關資料,探討ResNet的細節所在。

為什麼ResNet會誕生

深度神經網路由於其具有很多層數(卷積層+全連線層)而冠以“深度”之名,基於神經網路的機器學習演算法因此也被稱作“深度學習”(由此可見AI從業者的包裝能力之強)。然而隨著算力的不斷增強、資料集的不斷擴張,一系列問題隨之而來,例如:

· 層數越多,訓練效果一定越好嗎?

· 如何最佳化過深的神經網路?

· 如何避免梯度消失和梯度爆炸?

對於第一個問題,不假思索來看,在相同的最佳化條件下,更深神經網路的訓練效果更強是十分顯然的,然而由於引數過多、模型複雜度更高,深層神經網路會出現十分嚴重的過擬合問題,即訓練集與測試集準確度之間的gap過大,由此引發了一系列的正則化方法,在此先按下不表。

然而,何愷明在實際實驗時發現,不僅是測試精度,而且在訓練精度上,更深的(56層)神經網路也遠不如淺一些的(20層)神經網路(如下圖)。

深度學習之殘差神經網路(ResNet)

更深的神經網路訓練和測試精度均不如淺層網路

由此引出了問題:

Is learning better networks as easy as stacking more layers?

對於以上問題而言,除了十分棘手的梯度消失/梯度爆炸,以及過擬合的問題之外(以上議題將會在未來的更新中涉及),一個十分嚴峻的挑戰在於負最佳化問題(degradation)。也就是說,56層的神經網路相比於20層,新增加的36層是對神經網路的“惡化”,它們非但沒有起到自己應有的作用,反而扭曲了網路空間,升高了training error。

由此一個想法自然而然的產生:如果這36層神經網路是恆等對映(identity mapping),那麼56層的神經網路不就和20層的一樣好了嗎?

更進一步呢?如果這36層神經網路相比於恆等對映再好上那麼一點點(更接近最優函式),那麼不就起到了正最佳化的作用了嗎?ResNet的insight由此誕生。

ResNet的數學表示

基於以上的考慮,我們在所擬合的函式中加入恆等函式。

假設某一層內,最優函式記為

H(x)

,那麼我們所擬合的目標函式

F(x)

定義為

F(x):=H(x)-x

,函式

F(x)

被稱為“殘差函式”。

由此可見,我們所需要的函式由兩部分組成:恆等函式和殘差函式。恆等函式的存在,避免了“負最佳化”問題,而殘差函式則起到了“錦上添花”的作用。

這一做法基於這樣的假設:最優函式與線性函式有較高的相似性,極端來看,若最優函式就是線性函式,那麼我們的最佳化就會變得極為容易,因為F(x)的引數在初始化時接近於0,因此不會在訓練過程中獲取較大的梯度,因而不會影響恆等函式的表現。

因此,ResNet的基本架構就由如下圖的殘差塊所組成。

深度學習之殘差神經網路(ResNet)

殘差塊

殘差塊中的恆等函式部分,也被稱為shortcut connection(or skip link)。

對應到神經網路中,殘差塊的數學表示式可以寫成:

y=\sigma(F(x,W)+x)

其中,

y

代表殘差塊的輸出,

\sigma(·)

代表啟用函式,

F(·)

代表殘差函式,

x

代表輸入,

W

代表殘差塊內的所有權重。

當然,在全連線層中,如果

\sigma

項的維度與

x

不同,則可以用一個變換矩陣

W

x

相乘(即對

x

做線性對映);如果在卷積層中二者形狀不同,則可以使用1*1卷積核(kernel)和zero-padding使得二者的維度與通道數相等。

殘差塊的程式碼實現(PyTorch)

注:部分內容參考了李沐等所著《Dive into Deep Learning》

ResNet沿用VGG完整的3*3卷積層設計,並使用了Batch Normalization層和ReLU啟用函式,此外引入了額外的1*1卷積層將輸入變換為需要的形狀,與殘差函式結果直接相加。

殘差塊的實現如下:

import

torch

from

torch

import

nn

from

torch。nn

import

functional

as

F

class

Residual

nn

Module

):

def

__init__

self

input_channels

num_channels

use_conv

=

False

strides

=

1

):

super

()

__init__

()

self

conv1

=

nn

Conv2d

input_channels

num_channels

kernel_size

=

3

padding

=

1

stride

=

strides

self

conv2

=

nn

Conv2d

num_channels

num_channels

kernel_size

=

3

padding

=

1

if

use_conv

self

conv3

=

nn

Conv2d

input_channels

num_channels

kernel_size

=

3

padding

=

1

else

self

conv3

=

None

self

bn1

=

nn

BatchNorm2d

num_channels

self

bn2

=

nn

BatchNorm2d

num_channels

def

forward

self

X

):

Y

=

F

relu

self

bn1

self

conv1

X

)))

Y

=

self

bn2

self

conv2

Y

))

if

self

conv3

X

=

self

conv3

X

Y

+=

X

return

F

relu

Y

如下圖所示,此程式碼生成兩種型別的網路,分別對應形狀一致和不同的情況,透過use_conv來判斷是否改變輸入的形狀。

深度學習之殘差神經網路(ResNet)

殘差塊架構

透過以上的程式碼,我們構造出了殘差塊單元。由於其繼承了nn。Module,因此可以直接將其作為nn。Sequential()的引數進行ResNet的架構。這會在之後的內容中加以呈現。

為什麼需要Shortcut Connection

1、最佳化梯度回傳

在梯度更新的步驟,我們一般使用反向傳播法(backpropagation)來計算損失函式對於權重的梯度,並加以更新。然而在深層的神經網路中,由於各種原因(比如啟用函式的飽和性(saturated)、權重的分佈不佳等等),梯度在反向傳播的過程中,訊號會逐漸消失,這會導致頂層權重更新速度快,而底層權重幾乎不更新的情況。這是災難性的,因為底層所提取到的特徵往往更為重要,例如邊緣、紋理等等更為普遍的性質,從而使得訓練效果不佳。

除此之外,在一般的神經網路中,如果某一層停止學習,則訊號就會在此消失,而無法傳到更底層,從而造成“梯度消失”現象。

然而,在shortcut connection的存在下,梯度回傳時,即使幾層還沒有開始學習(殘差函式的梯度接近零),由於恆等函式的導數恆為1,整個函式的梯度依然接近於1,根據鏈式法則,先前的梯度依然可以反向傳播,網路也可以開始取得進展(見下圖)。藉助shortcut connection,訊號可以輕鬆地在整個網路中傳播,從而避免了“梯度消失”。

深度學習之殘差神經網路(ResNet)

殘差網路中,梯度傳播更加順暢

2、殘差函式訓練更容易

讓我們複習一下:在訓練神經網路時,目標是使其成為目標函式H(x)的模型。如果將輸入x(即恆等函式)新增到網路的輸出,則網路則被迫建模殘差函式F(x),這稱為

殘差學習

如前所述,ResNet基於這樣一種假設:最優函式與線性函式有一定的相似性。初始化常規神經網路時,其權重引數接近零,因此網路僅輸出其輸入的副本。換言之,它首先對恆等函式建模。所以如果目標函式和恆等函式相當接近(通常是這種情況),那麼訓練速度會大大加快。這也是殘差學習相對更加容易的原因。

此外,利用殘差塊可以訓練出一個有效的深層神經網路:輸入可以透過層間的殘餘連線更快地向前傳播。

*3、巢狀函式類的實現

ResNet的提出,最初是為了解決“負最佳化”問題,也就是說讓更深層的網路表現的至少和淺層網路一樣好。這就涉及函式類的概念。

注:以下內容來源於

Dive into Deep Learning by Mu Li, et al。

假設我們有一類特定的神經網路架構

F

,它包括學習率及其他超引數。對於所有

f\in F

,存在一些引數集(包括權重和偏置),這些引數可以透過在合適的訓練集上進行訓練所獲得。現在假設

f^*

是我們真正想要找到的函式,如果

f^*\in F

,那麼我們可以輕而易舉地獲得它,但通常我們不會那麼幸運。相反,我們將嘗試找到一個函式

f^*_F

,這是我們在

F

中的最佳選擇。例如,給定一個具有

X

特性和

y

標籤的資料集,我們可以嘗試透過解決以下最佳化問題來找到它:

f^*_F:=\mathop{argmin}\limits_{f\in F}(X,y,f)

那麼,怎樣得到更近似真正

f^*

的函式呢?唯一合理的可能性是,我們需要設計一個更強大的架構

F

。換句話說,我們預計

f^*_{F

f^*_F

“更近似”。然而,如果

F\not\in F

,則無法保證新的體系“更近似”。事實上,

f^*_{F

可能更糟:如圖所示,對於非巢狀函式(non-nested function)類,較複雜的函式類並不總是向“真”函式

f^*

靠攏(複雜度由

F_1

F_6

遞增)。在下圖的左邊,雖然

F_3

F_1

更接近

f^*

,但

F_6

卻離得更遠了。相反對於下圖右側的巢狀函式(nested function)類

F_1\in \cdots \in F_6

,我們可以避免上述問題。

深度學習之殘差神經網路(ResNet)

巢狀函式類和非巢狀函式類

因此,只有當較複雜的函式類包含較小的函式類時,我們才能確保提高它們的效能。對於深度神經網路,如果我們能將新新增的層訓練成恆等對映,新模型將和原模型同樣有效。同時,由於新模型可能得出更優的解來擬合訓練資料集,因此新增層似乎更容易降低訓練誤差。

如上所述,透過加入shortcut connection,我們構造出了一系列“巢狀函式類”,使得層數越多,訓練效果越好。

也許有人疑問,難道殘差函式不會對恆等函式“負最佳化”嗎?假設最優函式就是恆等函式,那麼在最初的訓練中,由於殘差函式部分的權重初始化接近於零,因此它們並不會獲得較大的梯度(相較於1),在更新時也只會發生極其有限的改變,對於恆等函式的影響幾乎可以忽略不計。因此,即使在最極端的情況下(最優函式等於恆等函式),殘差函式也並不會產生“肉眼可見”的degradation。

殘差神經網路(ResNet)的架構及程式碼實現

注:部分內容參考了

Dive into Deep Learning by Mu Li, et al。

ResNet的前兩層與GoogLeNet中一樣:在輸出通道數為64,步幅為2的7*7卷積層後,接步幅為2的3*3的最大池化層。不同之處在於ResNet每個卷積層後增加了Batch Norm層。程式碼如下(需要之前的所有程式碼):

b1

=

nn

Sequential

nn

Conv2d

1

64

kernel_size

=

7

stride

=

2

padding

=

3

),

nn

BatchNorm2d

64

),

nn

ReLU

(),

nn

MaxPool2d

kernel_size

=

3

stride

=

2

padding

=

1

))

之後,ResNet使用了4個由殘差塊組成的

模組

,每個模組使用若干個同樣輸出通道數的殘差塊。第一個模組的通道數同輸入通道數一致。由於之前已經使用了步幅為2的最大池化層,所以無需減小高和寬。之後的每個模組在第一個殘差塊裡將上一個模組的通道數翻倍,並將高寬減半。

下面是程式碼實現,注意,我們對第一個模組做了特別處理。

def

resnet_block

input_channels

num_channels

num_residuals

first_block

=

False

):

blk

=

[]

for

i

in

range

num_residuals

):

if

i

==

0

and

not

first_block

blk

append

Residual

input_channels

num_channels

use_conv

=

True

strides

=

2

))

else

blk

append

Residual

num_channels

num_channels

))

return

blk

接著在ResNet加入所有殘差塊,這裡每個模組使用2個殘差塊。

b2

=

nn

Sequential

*

resnet_block

64

64

2

first_block

=

True

))

b3

=

nn

Sequential

*

resnet_block

64

128

2

))

b4

=

nn

Sequential

*

resnet_block

128

256

2

))

b5

=

nn

Sequential

*

resnet_block

256

512

2

))

最後,與GoogLeNet一樣,在ResNet中加入全域性平均池化層,以及全連線層輸出。

net

=

nn

Sequential

b1

b2

b3

b4

b5

nn

AdaptiveAvgPool2d

((

1

1

)),

nn

Flatten

(),

nn

Linear

512

10

))

每個模組有4個卷積層(不包括恆等對映的1*1卷積層)。加上第一個7*7卷積層和最後一個全連線層,共有18層。因此這種模型被稱為ResNet-18,其架構圖如下:

深度學習之殘差神經網路(ResNet)

此外,在何愷明等的論文中,給出了ResNet-34的架構圖:

深度學習之殘差神經網路(ResNet)

ResNet的意義和引申

何愷明等人使用ResNet贏得了ILSVRC 2015挑戰賽,其錯誤率低至3。57%,已經超越了人的識別能力(大約5%)。這是一個劃時代的成就。

除此之外,ResNet的出現還啟發了之後的諸多神經網路架構,例如DenseNet,受到ResNet的shortcut connection和泰勒展開式的啟發,構建了類似多項式的稠密連線方式,是ResNet的邏輯擴充套件。其模式圖如下:

深度學習之殘差神經網路(ResNet)

深度學習之殘差神經網路(ResNet)

除此之外,ResNet還有更多的改進,例如deeper bottleneck architecture(如下圖),透過在3*3卷積層前後引入1*1卷積層分別來減少和增加維度,讓3*3卷積層成為“瓶頸”,減少引數和浮點運算,使得模型更加“輕量”。

深度學習之殘差神經網路(ResNet)

這樣的改進,直接使得ResNet層數突破100大關,相繼產生了ResNet-101和ResNet-152這樣極其深邃的神經網路。經實驗驗證,它們的精確度均超過了ResNet-34。

實驗表明,單一ResNet-152的錯誤率可達4。49%。而透過整合6個不同深度的ResNet(含2個ResNet-152),何愷明等人以3。57%的錯誤率在比賽中拔得頭籌。而如此深的網路能夠正常訓練,也得益於shortcut connection提供的數值穩定性。

References:

· Deep Residual Learning for Image Recognition by Kaiming He, et al。

(arXiv: 1512。03385v1 [cs。CV] 10 Dec 2015)

· Dive into Deep Learning by Mu Li, et al。

·

Hands-on Machine Learning with Scikit-Learn & Tensorflow

by Aurélien Géron

寫在最後

本文從多個角度出發,簡單地介紹了ResNet的“前世今生”,旨在學術交流,如有錯誤,敬請批評指正!

本文部分圖片為轉載,如有侵權,請聯絡替換。

標簽: 函式  ResNet  殘差  神經網路  nn