【論文解讀】CNN深度卷積神經網絡-ResNet

24.jpg

1.簡介

深度殘差網絡(deep residual network)是2015年微軟何凱明團隊發表的一篇名為:《Deep Residual Learning for Image Recognition》的論文中提出的一種全新的網絡結構,其核心模塊是殘差塊residual block。正是由于殘差塊結構的出現使得深度神經網絡模型的層數可以不斷加深到100層、1000層甚至更深,從而使得該團隊在當年的ILSVRC 2015分類競賽中取得卓越成績,也深刻地影響了以后的很多深度神經網絡的結構設計。
殘差網絡的成功不僅表現在其在ILSVRC 2015競賽中的卓越效果,更是因為殘差塊skip connection/shorcut這樣優秀的思想和設計,使得卷積網絡隨著層數加深而導致的模型退化問題能被夠大幅解決,使模型深度提高一個數量級,到達上百、上千層。

1.1網絡加深的后果

在殘差塊這樣的結構引入之前,如果一個神經網絡模型的深度太深,可能會帶來梯度消失和梯度爆炸的問題(如下圖),隨著一些正則化方法的應用可以緩解此問題,但是隨著layer深度的繼續加深,又帶來了模型退化這樣的問題。而添加了帶shortcut的殘差塊結構之后,使得整個深度神經網絡的層數可以大幅增加,變得更【深】,從而有時會帶來更好的訓練效果。

1.2 網絡模型的退化

下圖為CIFER10在20層和56層普通網絡結構下測試和訓練過程中的損失。可見,僅僅簡單地加深網絡,并沒有帶來精度的提升,相反會導致網絡模型的退化。
image.png

那么,這里就有一個問題,為什么加深網絡會帶來退化問題?即使新增的這些layer什么都沒學習,保持恒等輸出(所有的weight都設為1),那么按理說網絡的精度也應該 = 原有未加深時的水平,如果新增的layer學習到了有用特征,那么必然加深過后的模型精度會 > 未加深的原網絡。看起來對于網絡的精度加深后都應該 >= 加深前才對啊 ?
實際上,讓新增的layer保持什么都不學習的恒等狀態,恰恰很困難,因為在訓練過程中每一層layer都通過線性修正單元relu處理,而這樣的處理方式必然帶來特征的信息損失(不論是有效特征or冗余特征)。所以上述假設的前提是不成立的,簡單的堆疊layer必然會帶來退化問題。

1.3 退化問題的解決

到此,何凱明團隊創新地提出了殘差塊的構想,通過shortcut/skip connection這樣的方式(最初出現在highway network中),繞過這些新增的layer,既然保持新增layer的identity恒等性很困難,那就直接繞過它們,通過shortcut通路來保持恒等。如圖2所示:

figure-2.png
figure-2.png
這里假設原有網絡結構的基礎映射為H(x),這里又添加了兩個layer,在網絡中的映射稱為F(x)。既然新增layer保持不了恒等性,那我們可以通過skip connection/shortcut來直接跳過它們,在shortcut上保持恒等,為了保持新結構的輸出F(x) + x = H(x)同原輸出H(x)相近,這里我只需要優化F(x),使其趨于0即可,而使得F(x)接近0是相對比較容易的(無論是從權重初始化的角度還是激活函數特征過濾的角度)
到這里,算是【曲線救國】了,雖然新增的F(x)不容易保持恒等,但讓其盡量靠近0,還是相對容易做到的,這種訓練方式稱為殘差學習,這種結構塊也稱為Residual Block殘差塊。正是殘差結構的出現,使得殘差網絡能很好的加深網絡層數,同時解決退化問題。

1.4 資源下載

【2015】【ResNet】1512.03385v1.pdf
訓練代碼(官方實現):https://github.com/facebookarchive/fb.resnet.torch

2.Abstract

