目標檢測算法之FPN(附FPN代碼實現)

  • 論文題目:FeaturePyramidNetworksforObjectDetection
  • 論文鏈接:https://arxiv.org/abs/1612.03144

所要解決的問題

針對小目標檢測網絡,CV領域一般用的是特徵金字塔。即將原圖以不同的比例採樣,然後得到不同分辨率的圖像進行訓練和測試,在多數情況下是有效的。但是特徵金字塔的計算、內存和時間開銷都非常大,導致在工程中應用是及其困難。FPN(即特徵金字塔)提出了一個獨特的特徵金字塔網絡來避免圖像金字塔產生的超高計算量,同時可以較好的處理目標檢測中的尺度變化問題,對於小目標檢測具有很強的魯棒性。

簡介

下圖表示FPN的整體結構:

圖a  多尺度金字塔 這是一個特徵圖像金字塔,整個過程是先對原始圖像構造圖像金字塔,然後在圖像金字塔的每一層提出不同的特徵,然後進行相應的預測。這種方法的缺點是計算量大,需要大量的內存;優點是可以獲得較好的檢測精度。

圖b  淺層的網絡更關注於細節和位置信息,高層的網絡更關注於語義信息,而高層的語義信息能夠幫助我們準確的檢測出目標,因此我們可以利用最後一個卷積層上的feature map來進行預測。

圖c  同時利用低層特徵和高層特徵,分別在不同的層同時進行預測,這是因爲我的一幅圖像中可能具有多個不同大小的目標,區分不同的目標可能需要不同的特徵,對於簡單的目標我們僅僅需要淺層的特徵就可以檢測到它,對於複雜的目標我們就需要利用複雜的特徵來檢測它。整個過程就是首先在原始圖像上面進行深度卷積,然後分別在不同的特徵層上面進行預測。

圖d(FPN網絡) 首先我們在輸入的圖像上進行深度卷積,然後對Layer2上面的特徵進行降維操作(即添加一層1x1的卷積層),對Layer4上面的特徵就行上採樣操作,使得它們具有相應的尺寸,然後對處理後的Layer2和處理後的Layer4執行加法操作(對應元素相加),將獲得的結果輸入到Layer5中去。其背後的思路是爲了獲得一個強語義信息,這樣可以提高檢測性能。其實看下面的代碼就可以明白,把卷積之後的{Ck}層和上採樣之後的{Pk}層進行相加,目的是把低層次高分辨率的信息和高層次強語義的信息結合起來,提高檢測性能和小目標識別。

FPN結構

自底向上

這是神經網絡的前向計算,就是由卷積和池化層組成的特徵提取網絡。在這個自底向上的結構中,一個stage對應特徵金字塔的一個level。對於以ResNet爲backbone的主幹網絡,選取conv2、conv3、conv4、conv5層的最後一個殘差block層特徵作爲FPN的特徵,記爲{C2、C3、C4、C5},也即是FPN網絡的4個級別。這幾個特徵層相對於原圖的步長分別爲4、8、16、32。

自上向下和側向連接

自上向下是前向計算後將輸出的特徵圖放大的過程,我們一般採用upsample(上採樣)來實現。FPN的巧妙之處就在於從高層特徵上採樣不僅可以利用頂層的高語義、低分辨率信息(有助於分類),而且利用淺層的、低語義、高分辨率信息(有助於定位)。爲了將上述兩者相結合,論文提出了類似於殘差結構的側向連接。向連接將上一層經過上採樣後和當前層分辨率一致的特徵,通過相加的方法(如:pytorch的torch.cat或torch.add)進行融合。同時爲了保持所有級別的特徵層通道數都保持一致,這裏使用1*1卷積來實現。

ResNet+FPN網絡結構及代碼實現

# Build the shared convolutional layers.
# Bottom-up Layers
# Returns a list of the last layers of each stage, 5 in total.
# 扔掉了C1
_, C2, C3, C4, C5 = resnet_graph(input_image, "resnet101", stage5=True)
# Top-down Layers
# TODO: add assert to varify feature map sizes match what's in config
P5 = KL.Conv2D(256, (1, 1), name='fpn_c5p5')(C5)
P4 = KL.Add(name="fpn_p4add")([
    KL.UpSampling2D(size=(2, 2), name="fpn_p5upsampled")(P5),
    KL.Conv2D(256, (1, 1), name='fpn_c4p4')(C4)])
P3 = KL.Add(name="fpn_p3add")([
    KL.UpSampling2D(size=(2, 2), name="fpn_p4upsampled")(P4),
    KL.Conv2D(256, (1, 1), name='fpn_c3p3')(C3)])
P2 = KL.Add(name="fpn_p2add")([
    KL.UpSampling2D(size=(2, 2), name="fpn_p3upsampled")(P3),
    KL.Conv2D(256, (1, 1), name='fpn_c2p2')(C2)])
# 把每個{Pk}層都乘以一個3*3的卷積生成特徵圖.
P2 = KL.Conv2D(256, (3, 3), padding="SAME", name="fpn_p2")(P2)
P3 = KL.Conv2D(256, (3, 3), padding="SAME", name="fpn_p3")(P3)
P4 = KL.Conv2D(256, (3, 3), padding="SAME", name="fpn_p4")(P4)
P5 = KL.Conv2D(256, (3, 3), padding="SAME", name="fpn_p5")(P5)
# P6 is used for the 5th anchor scale in RPN. Generated by
# subsampling from P5 with stride of 2.
P6 = KL.MaxPooling2D(pool_size=(1, 1), strides=2, name="fpn_p6")(P5)
# Note that P6 is used in RPN, but not in the classifier heads.
rpn_feature_maps = [P2, P3, P4, P5, P6]
mrcnn_feature_maps = [P2, P3, P4, P5]

實驗

FPN對Fast RCNN的影響

使用和實驗1相同的規則對Fast RCNN做了實驗,結果如下表所示。

FPN對Segment Proposal的影響

結論

本文提出了一種簡單、有效的建立特徵金字塔的方式。它的使用對RPN方法和Fast/Faster RCNN方法都有極大的性能提升。另外,它的訓練和測試時間和普通的Faster RCNN方法相差很小。因此,它可以作爲圖像特徵金字塔的一種較好的替代。

論文開源代碼

https://github.com/unsky/FPN

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