摘要:殘差網路(ResNet)的提出是為了解決深度神經網路的「退化」(優化)問題。ResNet 通過設計殘差塊結構,調整模型結構,讓更深的模型能夠有效訓練更訓練。
本文分享自華為雲社群《Backbone 網路-ResNet 網路詳解》,作者: 嵌入式視覺 。
殘差網路(ResNet
)的提出是為了解決深度神經網路的「退化」(優化)問題。
有論文指出,神經網路越來越深的時候,反傳回來的梯度之間的相關性會越來越差,最後接近白噪聲。即更深的折積網路會產生梯度消失問題導致網路無法有效訓練。
而 ResNet
通過設計殘差塊結構,調整模型結構,讓更深的模型能夠有效訓練更訓練。目前 ResNet 被當作目標檢測、語意分割等視覺演演算法框架的主流 backbone。
作者認為,假設一個比較淺的折積網路已經可以達到不錯的效果,那麼即使新加了很多折積層什麼也不做,模型的效果也不會變差。但,之所以之前的深度網路出現退化問題,是因為讓網路層什麼都不做恰好是當前神經網路最難解決的問題之一!
因此,作者可以提出殘差網路的初衷,其實是讓模型的內部結構至少有恆等對映的能力(什麼都不做的能力),這樣可以保證疊加更深的折積層不會因為網路更深而產生退化問題!
對於 VGG 式的折積網路中的一個折積 block,假設 block 的輸入為 xx ,期望輸出為 H(x)H(x),block 完成非線性對映功能。
那麼,如何實現恆等對映呢?
假設直連(plain
)折積 block 的輸入為 xx ,block 期望輸出為 H(x)H(x),我們一般第一反應是直接讓學習 H(x)=xH(x)=x,但是這很難!
對此,作者換了個角度想問題,既然 H(x)=xH(x)=x 很難學習到,那我就將 H(x)H(x) 學習成其他的,而讓恆等對映能力通過其他結構來實現,比如,直接加個 shorcut 不就完事了!這樣只要直連 block 網路輸出學習為 0 就行了。而讓直連折積 block 輸出學習為 0 比學習成恆等對映的能力是要簡單很多的!畢竟前者通過 L2 正則化就能實現了!
因此,作者將網路設計為 H(x)=F(x)+xH(x)=F(x)+x,即直接把恆等對映作為網路的一部分,只要 F(x)=0F(x)=0,即實現恆等對映: H(x)=xH(x)=x。殘差塊結構(resdiual block
)。基本殘差塊結構如下圖所示:
從圖中可以看出,一個殘差塊有 22 條路徑 F(x)F(x) 和 xx,F(x)F(x) 路徑擬合殘差 H(x)−xH(x)−x,可稱為殘差路徑,xx 路徑為恆等對映(identity mapping),稱其為」shortcut」。圖中的 ⊕⊕ 為逐元素相加(element-wise addition
),要求參與運算的 F(x)F(x) 和 xx 的尺寸必須相同!
這就把前面的問題轉換成了學習一個殘差函數 F(x)=H(x)−xF(x)=H(x)−x。
綜上總結:可以認為 Residual Learning 的初衷(原理),其實是讓模型的內部結構至少有恆等對映的能力。以保證在堆疊網路的過程中,網路至少不會因為繼續堆疊而產生退化!
注意,很多部落格片面解釋 resnet 解決了梯度消失問題所以有效的的觀點是片面的且方向也錯了!resnet 到底解決了什麼問題以及為什麼有效問題的更細節回答,可以參考這個回答。
在 ResNet 原論文中,殘差路徑的設計可以分成 22 種,
bottleneck
結構,如圖3-5左所示,稱之為「basic block」,由 2 個 3×33×3 折積層構成。2 層的殘差學習單元其兩個輸出部分必須具有相同的通道數(因為殘差等於目標輸出減去輸入,即 H(x)−xH(x)−x,所以輸入、輸出通道數目需相等)。bottleneck
結構,稱之為 「bottleneck block」,對於每個殘差函數 FF,使用 33 層堆疊而不是 2 層,3 層分別是 1×11×1,3×33×3 和 1×11×1 折積。其中 1×11×1 折積層負責先減小然後增加(恢復)維度,使 3×33×3 折積層的通道數目可以降低下來,降低引數量減少算力瓶頸(這也是起名 bottleneck 的原因 )。50
層以上的殘差網路都使用了 bottleneck block 的殘差塊結構,因為其可以減少計算量和降低訓練時間。3 層的殘差學習單元是參考了 Inception Net 結構中的
Network in Network
方法,在中間 3×33×3 的折積前後使用 1×11×1 折積,實現先降低維度再提升維度,從而起到降低模型引數和計算量的作用。
shortcut
路徑大致也分成 22 種,一種是將輸入 xx 直接輸出,另一種則需要經過 1×11×1 折積來升維或降取樣,其是為了將 shortcut
輸出與 F(x)
路徑的輸出保持形狀一致,但是其對網路效能的提升並不明顯,兩種結構如下圖所示。
Residual Block(殘差塊)之間的銜接,在原論文中,F(x)+xF(x)+x 是經過 ReLU 後直接作為下一個 block 的輸入 xx。
殘差網路中,將堆疊的幾層折積 layer
稱為殘差塊(Residual Block
),多個相似的殘差塊串聯構成 ResNet。ResNet18 和 ResNet34 Backbone用的都是兩層的殘差學習單元(basic block
),更深層的ResNet則使用的是三層的殘差學習單元(bottle block
)。
ResNet18 其結構如下圖所示。
ResNet18 網路具體引數如下表所示。
假設影象輸入尺寸為,1024×20481024×2048,ResNet 共有五個階段。
conv1 layer
為一個 7×77×7 的折積核,stride
為 2,然後經過池化層處理,此時特徵圖的尺寸已成為輸入的1/4
,即輸出尺寸為 512×1024512×1024。layer
:conv2_x、conv3_x、conv4_x、conv5_x,後面三個都會降低特徵圖尺寸為原來的 1/2
,特徵圖的下取樣是通過步長為 2
的 conv3_1, conv4_1 和 conv5_1 執行。所以,最後輸出的 feature_map 尺寸為輸入尺寸降取樣 32=4×2×2×232=4×2×2×2 倍。在工程程式碼中用 make_layer
函數產生四個 layer
即對應 ResNet 網路的四個階段。根據不同層數的 ResNet(N):
blocks
是不同的,即每個階段(layer
)裡面的殘差模組數目不同(即 layers
列表不同)block
型別(basic
還是 bottleneck
版)也不同。本文介紹的 ResNet18,使用 basic block
,其殘差模組數量(即units數量)是 [2, 2, 2, 2],又因為每個殘差模組中只包含了 2 層折積,故殘差模組總的折積層數為 (2+2+2+2)*2=16,再加上第一層的折積和最後一層的分類,總共是 18 層,所以命名為 ResNet18。
ResNet50 為 [3, 4, 6, 3]。
看了後續的 ResNeXt
、ResNetv2
、Densenet
、CSPNet
、VOVNet
等論文,越發覺得 ResNet
真的算是 Backone
領域劃時代的工作了,因為它讓深層神經網路可以訓練,基本解決了深層神經網路訓練過程中的梯度消失問題,並給出了系統性的解決方案(兩種殘差結構),即系統性的讓網路變得更「深」了。而讓網路變得更「寬」的工作,至今也沒有一個公認的最佳方案(Inception
、ResNeXt
等後續沒有廣泛應用),難道是因為網路變得「寬」不如「深」更重要,亦或是我們還沒有找到一個更有效的方案。