Abstract
Deeper neural networks are more difficult to train. We present a residual learning framework to ease the training of networks that are substantially deeper than those used previously. We explicitly reformulate the layers as learning residual functions with reference to the layer inputs, instead of learning unreferenced functions. We provide comprehensive empirical evidence showing that these residual networks are easier to optimize, and can gain accuracy from considerably increased depth. On the ImageNet dataset we evaluate residual nets with a depth of up to 152 layers—8×deeper than VGG nets [41] but still having lower complexity. An ensemble of these residual nets achieves 3.57% erroron the ImageNet testset. This result won the 1st place on theILSVRC 2015 classification task. We also present analysison CIFAR-10 with 100 and 1000 layers.
The depth of representations is of central importancefor many visual recognition tasks. Solely due to our extremely deep representations, we obtain a 28% relative improvement on the COCO object detection dataset. Deepresidual nets are foundations of our submissions to ILSVRC& COCO 2015 competitions1, where we also won the 1stplaces on the tasks of ImageNet detection, ImageNet localization, COCO detection, and COCO segmentation
翻譯
更深的神經網絡更難訓練。 我們提出了一種殘差的學習框架,以簡化比之前使用的網絡還要深入的網絡結構的訓練。 我們通過改變一些層的輸入來調整了這些層的結構以構造成殘差函數來進行學習。我們提供了全面的經驗證據,表明這些殘差網絡更易于優化,并且可以通過深度的增加而提升準確性。 在ImageNet數據集上,我們評估深度最大為152層的殘差網絡-比VGG網絡[41]深8倍,但復雜度仍然較低。 這些殘差網絡整體在ImageNet測試集上實現了3.57%的誤差。 該結果在ILSVRC 2015分類任務中獲得第一名。 我們還將介紹具有100和1000層的基于CIFAR-10的分析。
表征深度對于許多視覺識別任務至關重要。 僅由于我們更深的網絡結構,我們在COCO對象檢測數據集上獲得了28%的相對改進。 深度殘差網絡是我們提交ILSVRC&COCO 2015競賽奪冠的基礎,在該競賽中,我們還獲得了ImageNet檢測,ImageNet本地化,COCO檢測和COCO分割等任務的第一名

3.網絡結構

3.1 示意圖

image.png

3.2 殘差塊

figure-2.png
figure-2.png
figure-5.png
figure-5.png
figure-5.png
figure-5.png

4.論文解讀

1.介紹

論文中Introduction部分的內容及思想,主要內容為殘差學習和殘差塊提出的原因,解決的問題,在競賽中取得的佳績等。(以下大多數內容和1.簡介中的類似)
深度神經網絡模型隨著深度加深,精度和表現都會提高。但是隨著深度逐漸加深也會帶來其他問題,首當其沖的是梯度消失和梯度爆炸,但是隨著標準初始化和中間的正則化層解決了此問題,使得數十層的網絡可以在隨機梯度下降SGD過程中進行反向傳播和收斂。然而,隨著網絡深度的進一步加深,模型的準確性達到飽和然后迅速下降,而且這種退化并不是由于過擬合所導致。如圖所示:

Figure1:CIFER10在20層和56層普通網絡結構下測試和訓練過程中的損失對比.png
訓練準確性的下降表明,并非所有系統都同樣易于優化。 讓我們考慮一下一個較淺的網絡結構,以及它的更深層次的對應結構。 有一個通過構造更深層模型的解決方案:添加的層是恒等映射,其他層是從學習的較淺層模型中復制的。 該構造方案的存在表明,更深的模型應該不會比其較淺的模型產生更高的訓練誤差,但是實驗表明,我們現有的求解器無法找到與構造的解決方案相比更好或更好的解決方案(或無法做到) 在可行的時間內)

在本文中,我們通過引入深度殘差學習框架解決降級問題,而不是希望每個堆疊的層都直接適合所需的基礎映射,而是明確讓這些層適合殘差映射。 形式上,將所需的基礎映射表示為H(x),我們讓堆疊的非線性層(圖中的weight layer)適合F(x) := H(x) - x的另一個映射。 原始映射將重鑄為F(x) + x。 我們假設與優化原始,未引用的映射相比,更容易優化殘留映射。 極端地,如果identity特征映射是最佳的,則將殘差推為零比通過用一疊非線性層擬合特征映射要容易。

圖2.png
圖2.png
F(x)+ x的表示可以通過具有“shortcut跳遠連接”的前饋神經網絡來實現(圖2)。shortcut[2、34、49]是跳過一層或多層的連接。 在我們的情況下,shortcut連接僅執行恒等映射,并將它們的輸出添加到堆疊層的輸出中(圖2)。 shortcut的連接方式既不會增加額外的參數,也不會增加計算復雜性。 整個網絡仍然可以通過SGD反向傳播進行端到端訓練,并且可以使用通用庫(例如Caffe [19])輕松實現,而無需修改求解器。


