2014-Network In Network

Network In Network學習筆記

原文地址http://blog.csdn.net/hjimce/article/details/50458190

作者:hjimce

一、相關理論

本篇博文主要講解2014年ICLR的一篇非常牛逼的paper:《Network In Network》,過去一年已經有了好幾百的引用量,這篇paper改進了傳統的CNN網絡,採用了少量的參數就鬆鬆擊敗了Alexnet網絡,Alexnet網絡參數大小是230M,採用這篇paper的算法才29M,減小了將近10倍啊。這篇paper提出的網絡結構,是對傳統CNN網絡的一種改進(這種文獻少之又少,所以感覺很有必要學習)。

傳統的卷積神經網絡一般來說是由:線性卷積層、池化層、全連接層堆疊起來的網絡。卷積層通過線性濾波器進行線性卷積運算,然後在接個非線性激活函數,最終生成特徵圖。以Relu激活函數爲例,特徵圖的計算公式爲:

 

其中(i,j)表示圖片像素點的位置索引,xij表示我們卷積窗口中的圖片塊,k則表示我們要提取的特徵圖的索引。

一般來說,如果我們要提取的一些潛在的特徵是線性可分的話,那麼對於線性的卷積運算來說這是足夠了。然而一般來說我們所要提取的特徵一般是高度非線性的。在傳統的CNN中,也許我們可以用超完備的濾波器,來提取各種潛在的特徵。比如我們要提取某個特徵,於是我就用了一大堆的濾波器,把所有可能的提取出來,這樣就可以把我想要提取的特徵也覆蓋到,然而這樣存在一個缺點,那就是網絡太恐怖了,參數太多了。

我們知道CNN高層特徵其實是低層特徵通過某種運算的組合。於是作者就根據這個想法,提出在每個局部感受野中進行更加複雜的運算,提出了對卷積層的改進算法:MLP卷積層。另一方面,傳統的CNN最後一層都是全連接層,參數個數非常之多,容易引起過擬合(如Alexnet),一個CNN模型,大部分的參數都被全連接層給佔用了,故這篇paper提出採用了:全局均值池化,替代全連接層。因此後面主要從這兩個創新點進行講解。

二、MLP卷積層(文獻創新點1)

這個是文獻的大創新點,也就是提出了mlpconv層。Mlpconv層可以看成是每個卷積的局部感受野中還包含了一個微型的多層網絡。其實在以前的卷積層中,我們局部感受野窗口的運算,可以理解爲一個單層的網絡,如下圖所示:


線性卷積層

CNN層的計算公式如下:


然而現在不同了,我們要採用多層的網絡,提高非線性,於是mlpconv層的網絡結構圖如下::

 

Mlpconv層

從上面的圖可以看到,說的簡單一點呢,利用多層mlp的微型網絡,對每個局部感受野的神經元進行更加複雜的運算,而以前的卷積層,局部感受野的運算僅僅只是一個單層的神經網絡罷了。對於mlpconv層每張特徵圖的計算公式如下:

