mmdetection最小復(fù)刻版(六):FCOS深入可視化分析
AI編輯:深度眸
0 概要
論文名稱:FCOS: A simple and strong anchor-free object detector
論文地址:https://arxiv.org/pdf/2006.09214v3.pdf
論文名稱:FCOS: Fully Convolutional One-Stage Object Detection
論文地址:https://arxiv.org/pdf/1904.01355v1.pdf
官方代碼地址:https://github.com/aim-uofa/AdelaiDet/
? ? FCOS是目前最經(jīng)典優(yōu)雅的一階段anchor-free目標(biāo)檢測(cè)算法,其模型結(jié)構(gòu)主流、設(shè)計(jì)思路清晰、超參極少和不錯(cuò)的性能使其成為后續(xù)各個(gè)改進(jìn)算法的baseline,和retinanet一樣影響深遠(yuǎn),故非常有必要對(duì)其進(jìn)行深入分析。
? ? 一個(gè)大家都知道的問題,anchor-base的缺點(diǎn)是:超參太多,特別是anchor的設(shè)置對(duì)結(jié)果影響很大,不同項(xiàng)目這些超參都需要根據(jù)經(jīng)驗(yàn)來(lái)確定,難度較大。?而anchor-free做法雖然還是有超參,但是至少去掉了anchor設(shè)置這個(gè)最大難題。fcos算法可以認(rèn)為是point-base類算法也就是特征圖上面每一個(gè)點(diǎn)都進(jìn)行分類和回歸預(yù)測(cè),簡(jiǎn)單來(lái)說(shuō)就是anchor個(gè)數(shù)為1的且為正方形anchor-base類算法。
? ? 在目前看來(lái),任何一個(gè)目標(biāo)檢測(cè)算法的核心組件都包括backbone+neck+多尺度head+正負(fù)樣本定義+正負(fù)樣本平衡采樣+loss設(shè)計(jì),除了正負(fù)樣本平衡采樣不一定有外,其他每個(gè)環(huán)節(jié)都是目前研究重點(diǎn),到處存在不平衡問題,而本文重點(diǎn)是在正負(fù)樣本定義上面做文章。
貼一下github:
https://github.com/hhaAndroid/mmdetection-mini
歡迎star
1 fcos和retinanet算法對(duì)比分析
? ? ?FCOS結(jié)構(gòu)和retinanet幾乎相同,但是有細(xì)微差別,下面會(huì)細(xì)說(shuō)。

? ? 不清楚retinanet結(jié)構(gòu)的請(qǐng)看:mmdetection最小復(fù)刻版(二):RetinaNet和YoloV3分析
? ? retinanet的結(jié)構(gòu)大概可以總結(jié)為:
resnet輸出是4個(gè)特征圖,按照特征圖從大到小排列,分別是c2 c3 c4 c5,stride=4,8,16,32。Retinanet考慮計(jì)算量?jī)H僅用了c3 c4 c5
先對(duì)這三層進(jìn)行1x1改變通道,全部輸出256個(gè)通道;然后經(jīng)過從高層到底層的最近鄰上采樣add操作進(jìn)行特征融合,最后對(duì)每個(gè)層進(jìn)行3x3的卷積,得到p3,p4,p5特征圖
還需要構(gòu)建兩個(gè)額外的輸出層stride=64,128,首先對(duì)c5進(jìn)行3x3卷積且stride=2進(jìn)行下采樣得到P6,然后對(duì)P6進(jìn)行同樣的3x3卷積且stride=2,得到P7
下面介紹fcos和retinanet算法的區(qū)別
1.1 resnet的style模式區(qū)別

左邊是fcos配置,右邊是retinanet配置。
(1) resnet骨架區(qū)別
? ? 在resnet骨架中,style='caffe'參數(shù)和style='pytorch'的差別就在Bottleneck模塊,該模塊的結(jié)構(gòu)如下:

主干網(wǎng)絡(luò)是標(biāo)準(zhǔn)的1x1-3x3-1x1結(jié)構(gòu),考慮stride=2進(jìn)行下采樣的場(chǎng)景,對(duì)于caffe模式來(lái)說(shuō),stride參數(shù)放置在第一個(gè)1x1卷積上,對(duì)于pytorch模式來(lái)說(shuō),stride放在第二個(gè)3x3卷積上:
if self.style == 'pytorch':self.conv1_stride = 1self.conv2_stride = strideelse:self.conv1_stride = strideself.conv2_stride = 1
唯一區(qū)別就是這個(gè),至于為啥存在caffe模式,是因?yàn)樵缙趍mdetection采用了detectron權(quán)重(不想重新訓(xùn)練imagenet),其早期采用了caffe2來(lái)構(gòu)建模型,后續(xù)detectron2才切換到pytorch中,屬于歷史遺留問題。
(2) 骨架訓(xùn)練策略區(qū)別
? ? 注意看上面的對(duì)比配置,可以發(fā)現(xiàn)除了上面說(shuō)的不同外,在caffe模式下,requires_grad=False,也就是說(shuō)resnet的所有BN層參數(shù)都不更新并且全局均值和方差也不再改變,而在pytorch模式下,除了frozen_stages的BN參數(shù)不更新外,其余層BN參數(shù)還是會(huì)更新的。我不清楚為啥要特意區(qū)別。
? ? 總的來(lái)說(shuō),在caffe模式下訓(xùn)練的內(nèi)存肯定會(huì)少一些,但是效果究竟誰(shuí)的更好,看了下對(duì)比結(jié)果發(fā)現(xiàn)差不多。
1.2 FPN結(jié)構(gòu)區(qū)別

和retinanet相比,fcos的FPN層抽取層也是不一樣的,需要注意。?
? ? ?retinanet在得到p6,p7的時(shí)候是采用c5層特征進(jìn)行maxpool得到的(對(duì)應(yīng)參數(shù)是add_extra_convs='on_input',),而fcos是從p5層抽取得到的(對(duì)應(yīng)參數(shù)是extra_convs_on_inputs=False),而且其還有relu_before_extra_convs=True參數(shù),也就是p6和p7進(jìn)行卷積前,還會(huì)經(jīng)過relu操作,retinanet的FPN沒有這個(gè)算子(C5不需要是因?yàn)閞esnet輸出最后就是relu)。從實(shí)驗(yàn)結(jié)果來(lái)看,從p5抽取的效果是好于c5的,baseline的mAP從38.5提高到38.9。
1.3 數(shù)據(jù)歸一化區(qū)別
? ? 當(dāng)切換style='caffe'時(shí)候,需要注意圖片均值和方差也改變了:
# pytorchmean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True# caffemean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False
1.4 head模塊區(qū)別
? ? 和retinanet相比,fcos的head結(jié)構(gòu)多了一個(gè)centerness分支,其余也是比較重量級(jí)的兩條不共享參數(shù)的4層卷積操作,然后得到分類和回歸兩條分支。
2 fcos算法深入分析
2.1 fcos輸出格式

fcos是point-base類算法,對(duì)于特征圖上面任何一點(diǎn)都回歸其距離bbox的4條邊距離

? ? 假設(shè)x是特征圖上任意點(diǎn)坐標(biāo),x0y0x1y1是某個(gè)gt bbox在原圖上面的坐標(biāo),那么4條邊的邊界(都是正數(shù))其實(shí)很好算,公式如上所示。需要注意的是由于大小bbox且數(shù)值問題,一般都會(huì)對(duì)值進(jìn)行變換,也就是除以s,主要目的是壓縮預(yù)測(cè)范圍,容易平衡分類和回歸Loss權(quán)重。
? ? 如果某個(gè)特征圖上面點(diǎn)處于多個(gè)bbox重疊位置,則該point負(fù)責(zé)小bbox的預(yù)測(cè)。
2.2 正負(fù)樣本定義
? ? 一個(gè)目標(biāo)檢測(cè)算法性能的優(yōu)異性,最大影響因素就是如何定義正負(fù)樣本。而fcos的定義方式非常mask sense,通俗易懂。主要分為兩步:
(1) 設(shè)置regress_ranges=((-1, 64), (64, 128), (128, 256), (256, 512),(512, INF),用于將不同大小的bbox分配到不同的FPN層進(jìn)行預(yù)測(cè)即距離4條邊的最大值在給定范圍內(nèi)
(2) 設(shè)置center_sampling_ratio=1.5,用于確定對(duì)于任意一個(gè)輸出層距離bbox中心多遠(yuǎn)的區(qū)域?qū)儆谡龢颖?,該值越大,擴(kuò)張比例越大,正樣本區(qū)域越大
為了說(shuō)明其重要性,作者還做了很多分析實(shí)驗(yàn)。
(1) 為啥需要第一步?
? ? regress_ranges的意思是對(duì)于不同層僅僅負(fù)責(zé)指定范圍大小的gt bbox,例如最淺層輸出,其范圍是0-64,表示對(duì)于該特征圖上面任何一點(diǎn),假設(shè)其負(fù)責(zé)的gt bbox的label值是left、top、right和bottom,那么這4個(gè)值里面取max必須在0-64范圍內(nèi),否則就算背景樣本。
? ? 為啥需要限制層回歸范圍?目的應(yīng)該有以下幾點(diǎn):
1. 在SNIP論文中說(shuō)到,CNN對(duì)尺度是非常敏感的,一個(gè)層負(fù)責(zé)處理各種尺度,難度比較大,采用FPN來(lái)限制回歸范圍可以減少訓(xùn)練難度
2. 提高best possible recall
? ? 通常我們知道anchor設(shè)置的越密集,理論上召回率越高,現(xiàn)在fcos是anchor-free,那么需要考慮理論上的最好召回率是多少,如果理論值都比較低,那肯定性能不行。best possible recall定義為訓(xùn)練過程中所有GT的最大召回率,如果訓(xùn)練過程中一個(gè)GT被某個(gè)anchor或者location匹配上那么就認(rèn)為被召回了。

