目標檢測:SPPNet 論文閱讀

回顧歷史,SPPNet 標誌著人們更加深入的使用 CNN 去做目標檢測問題,這篇論文的作者們暗埋下的一條思緒讓我深受啟發,在此特地向他們致敬!

論文:Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition

核心思想

R-CNN 扔了一塊敲門磚,從此後來者絡繹不絕,SPPNet 的作者們點「磚」為「塔」,從此一起踏入了目標檢測的煉丹事業。針對 R-CNN 提出了兩點改進思想:

改進1:先卷積後取區域

R-CNN 提取特徵的順序是先生成區域、再通過卷積神經網路提取特徵,雖然相比傳統的滑窗策略減少了大量的運算,但是依舊有大量的算力冗餘。

不同區域會有大量的重疊,對同一個區域的重複計算是不符合經濟學原理的,於是何愷明等作者改變了一下順序——先卷積,再特徵圖上取區域特徵。這一操作雖然看似簡單,但實際上凡而不凡。

改進2:不固定輸入尺寸

一張 16:9 的圖片 Resize1:1 的圖片,就算是人眼看都會覺得很難受,更何況對卷積核。抱著讓輸入更加原汁原味,對卷積核更友好地想法,何愷明等人思索出了 SPPooling 層,解決了不定尺寸輸入、定尺寸輸出的問題。

他們發現必須定尺寸輸入的原因是後面的全連接層需要固定參數,那麼只需要在 FC 層前加一個自定義的 Pooling 層,保證傳到下一層的輸入固定。這就是他們想出解決辦法大致思路,但是他們並不知道自己實現的這個 SPPooling 對後面有多大的影響。

這個 SPPooling 層大致原理就是「拼湊七巧板」,我們需要的輸出是一個固定的模樣,輸入是和輸出不一樣大小尺寸的數據,那麼我們將輸入通過 Pooling 將輸入變成輸出的模樣、或者變成輸出模樣的一部分,最後達到輸出固定尺寸數據的效果。

這一改進可謂是在 FCN 前的偉大創舉,不固定輸入尺寸保留原有特徵,對卷積核更加友好,從而提升識別的效果。

流程步驟

仍然是四個步驟:

1、使用 EdgeBoxes 演算法生成候選區域

2、使用 CNN 提取全圖特徵

3、將候選區域特徵輸入到 SVM 分類器,判別輸入類別

4、以回歸的方式精修候選框

註:作者在此選擇了 EdgeBoxes 演算法而不是 Selective Search 演算法。

核心部分

SPPNet 和 R-CNN 的區別如我們再核心思想上講的,我們在此只探討「卷積後取特徵」以及「SPPooling」,雖然生成候選區域的演算法變成了 EdgeBoxes 但是改變不了他們提取的特徵還是 Low Level 的特徵。

先卷積,後取特徵

其實從這裡開始,就體現了作者們的功力,他們對 feature map 進行可視化處理,發現 feature map 裡面有豐富的抽象後的信息,給後續的 R-CNN 大升級埋下了伏筆。

先卷積後取特徵,最為麻煩的問題就是原始圖和卷積處理後的圖尺寸是不一樣的,所以我們首先要找到對應關係,這部分作者們在 Appendix 中有詳細的介紹。

假設原圖某點的坐標是 (x,y) ,特徵圖該點的坐標是 (x′,y′) ,由於不同層處理後的特徵圖大小尺寸不一樣,所以轉換有一個中間參數 S ,最後得到 (x,y)=(Sx′,Sy′)

那麼我們就可以得到如下坐標公式:

Left (top) boundary: x』 = [x/S] + 1

Right (bottom) boundary: x』 = [x/S] - 1

其中 SS 是卷積神經網路中所有的 strides 的乘積,包含了池化、卷積的 stride

我們可以從上圖中計算出對應的 SS :

ZF-5:  2?2?2?2 = 16

Overfeat-5/7: 2?3?2=12

SPPooling

SPPNet 最核心的還是 SPPooling ,解決了可以輸入任意尺寸圖片的問題,而對「目標檢測」而言,圖像中物體的尺寸是一個很重要的特徵。

SPPNet 實際上做了一個自適應的功能,利用 PoolingStidePadding 對輸入數據進行任意尺寸的改變。一個 SPPooling層可能會有多個 Pooling ,多個 Pooling 帶來的好處就是 多尺度觀察 ,這也是 SPPNet 準確度有提高的原因之一。

上面是論文給的圖,下面給出 SPPooling 層的實現代碼,幫助我們更好理解:

import mathdef spatial_pyramid_pool(self,previous_conv, num_sample, previous_conv_size, out_pool_size): previous_conv: a tensor vector of previous convolution layer num_sample: an int number of image in the batch previous_conv_size: an int vector [height, width] of the matrix features size of previous convolution layer out_pool_size: a int vector of expected output size of max pooling layer returns: a tensor vector with shape [1 x n] is the concentration of multi-level pooling # print(previous_conv.size()) for i in range(len(out_pool_size)): # print(previous_conv_size) h_wid = int(math.ceil(previous_conv_size[0] / out_pool_size[i])) w_wid = int(math.ceil(previous_conv_size[1] / out_pool_size[i])) h_pad = (h_wid*out_pool_size[i] - previous_conv_size[0] + 1)/2 w_pad = (w_wid*out_pool_size[i] - previous_conv_size[1] + 1)/2 maxpool = nn.MaxPool2d((h_wid, w_wid), stride=(h_wid, w_wid), padding=(h_pad, w_pad)) x = maxpool(previous_conv) if(i == 0): spp = x.view(num_sample,-1) # print("spp size:",spp.size()) else: # print("size:",spp.size()) spp = torch.cat((spp,x.view(num_sample,-1)), 1) return spp

代碼來源:sppnet-pytorch - Github

在同年 9 月,Google 團隊發布了第一版本的 Inception ,裡面就借鑒了多尺度觀察的思想,雖然一個是池化層一個是卷積核,但並不影響這個思想的偉大。

總結 Summary

SPPNet 改變了卷積的順序,減少了冗餘的計算量,大大提高了對圖片處理的速度。也從這一思想可以看出作者們對卷積神經網路的理解十分深刻,特別是從這個時候開始就埋下了對 Feature Map 極致利用的主線。將金字塔池化 SPPooling 引入到卷積神經網路中,從此無需固定圖像輸入尺寸,保留更多的特徵、對卷積核更加友好。

雖然其他的部分都是基於 R-CNN 的,但是他們這兩大改進所體現出來的思想就足以讓人注目眺望。

參考資料 Reference

  1. SPPNet 「Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition」
  2. RCNN–對象檢測的又一偉大跨越 2(包括SPPnet、Fast RCNN)
  3. SPP-Net論文詳解

推薦閱讀:

TAG:深度學習DeepLearning | 目標檢測 |