金字塔c_FPN特征金字塔网络解读
上傳在github:https://github.com/FermHan/Learning-Notes發表在CSDN:https://blog.csdn.net/hancoder/article/發表在知乎專欄:https://zhuanlan.zhihu.com/c_1088438808227254272
預備知識: Faster R-CNN,RPN可見本人博客https://blog.csdn.net/hancoder/article/details/87917174
Feature Pyramid Networks for Object Detection (簡稱FPN)
作者Tusing-Yi Lin,Ross Girshich,Kaiming He
[TOC]
1、常見卷積與FPN模型
首先看幾種卷積分類方式
(a) Featurized image pyramid 計算與內存開銷太大
剛開始你可能會不熟悉這4個命名方式,你只需記住第一個里是圖像image金字塔,而FPN是特征feature金字塔。因為需要縮放原圖然后進行卷積,這種卷積方式肯定是耗內存的,最不科學的。
(b) Single feature map 框不出小物體
b所講的就是簡單的分類網絡,如AlexNet等。使用Single feature map的包括R-CNN、SPPNet、Fast R-CNN、Faster R-CNN、YOLOv1以及R-FCN系列。
(c) Pyramidal feature hierarchy 底層大scale的feature map語義信息少,雖然框出了小物體,但小物體容易被錯分:
使用Pyramidal feature hierarchy的包括SSD。SSD沒有上采樣過程,因為是在原有特征圖上預測的,所以也不會增加額外的計算開銷,但作者認為SSD沒有用到足夠底層的特征,而越底層的特征對檢測小物體越有利。SSD用的最底層的特征是conv4_3。SSD也可以去我的CSDN等地觀看。
Note:
- YOLOv2是個特例,其在 26×26 層設置了通道層接至 13×13 層。本質上即為single-scale上處理two-scale的feature map信息。
總結:上面abc這三種卷積方式都不是特征理想,那么怎么才能兼顧準確率(檢測小物體)和速度(開銷)呢?
FPN的框架
(d) Feature Pyramid Network
參照d圖及下圖。特征金字塔網絡相當于先進行傳統的bottom-up自上而下的特征卷積(d圖左側),然后FPN試圖融合左側特征圖的相鄰的特征圖。左側模型叫bottom-up,右側模型叫top-down,橫向的箭頭叫橫向連接lateral connections。這么做的目的是因為高層的特征語義多,低層的特征語義少但位置信息多。
左側模型特征圖大小相差1倍,但像AlexNet一樣,其實是每在同樣大小的feature上卷積幾次才進行一次池化操作,我們把在同樣大小feature上的卷積稱之為一個stage。d圖這里畫的圖是每個stage的最后一個卷積層,因為每個stage的最后一層feature語義信息最多
具體做法是兩個特征層的較高層特征2倍上采樣(上采樣方法很多,上采樣幾乎都是采用內插值方法,即在原有圖像像素的基礎上在像素點之間采用合適的插值算法插入新的元素,總之是把feature大小擴大了一倍)。較低層特征通過1×1卷積改變一下低層特征的通道數,然后簡單地把將上采樣和1×1卷積后的結果對應元素相加。為什么橫向連接要使用1×1卷積呢,為什么不能原地不動地拿過來呢?原來在于作者想用1×1改變通道數,以達到各個level處理結果的channel都為256-d,便于后面對加起來的特征進行分類。這段文字表述的即是下圖。
FPN只是提取特征的一種方法而已,這篇論文作者的應用于實驗主要是在Faster R-CNN上進行的。
雖然d圖只畫了3個stage,但我們以論文描述的為主,其實最起碼有6個stage。左側模型從低到高的卷積結果記為C2,C3,C4,C5,C6(有C1,但是論文里是拋棄了這層,為了不造成混淆,所以這里自動忽略了),同理右側模型從低到高記為P2,P3,P4,P5,P6。接下來的內容最好聯系下圖Faster R-CNN網絡進行學習。
先在圖像上進行完像圖d一樣的操作后,得到FPN的結果,結果即d圖右側模型$P_i$。而d圖左側是普通的主干網絡$C_i$。然后我們在FPN的結果(d圖右側)上進行操作:像Faster R-CNN中的RPN一樣,先在$P_i$上進行3×3的卷積操作,然后在此結果上,兩支并行的1×1卷積核分別卷積出來分類(前背景)與框位置信息(xywh)。
然后我們把RPN的結果拿出來進行RoIpooling后進行分類。
至此FPN的框架介紹結束,簡言之把FPN結合到普通網絡中后,有三條路線:Bottom-up pathway + Top-down pathway + lateral connections。
2、框架三部分Details
Bottom-up pathway
Bottom-up的畫的是每個stage的最后一層feature,這個我們已經前文說過,因為該層有最strong的特征。
此文用的是ResNet,所以$C_i={C_2,C_3,C_4,C_5}?$,分別對應conv2,conv3,conv4,conv5的輸出,與原圖相比的步長分別是{4,8,16,32}。不要conv1的原因是its large memory footprint(能體會但是不會翻譯)。
Top-down pathway and lateral connections
上采樣操作降低了特征的分辨率(hallucinate higher resolution features,這句可能沒理解好,望糾正)。但是這些上采樣的結果通過與橫向連接結合,相加更好enhance了。相加的兩者中,bottom-up的特征$C_i$雖然語義信息較少,但他的位置信息較多,因為他的下采樣次數更少。The bottom-up feature map is of lower-level semantics,but its activations are more accurately localized as it was subsampled fewer times
在ResNet中,先在$C_5$上進行1×1卷積降維通道數,與上采樣結果相加融合后用3×3卷積處理,以減小上采樣帶來的混淆現象(附原文We append a 3×3 convolution on each merged map to generate the final feature map,which is to reduce the aliasing effect of upsampling)。相加的結果稱為${P_2,P_3,P_4,P_5}$,與同樣大小的$C_i$對應。
因為金字塔所有級level使用相同的分類/回歸器(這句應該指的是RPN),所以固定了特征圖上的通道數d都為256,即每個stage或每個level的特征圖$P_i?$的通道數都是d=256。
由上圖可以看出(圖上P5P6處有些錯誤),我們的C2-C5是正常卷積出來的,P5是1×1卷積改變通道數256后的結果,其余P4,P3,P2是1×1卷積和上采樣加和的融合。然后P2-P5經過3×3卷積后仍然叫P2-P5(Pi處理后賦值給Pi)。P6是從P5極大值池化后直接得到的
3、應用
FPN for RPN
RPN即一個用于目標檢測的一系列滑動窗口。具體地,RPN是先進行3×3,然后跟著兩條并行的1×1卷積,分布產生前背景分類和框位置回歸,我們把這個組合叫做網絡頭部network head。
但是前背景分類與框位置回歸是在anchor的基礎上進行的,簡言之即我們先人為定義一些框,然后RPN基于這些框進行調整即可。在SSD中anchor叫prior,更形象一些。為了回歸更容易,anchor在Faster R-CNN中預測了3種大小scale,寬高3種比率ratio{1:1,1:2,2:1},共9種anchor框。
在FPN中我們同樣用了一個3×3和兩個并行的1×1,但是是在每個級上都進行了RPN這種操作。既然FPN已經有不同大小的特征scale了,那么我們就沒必要像Faster R-CNN一樣采用3中大小的anchor了,我們只要采用3種比率的框就行了。所以每個級level的anchor都是相同的scale。所以我們在${P_2,P_3,P_4,P_5,P_6}$上分別定義anchor的scale為${32^2,64^2,128^2,256^2,521^2}$,在每級level的$P_i?$上有{1:1,1:2,2:1}三種寬高比率ratio的框。所以我們在特征金字塔上總共有15個anchor。
RPN訓練時需要有anchor的前背景類標。對anchor進行label的原理和Faster R-CNN里一模一樣,詳情可以去本人博客https://blog.csdn.net/hancoder/article/details/87917174 的RPNlabel部分查看。反正就是與gt的IoU>0.7就是正類label=1,IoU<0.3是負類背景label=0,其余介于0.3和0.7直接的都扔掉不參與訓練label=-1。在faster rcnn中拿256個anchors訓練后得到W×H×9個roi。
此外,每個級level的頭部的參數是共享的,共享的原因是實驗驗證出來的。實驗證明,雖然每級的feature大小不一樣,但是共享與不共享頭部參數的準確率是相似的。這個結果也說明了其實金字塔的每級level都有差不多相似的語義信息,而不是普通網絡那樣語義信息區別很大。
FPN for Fast R-CNN
RPN抽取到特征后,Fast R-CNN用RoIpool抽取出RoI后進行分類。Fast R-CNN is a region-based object detector in which Region-of-Interest(RoI) pooling is used to extract features.Fast R-CNN在單scale特征上有好的表現。為了使用FPN,需要把各個scale的RoI賦給金字塔級level。Fast rcnn中的ROI Pooling層使用region proposal的結果和特征圖作為輸入。經過特征金字塔,我們得到了許多特征圖,作者認為,不同層次的特征圖上包含的物體大小也不同,因此,不同尺度的ROI,使用不同特征層作為ROI pooling層的輸入。大尺度ROI就用后面一些的金字塔層,比如P5;小尺度ROI就用前面一點的特征層,比如P4。
對于原圖上w×h 的RoI,需要選擇一層的feature map來對他RoIpooling,選擇的feature map的層數P_k的選擇依據是
$k=left lfloor k_0+log_2(sqrt{wh}/224) right rfloor?$
224是ImageNet預訓練的大小,k0是基準值,設置為5或4,代表P5層的輸出(原圖大小就用P5層),w和h是ROI區域的長和寬,假設ROI是112 * 112的大小,那么k = k0-1 = 5-1 = 4,意味著該ROI應該使用P4的特征層。k值做取整處理。這意味著如果RoI的尺度變小(比如224的1/2),那么它應該被映射到一個精細的分辨率水平。4、實驗
使用80類的COCO數據集,訓練集80k,驗證集35k+5k(mini),在ImageNet1k上預訓練。使用ResNet-50和Resnet-101模型。
表1 FPN對RPN的影響:關心的是召回率AR
下標sml指的是gt框的大小small,medium,large
- (a,b)只使用conv4或conv5的R-CNN在召回率上提升10%(a,b),尤其在小物體上提升明顯。(使用相同的超參數anchors)
- (d)去掉了top-down,只保留橫向連接 。即去掉了上采樣。相當于論文圖1的c。性能僅與原 RPN 差不多,原因可能是不同層的語義信息差別較大。原因在于不同層之間的語義特征差距較大。還測試了共享/不共享頭部參數的區別,都很差。
- (e)去掉了橫向鏈接。相當于只上采樣。語義多,但位置不準確。
- (f)只用P2特征層,不使用金字塔模型。對應論文圖1的(b)。結果當然不是很好。
表2 FPN對Fast R-CNN的影響:關心的是準確率AP
類似于RPN的實驗,改變FPN的結構,以驗證FPN對Fast R-CNN重要性。
表3FPN對整個Faster R-CNN的影響
表4 對比其他單模型
表5 共享特征
在FPN基礎上,將RPN和Fast R-CNN的特征共享,與原Faster R-CNN一樣,精度得到了小幅提升。
表6 在實例分割上的表現
5、CVPR現場:
海報:https://vision.cornell.edu/se3/wp-content/uploads/2017/07/fpn-poster.pdf
上圖是FPN的海報,Fast R-CNN+FPN與單純的Fast R-CNN沒什么差別。通道數從1024減小到256減少了計算量,訓練和前向運算都快了。
我們利用2個MLP層取代了Conv5,作為我們的頭分類器;
CVPR 現場 QA:
Q1. 不同深度的 feature map 為什么可以經過 upsample 后直接相加?
A:作者解釋說這個原因在于我們做了 end-to-end 的 training,因為不同層的參數不是固定的,不同層同時給監督做 end-to-end training,所以相加訓練出來的東西能夠更有效地融合淺層和深層的信息。
Q2. 為什么 FPN 相比去掉深層特征 upsample(bottom-up pyramid) 對于小物體檢測提升明顯?(RPN 步驟 AR 從 30.5 到 44.9,Fast RCNN 步驟 AP 從 24.9 到 33.9)
A:作者在 poster 里給出了這個問題的答案
對于小物體,一方面我們需要高分辨率的 feature map 更多關注小區域信息,另一方面,如圖中的挎包一樣,需要更全局的信息更準確判斷挎包的存在及位置。
Q3. 如果不考慮時間情況下,image pyramid 是否可能會比 feature pyramid 的性能更高?
A:作者覺得經過精細調整訓練是可能的,但是 image pyramid 主要的問題在于時間和空間占用太大,而 feature pyramid 可以在幾乎不增加額外計算量情況下解決多尺度檢測問題。
后續
- FPN如今已成為Detecton算法的標準組件,不管是one-stage(RetinaNet、DSSD)、two-stage(Faster R-CNN、Mask R-CNN)還是four-stage(Cascade R-CNN)都可用;
- 何愷明大神的論文Mask R-CNN 獲得ICCV最佳論文,其中也應用了FPN網絡
- R-FCN系由于其自身設計的緣故,無法使用FPN;
- 后來者PAN在FPN的基礎上再加了一個bottom-up方向的增強,使得頂層feature map也可以享受到底層帶來的豐富的位置信息,從而把大物體的檢測效果也提上去了:
6、代碼實現
# 在此貼出Pi卷積層的代碼,幫助理解 # 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) # C5卷積一下就當做P5 P4 = KL.Add(name="fpn_p4add")([ # P4 開始有了對應元素add操作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)])# Attach 3x3 conv to all P layers to get the final feature maps. 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是P5的極大值池化 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]參考:
https://blog.csdn.net/jningwei/article/details/80661954
https://vision.cornell.edu/se3/wp-content/uploads/2017/07/fpn-poster.pdf FPN的海報
機器之心
https://blog.csdn.net/weixin_40683960/article/details/79055537
總結
以上是生活随笔為你收集整理的金字塔c_FPN特征金字塔网络解读的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于Aws SNS的使用 小结
- 下一篇: 解决Pytohn安装第三方库出现read