? ? ?low-quality matches意思是retinanet配置中的min_pos_iou參數(shù),默認(rèn)是0。在不使用low-quality matches時(shí)候,對(duì)于某些gt,如果其和anchor的最大iou沒有超過正樣本閾值,那么就是背景樣本,一開啟low-quality matches則可能能夠撈回來(lái),開啟這個(gè)操作可以顯著提高BPR,從表中也可以看出,從88.16變成99.32。至于在ALL模式下為啥不是1,作者分析原因是有些bbox特別小并且挨著,經(jīng)過下采樣后在同一個(gè)位置,導(dǎo)致出現(xiàn)相互覆蓋。
? ? 對(duì)于FCOS,即使在不開啟FPN時(shí)候,其BPR也很高,因?yàn)槠鋌box中心范圍內(nèi)都算正樣本,BPR肯定比較高,在開啟FPN后和retinanet相比差別不大,對(duì)最終性能沒有影響。為了強(qiáng)調(diào)FPN層的作用性,作者還對(duì)模糊樣本數(shù)進(jìn)行分析:

? ? 模糊樣本就是某個(gè)特征圖位置處于多個(gè)gt bbox重疊位置,也就是圖表中的大于1個(gè)數(shù)??梢园l(fā)現(xiàn)在開啟FPN后,模糊樣本明顯減少,因?yàn)椴煌笮〉膅t bbox被強(qiáng)制分配到不同層預(yù)測(cè)了,當(dāng)結(jié)合中心采樣策略后可以進(jìn)一步提高。
(2) 為啥需要第二步?
中心采樣的作用有兩個(gè)
1. 減少模糊樣本數(shù)目
2. 減少標(biāo)注噪聲干擾

? ? bbox標(biāo)注通常都有噪聲或者會(huì)框住很多無(wú)關(guān)區(qū)域,如果這些無(wú)關(guān)區(qū)域也負(fù)責(zé)回歸則比較奇怪,這其實(shí)是目前非常常用的處理策略,在文本檢測(cè)領(lǐng)域廣泛應(yīng)用。

? ? (a)是早期做法也就是對(duì)于本文不采用中心采樣策略的做法;(b)是本文做法;(c)是 centernet做法;(d)是centernet改進(jìn)論文做法。從這里可以看出,(d)的做法應(yīng)該比f(wàn)cos更加mask sense,可解釋性更強(qiáng)。
總的來(lái)說(shuō),作者認(rèn)為FCOS的功臣可以歸功于FPN層的多尺度預(yù)測(cè)和中心采樣策略。
(3) 核心代碼分析
? ? 為了方便理解中心采樣策略代碼,我對(duì)代碼進(jìn)行了分解,具體在tools/fcos_analyze/center_samper_demo.py。其核心代碼邏輯是:
(1) 利用meshgrid函數(shù)獲取特征圖上面每個(gè)點(diǎn)的2d坐標(biāo)
(2) 擴(kuò)展維度,使得所有參數(shù)計(jì)算的tensor維度相同,方便后續(xù)計(jì)算
(3) 如果不采用中心采樣策略,則直接對(duì)特征點(diǎn)上面每個(gè)點(diǎn)計(jì)算和所有g(shù)t bbox的left/top/right/bottom值。然后取4個(gè)值中的最小值,如果小于0,則該point至少有一條邊不再bbox內(nèi)部,屬于背景point樣本,否則就是正樣本
(4) 如果采用中心采用策略,則基于gt bbox中心點(diǎn)進(jìn)行擴(kuò)展出正方形,擴(kuò)展范圍是center_sample_radius×stride,正方形區(qū)域就當(dāng)做新的gt bbox,然后和(3)步驟一樣計(jì)算正樣本即可。還需要注意一個(gè)細(xì)節(jié):如果擴(kuò)展比例過大,導(dǎo)致中心采樣區(qū)域超過了gt bbox本身范圍了,此時(shí)需要截?cái)嗖僮?/p>
? ? 以上操作就可以確定哪些區(qū)域是正樣本了,我仿真的結(jié)果如下所示:

藍(lán)色是gt bbox,白色區(qū)域是正樣本區(qū)域。從這里也可以看出,其實(shí)FCOS中心采樣策略還有改進(jìn)空間,因?yàn)樗恼龢颖緟^(qū)域沒有考慮gt bbo寬高信息,對(duì)于圖片中包含人這種長(zhǎng)寬比比較大的場(chǎng)景,這種做法其實(shí)不好。需要注意的是為了可視化代碼簡(jiǎn)單,我是直接對(duì)特征圖mask進(jìn)行上采樣得到的,實(shí)際上在原圖上對(duì)應(yīng)的白色區(qū)域是一個(gè)點(diǎn),而不是一個(gè)白塊。
(4) 理解糾正
? ? 我們?cè)賮?lái)看下上面的一句話:
(1) 設(shè)置regress_ranges=((-1, 64), (64, 128), (128, 256), (256, 512),(512, INF),用于將不同大小的bbox分配到不同的FPN層進(jìn)行預(yù)測(cè)
(2) 設(shè)置center_sampling_ratio=1.5,用于確定對(duì)于任意一個(gè)輸出層距離bbox中心多遠(yuǎn)的區(qū)域?qū)儆谡龢颖?,該值越大,擴(kuò)張比例越大,正樣本區(qū)域越大
看起來(lái)好像沒問題,后來(lái)我通過正樣本可視化分析發(fā)現(xiàn)我上面說(shuō)法是錯(cuò)誤的。正確的應(yīng)該是:
(1) 對(duì)于任何一個(gè)gt bbox,首先映射到每一個(gè)輸出層,利用center_sampling_ratio值計(jì)算出該gt bbox在每一層的正樣本區(qū)域以及對(duì)應(yīng)的left/top/right/bottom的target
(2) 對(duì)于每個(gè)輸出層的正樣本區(qū)域,遍歷每個(gè)point位置,計(jì)算其max(left/top/right/bottom的target)值是否在指定范圍內(nèi),不再范圍內(nèi)的認(rèn)為是背景
上面兩個(gè)寫法的順序變了,結(jié)果也差別很大,最大區(qū)別是第二種寫法可以使得某一個(gè)gt bbox在多個(gè)預(yù)測(cè)層都是正樣本,而第一種做法先把gt bbox映射到預(yù)測(cè)層后面才進(jìn)行中心采樣,第二種做法相比第一種做法可以增加很多正樣本區(qū)域。很明顯,第二種才是正確的。
? ? 通過正樣本可視化分析可以發(fā)現(xiàn):

紅色點(diǎn)表示正樣本point,其中0-4表示stride=[8,16,32,64,128]的輸出特征圖,代表從小到大物體的預(yù)測(cè)。

可以看出,其是完全基于回歸距離來(lái)定義正負(fù)樣本位置的,但是從語(yǔ)義角度來(lái)看,這種設(shè)計(jì)不夠make sense,因?yàn)榧t色點(diǎn)不是對(duì)稱分布,特別是上標(biāo)為2的小象內(nèi)部不算正樣本,比較奇怪。從語(yǔ)義角度理解不合理,但是從回歸數(shù)值范圍理解是很合理的。
? ? 正樣本可視化代碼我已經(jīng)新增到mmdetection-mini中了,只需要對(duì)應(yīng)train_cfg里面的debug設(shè)置為True即可可視化。
2.3 loss計(jì)算
? ? 在確定了每一層預(yù)測(cè)層的正負(fù)樣本后就可以計(jì)算loss了,對(duì)于分類分支(class_num,h',w'),其采用的是FocalLoss,參數(shù)和retinanet一樣。對(duì)于回歸分支(4,h',w'),其采用的是GIou loss,也是常規(guī)操作,回歸分支僅僅對(duì)正樣本進(jìn)行監(jiān)督。
? ? 在這種設(shè)置情況下,作者發(fā)現(xiàn)訓(xùn)推理時(shí)候會(huì)出現(xiàn)一些奇怪的bbox,原因是對(duì)于回歸分支,正樣本區(qū)域的權(quán)重是一樣的,同等對(duì)待,導(dǎo)致那些雖然是正樣本但是離gt bbox中心比較遠(yuǎn)的點(diǎn)對(duì)最終loss產(chǎn)生了比較大的影響,其實(shí)這個(gè)現(xiàn)象很容易想到,但是解決辦法有多種。

