1. 程式人生 > >理解卷積神經網路CNN中的特徵圖 feature map

理解卷積神經網路CNN中的特徵圖 feature map

         一直以來,感覺 feature map 挺晦澀難懂的,今天把初步的一些理解記錄下來。參考了斯坦福大學的機器學習公開課和七月演算法中的機器學習課。

        CNN一個牛逼的地方就在於通過感受野和權值共享減少了神經網路需要訓練的引數的個數。總之,卷積網路的核心思想是將:區域性感受野、權值共享(或者權值複製)以及時間或空間亞取樣這三種結構思想結合起來獲得了某種程度的位移、尺度、形變不變性.
       下圖左:如果我們有1000x1000畫素的影象,有1百萬個隱層神經元,那麼他們全連線的話(每個隱層神經元都連線影象的每一個畫素點),就有1000x1000x1000000=10^12個連線,也就是10^12個權值引數。然而影象的空間聯絡是區域性的,就像人是通過一個區域性的感受野去感受外界影象一樣,每一個神經元都不需要對全域性影象做感受,每個神經元只感受區域性的影象區域,然後在更高層,將這些感受不同區域性的神經元綜合起來就可以得到全域性的資訊了。這樣,我們就可以減少連線的數目,也就是減少神經網路需要訓練的權值引數的個數了。如下圖右:假如區域性感受野是10x10,隱層每個感受野只需要和這10x10的區域性影象相連線,所以1百萬個隱層神經元就只有一億個連線,即10^8個引數。比原來減少了四個0(數量級),這樣訓練起來就沒那麼費力了,但還是感覺很多的啊,那還有啥辦法沒?

  

      我們知道,隱含層的每一個神經元都連線10x10個影象區域,也就是說每一個神經元存在10x10=100個連線權值引數。那如果我們每個神經元這100個引數是相同的呢?也就是說每個神經元用的是同一個卷積核去卷積影象。這樣我們就只有多少個引數??只有100個引數啊!不管你隱層的神經元個數有多少,兩層間的連線我只有100個引數啊!這就是權值共享。
好了,你就會想,這樣提取特徵也忒不靠譜吧,這樣你只提取了一種特徵啊?對了,真聰明,我們需要提取多種特徵對不?假如一種濾波器,也就是一種卷積核就是提出影象的一種特徵,例如某個方向的邊緣。那麼我們需要提取不同的特徵,怎麼辦,加多幾種濾波器不就行了嗎?對了。所以假設我們加到100種濾波器,每種濾波器的引數不一樣,表示它提出輸入影象的不同特徵,例如不同的邊緣。這樣每種濾波器去卷積影象就得到對影象的不同特徵的放映,我們稱之為Feature Map。所以100種卷積核就有100個Feature Map。這100個Feature Map就組成了一層神經元。到這個時候明瞭了吧。我們這一層有多少個引數了?100種卷積核x每種卷積核共享100個引數=100x100=10K,也就是1萬個引數。才1萬個引數。見下圖右:不同的顏色表達不同的濾波器。

  

      嘿喲,遺漏一個問題了。剛才說隱層的引數個數和隱層的神經元個數無關,只和濾波器的大小和濾波器種類的多少有關。那麼隱層的神經元個數怎麼確定呢?它和原影象,也就是輸入的大小(神經元個數)、濾波器的大小和濾波器在影象中的滑動步長都有關!例如,我的影象是1000x1000畫素,而濾波器大小是10x10,假設濾波器沒有重疊,也就是步長為10,這樣隱層的神經元個數就是(1000x1000 )/ (10x10)=100x100個神經元了,假設步長是8,也就是卷積核會重疊兩個畫素,那麼……我就不算了,思想懂了就好。注意了,這只是一種濾波器,也就是一個Feature Map的神經元個數哦,如果100個Feature Map就是100倍了。由此可見,影象越大,神經元個數和需要訓練的權值引數個數的貧富差距就越大。

feature map計算方法:

在CNN網路中roi從原圖對映到feature map中的計算方法

INPUT為32*32,filter的大小即kernel size為5*5,stride = 1,pading=0,卷積後得到的feature maps邊長的計算公式是: 
output_h =(originalSize_h+padding*2-kernelSize_h)/stride +1 
所以,卷積層的feature map的變長為:conv1_h=(32-5)/1 + 1 = 28 
卷積層的feature maps尺寸為28*28. 
由於同一feature map共享權值,所以總共有6*(5*5+1)=156個引數。 
卷積層之後是pooling層,也叫下采樣層或子取樣層(subsampling)。它是利用影象區域性相關性的原理,對影象進行子抽樣,這樣在保留有用資訊的同時可以減少資料處理量。pooling層不會減少feature maps的數量,只會縮減其尺寸。常用的pooling方法有兩種,一種是取最大值,一種是取平均值。 
pooling過程是非重疊的,S2中的每個點對應C1中2*2的區域(也叫感受野),也就是說kernelSize=2,stride=2,所以pool1_h = (onv1_h - kernelSize_h)/stride +1 = (28-2)/2+1=14。pooling後的feature map尺寸為14*14.

 fast rcnn以及faster rcnn做檢測任務的時候,涉及到從影象的roi區域到feature map中roi的對映,然後再進行roi_pooling之類的操作。  
       比如影象的大小是(600,800),在經過一系列的卷積以及pooling操作之後在某一個層中得到的feature map大小是(38,50),那麼在原圖中roi是(30,40,200,400),
在feature map中對應的roi區域應該是
roi_start_w = round(30 * spatial_scale);
roi_start_h = round(40 * spatial_scale);
roi_end_w = round(200 * spatial_scale);
roi_end_h = round(400 * spatial_scale);
其中spatial_scale的計算方式是spatial_scale=round(38/600)=round(50/800)=0.0625,所以在feature map中的roi區域[roi_start_w,roi_start_h,roi_end_w,roi_end_h]=[2,3,13,25];
具體的程式碼可以參見caffe中roi_pooling_layer.cpp