針對上述構想,作者團隊在ImageNet上做了全面實驗并證明:

  • 1.隨著網絡層數的增加,普通網絡結構的訓練誤差相比殘差網絡更高
  • 2.深度殘差網絡可以更容易地通過增加深度來提高網絡精度,而且結果比淺層網絡好很多。

作者團隊在在CIFAR-10數據集成功訓練了深度超過100層以上的模型,也得到了同樣的結論。并實驗了1000層以上模型的訓練。在ImageNet的分類數據集上,殘差網絡在測試集上取得了3.57%的top-5錯誤率從而獲得ILSVRC2015分類挑戰賽的冠軍,同時152層的網絡深度刷新了記錄且其參數量比VGGNet還少。
除此之外,通過極深的殘差網絡,其團隊在ILSVRC和COCO 2015中的各項細分比賽中都獲得了冠軍,如:ImageNet目標檢測、定位;COCO目標檢測、分割。這些證據表明殘差學習的原則是通用的,在多項任務中都有著出色的泛化能力。

2.相關工作

殘差表示

主要內容是從圖像檢索和分類的角度,殘差矢量計算的對比和優化,從理論上給出證據表面殘差方案使得訓練時的模型收斂速度加快。以下是原論文翻譯:

在圖像識別中,VLAD [18]是通過相對于字典的殘差矢量進行編碼的表示,Fisher Vector [30]可以表示為VLAD的概率版本[18]。 它們都是用于圖像檢索和分類的有效的淺層表示[4,48]。 對于向量量化,編碼殘差向量[17]比編碼原始向量更有效。在低級視覺和計算機圖形學中,為求解偏微分方程(PDE),廣泛使用的Multigrid方法[3]將系統引申出多個規模的子問題,其中每個子問題負責在較粗和較精scale之間的殘差解決方案。 Multigrid的替代方法是以分層為基礎的預處理[45,46],它依賴于代表兩種scale之間的殘差向量的變量。 已經證明[3、45、46],這些方案的收斂速度比那些對殘差本質尚未涉及的標準方案快得多。 這些方法表明,良好的重構或預處理可以簡化優化過程。

shortcut連接

這一小節主要是進行了shortcut理論和實踐的溯源,還有同highway network中shortcut功能區別的對比。以下部分是原論文翻譯:

關于shortcut連接的實踐和理論[2,34,49]已有很長時間的研究。 訓練多層感知器(MLP)的早期實踐是添加從網絡輸入連接到輸出的線性層(如:Pattern recognition and neural networks. Cambridgeuniversity press, 1996)。 在GoogLeNet等網絡中,一些中間層直接連接到輔助分類器,以解決消失/爆炸梯度。 文獻[39,38,31,47]提出了通過shortcut連接實現對層響應,梯度和傳播誤差進行居中的方法。 在GoogLeNet中,“Inception”層由shortcut分支和一些更深的分支組成。
與我們同期的工作,“highway networks” [42、43]中,shortcut連接作為門功能[15]而呈現。這些門(gates)是帶參的且依賴數據的,正與我們shortcut帶參且有恒等性相反。當shortcut門“關閉”時(接近0),highway networks中的層表現出非殘差功能;相反我們的表達式卻永遠在進行殘差的學習。我們的shortcut永遠不會關閉,所有信息始終通過其傳遞,同時殘差函數也始終在進行學習。此外,highway networks并沒有證明,隨著深度增加,準確性有了明顯提升。

3.深度殘差學習

3.2 shortcut恒等映射

在殘差網絡中,對每一個堆疊層都采用殘差學習,一個堆疊層形如圖2所示的一個殘差塊。

figure-2.png
figure-2.png
殘差塊的公式定義為:
這里x和y分別為輸入輸出;即代表需要進行殘差學習的函數。以圖2展示的殘差塊為例,殘差函數可以表示為:(激活函數為ReLU,且省略了bias)作者指出,這個公式并沒有引入額外參數,也沒有增加計算復雜度。

x和F(x)計算時尺寸必須相等,為此我們可以在必要時通過矩陣Ws來改變輸入x的維度:\mathbf{y}=\mathcal{F}\left(\mathbf{x},\left\{W_{i}\right\}\right)+W_{s} \mathbf{x}在殘差塊中堆疊的layer數量至少為2,因為如果只增加了1層,整個表達式便退化成了線性方程,而這就失去作用了。為了簡單起見,表達式看上去只適合全連接層,其實可也以表示卷積層,F(x,{Wi})可以表示多個卷積層。在兩個feature maps之間,元素之間的相加是在通道維上逐個進行的。

