天天看點

深度殘差網絡(Deep residual network, ResNet)

一、前言

深度殘差網絡(Deep residual network, ResNet)的提出是CNN圖像史上的一件裡程碑事件,讓我們先看一下ResNet在ILSVRC和COCO 2015上的戰績:

深度殘差網絡(Deep residual network, ResNet)

ResNet取得了5項第一,并又一次重新整理了CNN模型在ImageNet上的曆史,

ImageNet分類Top-5誤差:

深度殘差網絡(Deep residual network, ResNet)

那麼ResNet為什麼會有如此優異的表現呢?其實ResNet是解決了深度CNN模型難訓練的問題,從圖2中可以看到14年的VGG才19層,而15年的ResNet多達152層,這在網絡深度完全不是一個量級上,是以如果是第一眼看這個圖的話,肯定會覺得ResNet是靠深度取勝。事實當然是這樣,但是ResNet還有架構上的技巧,這才使得網絡的深度發揮出作用,這個技巧就是殘差學習(Residual learning)。

  • 論文名稱:Deep Residual Learning for Image Recognition
  • 論文作者:Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun

二、深度網絡的退化問題

從經驗來看,網絡的深度對模型的性能至關重要,當增加網絡層數後,網絡可以進行更加複雜的特征模式的提取,是以當模型更深時理論上可以取得更好的結果,

在深度學習中,網絡層數增多一般會伴着下面幾個問題

  1. 計算資源的消耗
  2. 模型容易過拟合
  3. 梯度消失/梯度爆炸問題的産生
  • 問題1可以通過GPU叢集來解決,對于一個企業資源并不是很大的問題;
  • 問題2的過拟合通過采集海量資料,并配合Dropout正則化等方法也可以有效避免;
  • 問題3通過Batch Normalization也可以避免。

    貌似我們隻要無腦的增加網絡的層數,我們就能從此獲益,但實驗資料給了我們當頭一棒。實驗發現深度網絡出現了退化問題(Degradation problem):網絡深度增加時,網絡準确度出現飽和,甚至出現下降。這個現象可以在下圖中直覺看出來:

    深度殘差網絡(Deep residual network, ResNet)
    56層的網絡比20層網絡效果還要差。這不會是過拟合問題,因為56層網絡的訓練誤差同樣高。我們知道深層網絡存在着梯度消失或者爆炸的問題,這使得深度學習模型很難訓練。但是現在已經存在一些技術手段如BatchNorm來緩解這個問題。是以,出現深度網絡的退化問題是非常令人詫異的。

當網絡退化時,淺層網絡能夠達到比深層網絡更好的訓練效果,這時如果我們把低層的特征傳到高層,那麼效果應該至少不比淺層的網絡效果差,或者說如果一個VGG-100網絡在第98層使用的是和VGG-16第14層一模一樣的特征,那麼VGG-100的效果應該會和VGG-16的效果相同。但是實驗結果表明,VGG-100網絡的訓練和測試誤差比VGG-16網絡的更大。這說明A網絡在學習恒等映射的時候出了問題,也就是​

​傳統的網絡("plain" networks)很難去學習恒等映射。​

​也就是說,我們不得不承認肯定是目前的訓練方法有問題,才使得深層網絡很難去找到一個好的參數。

是以,我們可以在VGG-100的98層和14層之間添加一條直接映射(Identity Mapping)來達到此效果。

從資訊論的角度講,由于DPI(資料處理不等式)的存在,在前向傳輸的過程中,随着層數的加深,Feature Map包含的圖像資訊會逐層減少,而ResNet的直接映射的加入,保證了 l+1層的網絡一定比 l 層包含更多的圖像資訊。

基于這種使用直接映射來連接配接網絡不同層直接的思想,殘差網絡應運而生。

三、殘差學習

3.1 殘差網絡原理

對于一個堆積層結構(幾層堆積而成)當輸入為x時其學習到的特征記為H (x),現在我們希望其可以學習到殘差F(x)= H(x) - x,這樣其實原始的學習特征是H(x)= F(x) + x。之是以這樣是因為殘差學習相比原始特征直接學習更容易。當殘差為0時,此時堆積層僅僅做了恒等映射,至少網絡性能不會下降,實際上殘差不會為0,這也會使得堆積層在輸入特征基礎上學習到新的特征,進而擁有更好的性能。殘差學習的結構如下圖所示。這有點類似與電路中的“短路”,是以是一種短路連接配接(shortcut connection)。

  • 改變前目标: 訓練F(x) 逼近 H(x)
  • 改變後目标:訓練 F(x)逼近H(x) - x
    深度殘差網絡(Deep residual network, ResNet)

上圖中,左邊的original block需要調整其内部參數,使得輸入的x經過卷積操作後最終輸出的F(x)等于x,即實作了恒等映射F(x)=x,等号左邊是block的輸出,右邊是block的輸入。但是這種結構的卷積網絡很難調整其參數完美地實作F(x)=x。再看右邊的Res block。因為shortcut的引入,整個block的輸出變成了F(x)+x,block的輸入還是x。此時網絡需要調整其内部參數使得F(x)+x=x,也就是直接令其内部的所有參數為0,使得F(x)=0,F(x)+x=x就變成了0+x = x,等号左邊是block的輸出,右邊是block的輸入。輸出等于輸入,即完美地完成了恒等映射。

3.2 ResNet結構為什麼可以解決深度網絡退化問題?

因為ResNet更加容易拟合恒等映射,原因如下:

ResNet的結構使得網絡具有與學習恒等映射的能力,同時也具有學習其他映射的能力。是以ResNet的結構要優于傳統的卷積網絡(plain networks)結構。

3.3 殘差單元

由于ResNet要求 F(x)與 x 的次元大小要一緻才能夠相加,是以在 F(x) 與 x 次元不相同時就需要對 x 的次元做調整。

ResNet使用兩種殘差單元,如下圖所示。左圖對應的是淺層網絡,而右圖對應的是深層網絡。對于短路連接配接,當輸入和輸出次元一緻時,可以直接将輸入加到輸出上。但是當次元不一緻時(對應的是次元增加一倍),這就不能直接相加。有兩種政策:

(A方式)采用zero-padding增加次元,此時一般要先做一個downsamp,可以采用strde=2的pooling,這樣不會增加參數;

(B方式)采用新的映射(projection shortcut),一般采用1x1的卷積,這樣會增加參數,也會增加計算量。

深度殘差網絡(Deep residual network, ResNet)

A方式采用0填充.,完全不存在任何的殘差學習能力。

B方式的模型複雜度偏高

是以論文中采用折中的C方式

C方式在F(x)的次元與 x的次元相同時,直接用 F(x) 加上 x,在次元不同時,才采用1x1的卷積層對 x 的次元進行調整。

def identity_block(input_tensor, kernel_size, filters, stage, block):
"""The identity block is the block that has no conv layer at shortcut. A方式

    # Arguments
        input_tensor: input tensor
        kernel_size: defualt 3, the kernel size of middle conv layer at main path
        filters: list of integers, the filters of 3 conv layer at main path
        stage: integer, current stage label, used for generating layer names
        block: 'a','b'..., current block label, used for generating layer names

    # Returns
        Output tensor for the block.
    """
filters1, filters2, filters3 = filters
if K.image_data_format() == 'channels_last':
bn_axis = 3
else:
bn_axis = 1
conv_name_base = 'res' + str(stage) + block + '_branch'
bn_name_base = 'bn' + str(stage) + block + '_branch'

x = Conv2D(filters1, (1, 1), name=conv_name_base + '2a')(input_tensor)
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x)
x = Activation('relu')(x)

x = Conv2D(filters2, kernel_size,
padding='same', name=conv_name_base + '2b')(x)
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x)
x = Activation('relu')(x)

x = Conv2D(filters3, (1, 1), name=conv_name_base + '2c')(x)
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x)

x = layers.add([x, input_tensor])
x = Activation('relu')(x)
return x

      
def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2, 2)):
"""conv_block is the block that has a conv layer at shortcut
    B方式
    # Arguments
        input_tensor: input tensor
        kernel_size: defualt 3, the kernel size of middle conv layer at main path
        filters: list of integers, the filterss of 3 conv layer at main path
        stage: integer, current stage label, used for generating layer names
        block: 'a','b'..., current block label, used for generating layer names

    # Returns
        Output tensor for the block.

    Note that from stage 3, the first conv layer at main path is with strides=(2,2)
    And the shortcut should have strides=(2,2) as well
    """
filters1, filters2, filters3 = filters
if K.image_data_format() == 'channels_last':
bn_axis = 3
else:
bn_axis = 1
conv_name_base = 'res' + str(stage) + block + '_branch'
bn_name_base = 'bn' + str(stage) + block + '_branch'

x = Conv2D(filters1, (1, 1), strides=strides,
name=conv_name_base + '2a')(input_tensor)
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x)
x = Activation('relu')(x)

x = Conv2D(filters2, kernel_size, padding='same',
name=conv_name_base + '2b')(x)
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x)
x = Activation('relu')(x)

x = Conv2D(filters3, (1, 1), name=conv_name_base + '2c')(x)
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x)

shortcut = Conv2D(filters3, (1, 1), strides=strides,
name=conv_name_base + '1')(input_tensor)
shortcut = BatchNormalization(axis=bn_axis, name=bn_name_base + '1')(shortcut)

x = layers.add([x, shortcut])
x = Activation('relu')(x)
return x
      

3.4 ResNet的網絡結構

ResNet網絡是參考了VGG19網絡,在其基礎上進行了修改,并通過短路機制加入了殘差單元,如下圖所示。變化主要展現在ResNet直接使用stride=2的卷積做下采樣,并且用global average pool層替換了全連接配接層。ResNet的一個重要設計原則是:當feature map大小降低一半時,feature map的數量增加一倍,這保持了網絡層的複雜度。從下圖中可以看到,ResNet相比普通網絡每兩層間增加了短路機制,這就形成了殘差學習,其中虛線表示feature map數量發生了改變。下圖展示的34-layer的ResNet,還可以建構更深的網絡如表1所示。從表中可以看到,對于18-layer和34-layer的ResNet,其進行的兩層間的殘差學習,當網絡更深時,其進行的是三層間的殘差學習,三層卷積核分别是1x1,3x3和1x1,一個值得注意的是隐含層的feature map數量是比較小的,并且是輸出feature map數量的1/4。

深度殘差網絡(Deep residual network, ResNet)
深度殘差網絡(Deep residual network, ResNet)

四、實驗結果

深度殘差網絡(Deep residual network, ResNet)
深度殘差網絡(Deep residual network, ResNet)

作者搭建了不同深度的ResNet模型進行了實驗,結果如上圖所示。ResNet在ImageNet上的錯誤率與網絡的深度是線性關系,網絡越深,錯誤率越低。說明在一定ResNet的網路結構解決之前所說的網絡退化的問題。