現(xiàn)象應(yīng)該和(b)圖一致,在靠近物體中心的四周會(huì)依然會(huì)產(chǎn)生大量高分值的輸出。
? ? 作者解決辦法是引入額外的centerness分類分支(1,h',w')來(lái)抑制,該分支和bbox回歸分支共享權(quán)重,僅僅在bbox head最后并行一個(gè)centerness分支,其target的設(shè)置是離gt bbox中心點(diǎn)越近,該值越大,范圍是0-1。雖然這是一個(gè)回歸問題,但是作者采用的依然是ce loss。很多人反映該分支訓(xùn)練時(shí)候loss下降的特別慢,其實(shí)這是非常正常的,這其實(shí)是整圖回歸問題,在每個(gè)點(diǎn)處都要回歸出對(duì)應(yīng)值其實(shí)是一個(gè)密集預(yù)測(cè)問題,難度是很大的,loss下降慢非常正常。
? ? 需要特別注意的是centerness分支也是僅僅對(duì)正樣本point進(jìn)行回歸。

? ? 通過上圖可以看出,在引入centerness分支后,將該預(yù)測(cè)值和分類分支結(jié)果相乘得到橫坐標(biāo)分支圖,縱坐標(biāo)是bbox和gt bbox的iou,可以明顯發(fā)現(xiàn)兩者的一致性得到了提高,對(duì)最終性能有很大影響。至于這個(gè)圖自己如何繪制,有個(gè)比較簡(jiǎn)單的辦法:
(1) 利用框架進(jìn)行測(cè)試,保存coco驗(yàn)證集的預(yù)測(cè)json格式
(2) 在寫一份離線代碼讀取該預(yù)測(cè)json和標(biāo)注的json,遍歷每張圖片的預(yù)測(cè)bbox和gt bbox
(3) 對(duì)于每張圖片的結(jié)果,遍歷預(yù)測(cè)bbox,然后和所有g(shù)t bbox計(jì)算最大iou,該值就是縱坐標(biāo),橫坐標(biāo)就是預(yù)測(cè)分值(cls*centerness)
(4) 所有數(shù)據(jù)都處理完成就可以上述圖表
由于代碼比較簡(jiǎn)單,我這里就不寫了。
對(duì)于任何一個(gè)點(diǎn),其centerness的target值通過如下公式計(jì)算:

tools/fcos_analyze/center_samper_demo.py仿真效果如下所示:

越靠近中心,min(l,r)和max(l,r)越接近1,也就是越大。
2.4 附加內(nèi)容
? ? fcos代碼在第一版和最終版上面修改了很多訓(xùn)練技巧,對(duì)最終mAP有比較大的影響,主要是:
(1) centerness 分支的位置
早先是和分類分支放一起,后來(lái)和回歸分支放一起
(2) 中心采樣策略
早先版本是沒有中心采樣策略的
(3) bbox預(yù)測(cè)范圍
早先是采用exp進(jìn)行映射,后來(lái)改成了對(duì)預(yù)測(cè)值進(jìn)行relu,然后利用scale因子縮放
(4) bbox loss權(quán)重
早先是所有正樣本都是同樣權(quán)重,后來(lái)將樣本點(diǎn)對(duì)應(yīng)的centerness target作為權(quán)重,離GT中心越近,權(quán)重越大
(5) bbox Loss選擇
早先采用的是iou,后面有更優(yōu)秀的giou,或許還可以嘗試ciou
(6) nms閾值選取
早先版本采用的是0.5,后面改為0.6
這些trick,將整個(gè)coco數(shù)據(jù)集mAP從38.6提高到42.5,提升特別大,新版本的論文中有非常詳細(xì)的對(duì)比實(shí)驗(yàn)報(bào)告,有興趣的可以自行閱讀。
再次貼一下github:
https://github.com/hhaAndroid/mmdetection-mini
歡迎star
推薦閱讀
mmdetection最小復(fù)刻版(四):獨(dú)家yolo轉(zhuǎn)化內(nèi)幕
mmdetection最小復(fù)刻版(三):數(shù)據(jù)分析神兵利器
mmdetection最小復(fù)刻版(二):RetinaNet和YoloV3分析
機(jī)器學(xué)習(xí)算法工程師
? ??? ? ? ? ? ? ? ? ? ? ? ??????????????????一個(gè)用心的公眾號(hào)
?