一般來說mlp是一個三層的網絡結構。
下面是一個單層的mlpconv網絡的caffe網絡結構文件,源碼來自於:https://gist.github.com/mavenlin/d802a5849de39225bcc6 :
  1. <span style=“font-size:18px;”>layers {  
  2.   bottom: ”data”  
  3.   top: ”conv1”  
  4.   name: ”conv1”  
  5.   type: CONVOLUTION  
  6.   blobs_lr: 1  
  7.   blobs_lr: 2  
  8.   weight_decay: 1  
  9.   weight_decay: 0  
  10.   convolution_param {  
  11.     num_output: 96  
  12.     kernel_size: 11  
  13.     stride: 4  
  14.     weight_filler {  
  15.       type: ”gaussian”  
  16.       mean: 0  
  17.       std: 0.01  
  18.     }  
  19.     bias_filler {  
  20.       type: ”constant”  
  21.       value: 0  
  22.     }  
  23.   }  
  24. }  
  25. layers {  
  26.   bottom: ”conv1”  
  27.   top: ”conv1”  
  28.   name: ”relu0”  
  29.   type: RELU  
  30. }  
  31. layers {  
  32.   bottom: ”conv1”  
  33.   top: ”cccp1”  
  34.   name: ”cccp1”  
  35.   type: CONVOLUTION  
  36.   blobs_lr: 1  
  37.   blobs_lr: 2  
  38.   weight_decay: 1  
  39.   weight_decay: 0  
  40.   convolution_param {  
  41.     num_output: 96  
  42.     kernel_size: 1  
  43.     stride: 1  
  44.     weight_filler {  
  45.       type: ”gaussian”  
  46.       mean: 0  
  47.       std: 0.05  
  48.     }  
  49.     bias_filler {  
  50.       type: ”constant”  
  51.       value: 0  
  52.     }  
  53.   }  
  54. }  
  55. layers {  
  56.   bottom: ”cccp1”  
  57.   top: ”cccp1”  
  58.   name: ”relu1”  
  59.   type: RELU  
  60. }  
  61. layers {  
  62.   bottom: ”cccp1”  
  63.   top: ”cccp2”  
  64.   name: ”cccp2”  
  65.   type: CONVOLUTION  
  66.   blobs_lr: 1  
  67.   blobs_lr: 2  
  68.   weight_decay: 1  
  69.   weight_decay: 0  
  70.   convolution_param {  
  71.     num_output: 96  
  72.     kernel_size: 1  
  73.     stride: 1  
  74.     weight_filler {  
  75.       type: ”gaussian”  
  76.       mean: 0  
  77.       std: 0.05  
  78.     }  
  79.     bias_filler {  
  80.       type: ”constant”  
  81.       value: 0  
  82.     }  
  83.   }  
  84. }  
  85. layers {  
  86.   bottom: ”cccp2”  
  87.   top: ”cccp2”  
  88.   name: ”relu2”  
  89.   type: RELU  
  90. }  
  91. </span>  