3.3 網絡結構

作者及其團隊已經測試過各種普通/殘差網絡,并觀測到一致的現象,這里僅舉ImageNet中的兩個模型作為說明。
image.png

普通網絡

上圖中間的是34層的基準普通網絡,包含34個帶權層(conv+fc)。其設計參考了VGG-19,卷積層的filter尺寸多為3×3,并遵循兩個設計原則:1.如果輸出的特征圖尺寸減半,則filter數量加倍 2.如果輸出的特征圖尺寸不變,filter數量也不變。stride保持為2,網絡結束之前會經過全局平均池化層,再連接一個1000路的softmax分類。

論文指出殘差網絡比VGG網絡有著更少的過濾器和更低的復雜度,34層的基準網絡有36億個FLOP(乘加),而VGG-19有196億個FLOP,僅占其18%。

殘差網絡

上圖最右邊是在中間普通網絡基礎上,增加了shortcut,使其變為了殘差網絡。這里有兩種shortcut,實線shortcut和虛線shortcut(投影projection)。當輸入和輸出維度相同時,使用實線shortcut,當維度增加時使用虛線shortcut。當維度改變使用虛線shortcut時,我們為了匹配維度有2種做法:

  • (A) shortcut任執行恒等映射,增加額外的0項來增加維度
  • (B)使用等式\mathbf{y}=\mathcal{F}\left(\mathbf{x},\left\{W_{i}\right\}\right)+W_{s} \mathbf{x} 中的方式,通過1×1卷積來改變維度

3.4 實現

對ImageNet的殘差網絡實現參照了VGGNet及其在ImageNet中的實現。
圖像resize,并水平翻轉,隨機剪裁減去RGB均值像素,顏色增強等處理;
BN批量正則化;
batch size設為256;
隨機梯度下降SGD;
初始學習率為0.1當loss穩定后除以10;
weight decay設為0.0001;
動量0.9;
值得注意的是,在該實現中并沒有使用Dropout方法。

4.實驗

4.1 ImageNet分類

作者在ImageNet2012分類數據集評估了殘差網絡,128萬張訓練圖,5萬張驗證圖,1000個分類,在測試服務器上通過10萬張測試圖評估得到了top-1和top-5錯誤率。

figure-4.png
table-2.png

普通網絡

上圖左邊可看出,在普通網絡的對比中,34層的比18層誤差大,存在模型退化現象。

殘差網絡

通過對比左右兩幅圖+table2可以發現:當模型深度不是很深時(18)層,普通網絡和ResNet網絡的準確率差不多,表示通過一些初始化和正則化方法,可以降低普通卷積神經網絡的過擬合;但當層數不斷加深,就不可避免地出現模型退化現象,而此時ResNet可以在此情況下很好地解決退化問題。

作者團隊不僅實驗了34層的ResNet更實驗了多種殘差塊,多種深度的殘差網絡,結構如下:

table-1.png

其中,以50層layer中的殘差塊為例,由于其輸入輸出尺寸不同,需要1×1卷積進行維度轉換,這種殘差block表現出上窄下寬的形狀,被稱為“瓶頸”殘差塊。具體如下圖:

figure-5.png

不同深度ResNet的對比

table-3.png

可以看見,在ResNet網絡中,并沒有看到模型退化的現象,反而隨著layer深度加深,網絡的精度越高。

各種經典網絡對比

table-5.png

5.代碼實現

這里使用tensorflow2.0實現ResNet-18網絡結構,完整訓練可參考:殘差網絡(ResNet)。我們先看一下ResNet-18的網絡結構:

選區_075.png

ResNet的前兩層跟之前介紹的GoogLeNet中的一樣:在輸出通道數為64、步幅為2的7×7卷積層后接步幅為2的3×3的最大池化層。不同之處在于ResNet每個卷積層后增加的批量歸一化層。然后接了4種類型的共計8個殘差塊,每種類型的2個殘差塊形成一個堆疊。最后加了全局平均池化和1000路的softmax輸出。

5.1定義殘差塊

