原始圖片中的ROI如何映射到到feature map?

原始圖片中的ROI如何映射到到feature map?


鏈接: https://zhuanlan.zhihu.com/p/24780433

在SPP-net中的難點一曾提到:ROI如何對應到feature map?

這個地方遇到不少坑,看了很多資料都沒有太明白,感覺太繞。

先數數遇到的坑:

  • 《Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition》原文是這樣寫的,一臉懵逼。
  • 找了張圖是這樣畫的:有那麼點意思,好像是從前向後推出各個層的感受野,可是還是不懂爲啥這樣。
  • 這兩張圖,看的有點摸不着頭腦


迴歸正題

最後找到一篇靠譜的文章 卷積神經網絡物體檢測之感受野大小計算 - machineLearning - 博客園,它給出了一個不錯的啓發,還附帶了代碼,最關鍵的是它給出了參考鏈接。 於是我終於在參考鏈接找到了這篇 Concepts and Tricks In CNN(長期更新) 最佳博文,不僅清晰易懂,而且公式詳細。(不過感覺略有不足,所以下面就詳細介紹一下這個大坑)

【先說說感受野的計算】

回憶一下我之前在 卷積神經網絡(CNN)簡介 裏就曾經畫圖推導過的一個公式(這個公式很常見,可是竟然很少有人去講它怎麼來的,當時我在寫 CNN簡介就順便畫圖推導了一下,沒細看的同學可以回頭看看)

原文裏提到:隱藏層邊長(輸出的邊長) = (W - K + 2P)/S + 1 
(其中 W是輸入特徵的大小,K是卷積核大小,P是填充大小,S是步長(stride))

爲了理解方便我就把公式先用英文寫一下:

output field size = ( input field size - kernel size + 2*padding ) / stride + 1

(output field size 是卷積層的輸出,input field size 是卷積層的輸入)

反過來問你: 卷積層的輸入(也即前一層的感受野) = ?

答案必然是: input field size = (output field size - 1)* stride - 2*padding + kernel size

再重申一下:卷積神經網絡CNN中,某一層輸出結果中一個元素所對應的輸入層的區域大小,被稱作感受野receptive field。感受野的大小是由kernel size,stride,padding , outputsize 一起決定的。

Concepts and Tricks In CNN(長期更新) 裏截張圖你感受一下:

公式化一下:

  • 對於Convolution/Pooling layer(博文作者忘了加上padding本文在這裏補上):r_i = s_i \cdot (r_{i+1} - 1) + k_i -2 \cdot padding
  • 對於 Neuronlayer(ReLU/Sigmoid/..) :r_I = r_{i+1} (顯然如此)

上面只是給出了 前一層在後一層的感受野,如何計算最後一層在原始圖片上的感受野呢? 從後向前級聯一下就可以了(先計算最後一層到倒數第二層的感受野,再計算倒數第二層到倒數第三層的感受野,依次從後往前推導就可以了)

卷積神經網絡物體檢測之感受野大小計算 - machineLearning - 博客園 中用如下核心代碼計算了 Alexnet zf-5和VGG16網絡每層輸出feature map的感受野大小。

net_struct = {'alexnet': {'net':[[11,4,0],[3,2,0],[5,1,2],[3,2,0],[3,1,1],[3,1,1],[3,1,1],[3,2,0]],
                   'name':['conv1','pool1','conv2','pool2','conv3','conv4','conv5','pool5']},
       'vgg16': {'net':[[3,1,1],[3,1,1],[2,2,0],[3,1,1],[3,1,1],[2,2,0],[3,1,1],[3,1,1],[3,1,1],
                        [2,2,0],[3,1,1],[3,1,1],[3,1,1],[2,2,0],[3,1,1],[3,1,1],[3,1,1],[2,2,0]],
                 'name':['conv1_1','conv1_2','pool1','conv2_1','conv2_2','pool2','conv3_1','conv3_2',
                         'conv3_3', 'pool3','conv4_1','conv4_2','conv4_3','pool4','conv5_1','conv5_2','conv5_3','pool5']},
       'zf-5':{'net': [[7,2,3],[3,2,1],[5,2,2],[3,2,1],[3,1,1],[3,1,1],[3,1,1]],
               'name': ['conv1','pool1','conv2','pool2','conv3','conv4','conv5']}}

imsize = 224