<span style="font-size:18px;">layers {
  bottom: "data"
  top: "conv1"
  name: "conv1"
  type: CONVOLUTION
  blobs_lr: 1
  blobs_lr: 2
  weight_decay: 1
  weight_decay: 0
  convolution_param {
    num_output: 96
    kernel_size: 11
    stride: 4
    weight_filler {
      type: "gaussian"
      mean: 0
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layers {
  bottom: "conv1"
  top: "conv1"
  name: "relu0"
  type: RELU
}
layers {
  bottom: "conv1"
  top: "cccp1"
  name: "cccp1"
  type: CONVOLUTION
  blobs_lr: 1
  blobs_lr: 2
  weight_decay: 1
  weight_decay: 0
  convolution_param {
    num_output: 96
    kernel_size: 1
    stride: 1
    weight_filler {
      type: "gaussian"
      mean: 0
      std: 0.05
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layers {
  bottom: "cccp1"
  top: "cccp1"
  name: "relu1"
  type: RELU
}
layers {
  bottom: "cccp1"
  top: "cccp2"
  name: "cccp2"
  type: CONVOLUTION
  blobs_lr: 1
  blobs_lr: 2
  weight_decay: 1
  weight_decay: 0
  convolution_param {
    num_output: 96
    kernel_size: 1
    stride: 1
    weight_filler {
      type: "gaussian"
      mean: 0
      std: 0.05
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layers {
  bottom: "cccp2"
  top: "cccp2"
  name: "relu2"
  type: RELU
}
</span>

三、全局均值池化(文獻創新點2)

傳統的卷積神經網絡卷積運算一般是出現在低層網絡。對於分類問題,最後一個卷積層的特徵圖通過量化然後與全連接層連接,最後在接一個softmax邏輯迴歸分類層。這種網絡結構,使得卷積層和傳統的神經網絡層連接在一起。我們可以把卷積層看做是特徵提取器,然後得到的特徵再用傳統的神經網絡進行分類。

然而,全連接層因爲參數個數太多,往往容易出現過擬合的現象,導致網絡的泛化能力不盡人意。於是Hinton採用了Dropout的方法,來提高網絡的泛化能力。

本文提出採用全局均值池化的方法,替代傳統CNN中的全連接層。與傳統的全連接層不同,我們對每個特徵圖一整張圖片進行全局均值池化,這樣每張特徵圖都可以得到一個輸出。這樣採用均值池化,連參數都省了,可以大大減小網絡,避免過擬合,另一方面它有一個特點,每張特徵圖相當於一個輸出特徵,然後這個特徵就表示了我們輸出類的特徵。這樣如果我們在做1000個分類任務的時候,我們網絡在設計的時候,最後一層的特徵圖個數就要選擇1000,下面是《Network In Network》網絡的源碼,倒數一層的網絡相關參數

  1. layers {  
  2. bottom: ”cccp7”  
  3. top: ”cccp8”  
  4. name: ”cccp8-1024”  
  5. type: CONVOLUTION  
  6. blobs_lr: 1  
  7. blobs_lr: 2  
  8. weight_decay: 1  
  9. weight_decay: 0  
  10. convolution_param {  
  11. num_output: 1000  
  12. kernel_size: 1   
  13. stride: 1  
  14. weight_filler {  
  15. type: ”gaussian”  
  16. mean: 0  
  17. std: 0.01  
  18. }  
  19. bias_filler {  
  20. type: ”constant”  
  21. value: 0  
  22. }  
  23. }  
  24. }  
layers {
bottom: "cccp7"
top: "cccp8"
name: "cccp8-1024"
type: CONVOLUTION
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
convolution_param {
num_output: 1000
kernel_size: 1 
stride: 1
weight_filler {
type: "gaussian"
mean: 0
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}

全局均值池化層的相關參數如下:

  1. layers {  
  2. bottom: ”cccp8”  
  3. top: ”pool4”  
  4. name: ”pool4”  
  5. type: POOLING  
  6. pooling_param {  
  7. pool: AVE  
  8. kernel_size: 6  
  9. stride: 1  
  10. }  
  11. }  
layers {
bottom: "cccp8"
top: "pool4"
name: "pool4"
type: POOLING
pooling_param {
pool: AVE
kernel_size: 6
stride: 1
}
}

因爲在Alexnet網絡中,最後一個卷積層輸出的特徵圖大小剛好是6*6,所以我們pooling的大小選擇6,方法選擇:AVE。

四、總體網絡架構

根據上面的作者對傳統CNN的兩個改進,利用其進行1000物體分類問題,於是作者最後設計了一個:4層的NIN+全局均值池化,網絡如下:


個人總結:個人感覺這篇文獻很有價值,實現方式也很簡單,一開始我還以爲需要caffe的c++源碼來實現NIN網絡,結果發現實現NIN的源碼實現方式其實就是一個1*1的卷積核,實現卷積運算,所以實現起來相當容易,不需要自己寫源碼,只需要簡簡單單的把卷積核的大小變一下,然後最後一層的全連接層直接用avg pooling替換一下就ok了。個人評價:網絡淺顯易懂,簡單實現,卻可以改進原來的網絡,提高精度,減小模型大小,所以是一篇很值得學習的文獻。後續即將講解另外幾篇2015年,也是對CNN網絡結構改進的牛逼文獻:《Spatial Transformer Networks》、《Striving For Simplicity:The All Convolutional Net》、《Stacked What-Where Auto-encoders》,敬請期待,畢竟這樣的文章敢於挑戰傳統的CNN結構,對其不知做出改進,所以我們需要一篇一篇的學。

參考文獻:

1、《Network In Network》

2、https://github.com/BVLC/caffe/wiki/Model-Zoo

3、https://gist.github.com/mavenlin/d802a5849de39225bcc6 

4、《Maxout Networks》

**********************作者:hjimce   時間:2016.1.4  聯繫QQ:1393852684     原創文章,版權所有,轉載請保留本行信息***************

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章