殘差塊沿用了VGG的3×3的卷積核尺寸,且有兩種結構:初入 = 輸出;輸入!=輸出。針對輸入和輸出shape不一樣的情況,需要增加一個1×1卷積變換維度。殘差塊內的卷積層經過卷積后接BN批量歸一化層,然后經過ReLU激活。

定義殘差塊實現類Residual:

import tensorflow as tf
from tensorflow.keras import layers,activations
class Residual(tf.keras.Model):
    def __init__(self, num_channels, use_1x1conv=False, strides=1, **kwargs):
        super(Residual, self).__init__(**kwargs)
        self.conv1 = layers.Conv2D(num_channels,
                                   padding='same',
                                   kernel_size=3,
                                   strides=strides)
        self.conv2 = layers.Conv2D(num_channels, kernel_size=3,padding='same')
        # 如果需要變換維度,則增加1×1卷積層
        if use_1x1conv:
            self.conv3 = layers.Conv2D(num_channels,
                                       kernel_size=1,
                                       strides=strides)
        else:
            self.conv3 = None
        self.bn1 = layers.BatchNormalization()
        self.bn2 = layers.BatchNormalization()

    def call(self, X):
        Y = activations.relu(self.bn1(self.conv1(X)))
        Y = self.bn2(self.conv2(Y))
        if self.conv3:
            X = self.conv3(X)
        return activations.relu(Y + X)

5.2定義殘差塊stack

ResNet-18總計4個殘差塊stack,每個stack包含兩個殘差塊。下面定義殘差塊stack

class ResnetBlock(tf.keras.layers.Layer):
    def __init__(self,num_channels, num_residuals, first_block=False,**kwargs):
        super(ResnetBlock, self).__init__(**kwargs)
        self.listLayers=[]
        for i in range(num_residuals):
            if i == 0 and not first_block:
                self.listLayers.append(Residual(num_channels, use_1x1conv=True, strides=2))
            else:
                self.listLayers.append(Residual(num_channels))      

    def call(self, X):
        for layer in self.listLayers.layers:
            X = layer(X)
        return X

5.3定義ResNet

class ResNet(tf.keras.Model):
    def __init__(self,num_blocks,**kwargs):
        super(ResNet, self).__init__(**kwargs)
        self.conv=layers.Conv2D(64, kernel_size=7, strides=2, padding='same')
        self.bn=layers.BatchNormalization()
        self.relu=layers.Activation('relu')
        self.mp=layers.MaxPool2D(pool_size=3, strides=2, padding='same')
        self.resnet_block1=ResnetBlock(64,num_blocks[0], first_block=True)
        self.resnet_block2=ResnetBlock(128,num_blocks[1])
        self.resnet_block3=ResnetBlock(256,num_blocks[2])
        self.resnet_block4=ResnetBlock(512,num_blocks[3])
        self.gap=layers.GlobalAvgPool2D()
        self.fc=layers.Dense(units=1000,activation=tf.keras.activations.softmax)

    def call(self, x):
        x=self.conv(x)
        x=self.bn(x)
        x=self.relu(x)
        x=self.mp(x)
        x=self.resnet_block1(x)
        x=self.resnet_block2(x)
        x=self.resnet_block3(x)
        x=self.resnet_block4(x)
        x=self.gap(x)
        x=self.fc(x)
        return x

mynet=ResNet([2,2,2,2])

# 觀察ResNet網絡的輸出
X = tf.random.uniform(shape=(1,  224, 224 , 3))
for layer in mynet.layers:
    X = layer(X)
    print(layer.name, 'output shape:\t', X.shape)

輸出:

conv2d output shape:  (1, 112, 112, 64)
batch_normalization output shape:  (1, 112, 112, 64)
activation output shape:  (1, 112, 112, 64)
max_pooling2d output shape:  (1, 56, 56, 64)
resnet_block output shape:  (1, 56, 56, 64)
resnet_block_1 output shape:  (1, 28, 28, 128)
resnet_block_2 output shape:  (1, 14, 14, 256)
resnet_block_3 output shape:  (1, 7, 7, 512)
global_average_pooling2d output shape:  (1, 512)
dense output shape:  (1, 1000)

6.總結

殘差網絡的出現使人們擺脫了【深度】的束縛,大幅改善了深度神經網絡中的模型退化問題,使網絡層數從數十層躍升至幾百上千層,大幅提高了模型精度,通用性強適合各種類型的數據集和任務。殘差塊和shortcut這種優秀的設計也極大影響了后面的網絡結構發展。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容