def outFromIn(isz, net, layernum):#從前向後算輸出維度
    totstride = 1
    insize = isz
    for layer in range(layernum):
        fsize, stride, pad = net[layer]
        outsize = (insize - fsize + 2*pad) / stride + 1
        insize = outsize
        totstride = totstride * stride
    return outsize, totstride

def inFromOut(net, layernum):#從後向前算感受野 返回該層元素在原始圖片中的感受野
    RF = 1
    for layer in reversed(range(layernum)):
        fsize, stride, pad = net[layer]
        RF = ((RF -1)* stride) + fsize
    return RF

【再談談感受野上面的座標映射 (Coordinate Mapping)】

爲了完整性直接摘錄博客內容了:

通常,我們需要知道網絡裏面任意兩個feature map之間的座標映射關係(一般是中心點之間的映射),如下圖,我們想得到map 3上的點p3映射回map 2所在的位置p2(橙色框的中心點)


計算公式:
  • 對於 Convolution/Pooling layer: pi = s_i \cdot p_{i+1} +( (k_i -1)/2 - padding)
  • 對於Neuronlayer(ReLU/Sigmoid/..) : p_I = p_{i+1}

上面是計算任意一個layer輸入輸出的座標映射關係,如果是計算任意feature map之間的關係,只需要用簡單的組合就可以得到,下圖是一個簡單的例子:



最後說一下 前面那張PPT裏的公式。


  • 對於上面 A simple solution:其實也是何凱明在SPP-net中採用的方法。其實就是巧妙的化簡一下公式 pi = s_i \cdot p_{i+1} +( (k_i -1)/2 - padding) 令每一層的padding都爲 padding = \lfloor k_i /2 \rfloor  \Rightarrow   pi = s_i \cdot p_{i+1} +( (k_i -1)/2 -  \lfloor k_i /2 \rfloor)
    • 當 k_i 爲奇數 ( (k_i -1)/2 -  \lfloor k_i /2 \rfloor) = 0 所以 p_i = s_i \cdot p_{i+1}
    • k_i 爲偶數 ( (k_i -1)/2 -  \lfloor k_i /2 \rfloor) = -0.5 所以 p_i = s_i \cdot p_{i+1} -0.5
    • 而 p_i 是座標值,不可能取小數 所以基本上可以認爲 p_i = s_i \cdot p_{i+1} 。公式得到了化簡:感受野中心點的座標p_i只跟前一層 p_{i+1} 有關。
  • 對於上面的 A general solution: 其實就是把 公式 pi = s_i \cdot p_{i+1} +( (k_i -1)/2 - padding) 級聯消去整合一下而已。


SPP-net的ROI映射做法詳解

SPP-net 是把原始ROI的左上角和右下角 映射到 feature map上的兩個對應點。 有了feature map上的兩隊角點就確定了 對應的 feature map 區域(下圖中橙色)。

如何映射?

左上角的點(x,y)映射到 feature map上的(x',y') : 使得 (x',y') 在原始圖上感受野(上圖綠色框)的中心點 與(x,y)儘可能接近。

對應點之間的映射公式是啥?

  • 就是前面每層都填充padding/2 得到的簡化公式 : p_i = s_i \cdot p_{i+1}
  • 需要把上面公式進行級聯得到 p_0 = S \cdot p_{i+1} 其中 (S = \prod_{0}^{i} s_i)
  • 對於feature map 上的 (x',y') 它在原始圖的對應點爲 (x,y) = (Sx', Sy')
  • 論文中的最後做法:把原始圖片中的ROI映射爲 feature map中的映射區域(上圖橙色區域)其中 左上角取:x' =  \lfloor x/S \rfloor +1  ,\;y' =  \lfloor y/S \rfloor +1, ;右下角的點取: 界取y'的x值:x' =  \lceil x/S \rceil - 1  ,\;y' =  \lceil y/S \rceil - 1。 下圖可見 \lfloor x/S \rfloor +1 , \lceil x/S \rceil - 1 的作用效果分別是增加和減少。也就是 左上角要向右下偏移,右下角要想要向左上偏移。個人理解採取這樣的策略是因爲論文中的映射方法(左上右下映射)會導致feature map上的區域反映射回原始ROI時有多餘的區域(下圖左邊紅色框是比藍色區域大的)



參考:

《Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition》

Concepts and Tricks In CNN(長期更新)

卷積神經網絡物體檢測之感受野大小計算 - machineLearning - 博客

iccv2015_tutorial_convolutional_feature_maps_kaiminghe.

卷積神經網絡(CNN)簡介


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