卷積神經網路學習路線(八)| 經典網路回顧之ZFNet和VGGNet

  • 2020 年 1 月 30 日
  • 筆記

開篇的這張圖代表ILSVRC歷年的Top-5錯誤率,我會按照以上經典網路出現的時間順序對他們進行介紹,同時穿插一些其他的經典CNN網路。

前言

這是卷積神經網路學習路線的第八篇文章,我們來回顧一下經典網路中的ZF-Net和VGGNet。

穩中求勝-ZFNet

ZFNet是ImageNet分類任務2013年的冠軍,其在AlexNet的結構上沒有做多大改進。首先作者Matthew D Zeiler提出了一種新的可視化技術,該技術可以深入了解中間特徵圖的功能和分類器的操作。這一點我在卷積神經網路學習路線(一)| 卷積神經網路的組件以及卷積層是如何在影像中起作用的?詳細介紹過。最終基於特徵圖的可視化結果發現以下兩點:

  • AlexNet第一層中有大量的高頻(邊緣)和低頻(非邊緣)資訊的混合,卻幾乎沒有覆蓋到中間的頻率資訊。
  • 由於第一層卷積用的步長為4,太大,導致了有非常多的混疊情況,學到的特徵不是特別好看,不像是後面的特徵能看到一些紋理、顏色等。

因此作者針對第一個問題將AlexNet的第一層的卷積核大小從改成。同時針對第二個問題將第一個卷積層的卷積核滑動步長從改成。

同時,ZFNet將AlexNet的第,,卷積層變為,,。然後就完了,可以看到ZFNet並沒有特別出彩的地方,因此這一年的ImageNet分類競賽算是比較平靜的一屆。

ZFNet的詳細網路結構如下圖:

在這裡插入圖片描述

ZFNet的程式碼實現如下:

def ZF_Net():      model = Sequential()      model.add(Conv2D(96,(7,7),strides=(2,2),input_shape=(224,224,3),padding='valid',activation='relu',kernel_initializer='uniform'))      model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))      model.add(Conv2D(256,(5,5),strides=(2,2),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))      model.add(Conv2D(384,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(Conv2D(384,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))      model.add(Flatten())      model.add(Dense(4096,activation='relu'))      model.add(Dropout(0.5))      model.add(Dense(4096,activation='relu'))      model.add(Dropout(0.5))      model.add(Dense(1000,activation='softmax'))      return model

越來越深-VGGNet

在2014年的ImageNet挑戰賽上,牛津大學的VGG(Visual Geometry Group)Net贏得了定位任務的關娟和分類任務的亞軍。VGGNet相比於前面的AlexNet,仍然沿用了卷積加全連接的結構,但深度更深。VGGNet的論文全名為:Very Deep Convolutional Networks for Large-Scale Visual Recognition》。

我們來看一下VGGNet的具體網路結構:

這個表格有意思了啊,他分為,,,,, 種網路。這是因為當時為了解決初始化權重的問題,VGG使用的是預訓練的方式,即先訓練一部分小網路,然後確保這部分網路收斂之後再在這個基礎上逐漸加深。並且當網路在D階段(VGG-16)效果是最好的,E階段(VGG-19)次之。VGG-16指的是網路的卷積層和全連接層的層數為。接下來我們仔細看一下VGG-16的結構圖:

在這裡插入圖片描述

從上圖可以看到網路的第一個卷積層的通道數為,然後每一層Max Pooling之後卷積層的通道數都成倍的增加,最後接看三分全連接層完成分類任務。總的來說VGGNet的貢獻可以概括如下兩點:

  • 所有隱藏層都使用了ReLU激活函數,而不是LRN(Local Response Normalization),因為LRN浪費了更多了記憶體和時間並且性能沒有太大提升。
  • 使用更小的卷積核和更小的滑動步長。和AlexNet相比,VGG的卷積核大小只有和兩種。卷積核的感受野很小,因此可以把網路加深,同時使用多個小卷積核使得網路總參數量也減少了。

其中卷積核相比於一個大尺寸的卷積核有更多的非線性函數,使得模型更有判別性。同時,多個層比一個大的卷積核參數更少,例如假設卷積層的輸出特徵圖和輸出特徵圖的大小分別是,,那麼三個卷積核的參數為。而一個的卷積核參數為。而至於為什麼個卷積核可以代替一個卷積核,這是因為這兩者的感受野是一致的,並且多個小卷積核非線性更多,效果更好。

而卷積的引入是在不影響輸入輸出維數的情況下,對輸入進行線性形變,然後通過Relu進行非線性處理,增加網路的非線性表達能力。

VGG-16的程式碼實現如下:

def VGG_16():      model = Sequential()        model.add(Conv2D(64,(3,3),strides=(1,1),input_shape=(224,224,3),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(Conv2D(64,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(MaxPooling2D(pool_size=(2,2)))        model.add(Conv2D(128,(3,2),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(Conv2D(128,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(MaxPooling2D(pool_size=(2,2)))        model.add(Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(MaxPooling2D(pool_size=(2,2)))        model.add(Conv2D(512,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(Conv2D(512,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(Conv2D(512,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(MaxPooling2D(pool_size=(2,2)))        model.add(Conv2D(512,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(Conv2D(512,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(Conv2D(512,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))      model.add(MaxPooling2D(pool_size=(2,2)))        model.add(Flatten())      model.add(Dense(4096,activation='relu'))      model.add(Dropout(0.5))      model.add(Dense(4096,activation='relu'))      model.add(Dropout(0.5))      model.add(Dense(1000,activation='softmax'))        return model

後記

今天講解了經典網路ZFNet和VGGNet,讓我們至少明白了一個東西,神經網路在2014年這個時期是在往更深的角度去發展。同時小卷積核的堆疊可以取代大卷積核。