【GiantPandCV導語】本文将介紹BBuf、小武和筆者一起在過年期間完成的一個目标檢測項目,将描述我們模型改進的思路、實驗思路、結果彙總和經驗性總結。聲明:這篇文章經過了三人同意,并且所有創新點也将被公布。此外,由于經驗上的不足,可能整個實驗思路不夠成熟,比不上CV大組的嚴謹性和完備性,如有問題還煩請指教。
紅外小目标檢測的目标比較小,目标極其容易和其他物體混淆,有一定的挑戰性。
另外,這本質上也是一個小目标領域的問題,很多适用于小目标的創新點也會被借鑒進來。
此外,該資料集還有一個特點,就是分背景,雖然同樣是檢測紅外小目标,差別是背景的不同,我們對資料集進行了統計以及通過人工翻看的方式總結了其特點,如下表所示:
背景類别
數量
特點
資料難度
測試mAP+F1
建議
trees
581
背景幹淨,目标明顯,數量較多
低
0.99+0.97
無
cloudless_sky
1320
背景幹淨,目标明顯,數量多
0.98+0.99
architecture
506
背景變化較大,目标形态變化較大,數量較多
一般
0.92+0.96
focal loss
continuous_cloud_sky
878
背景幹淨,目标形态變化不大,但個别目标容易會發生和背景中的雲混淆
0.93+0.95
complex_cloud
561
目标形态基本無變化,但背景對目标的定位影響巨大
較難
0.85+0.89
sea
17
背景幹淨,目标明顯,數量極少
0.87+0.88
生成高品質新樣本,可以讓其轉為簡單樣本(Mixup)
sea_sky
45
背景變化較大,且單張圖像中目标個數差異變化大,有密集的難點,且數量少
困難
0.68+0.77
paste政策
通過以上結果,可以看出背景的不同對結果影響還是蠻大的,最後一列也給出了針對性的建議,打算後續實施。
首先,我們使用的是U版的yolov3: <code>https://github.com/ultralytics/yolov3</code>,那時候YOLOv4/5、PPYOLO還都沒出,當時出了一個《從零開始學習YOLOv3》就是做項目的時候寫的電子書,其中的在YOLOv3中添加注意力機制那篇很受歡迎(可以水很多文章出來,畢業要緊:)
我們項目的代碼以及修改情況可以檢視:<code>https://github.com/GiantPandaCV/yolov3-point</code>
将資料集轉成VOC格式的資料集,之前文章有詳細講述如何轉化為标準的VOC資料集,以及如何将VOC格式資料集轉化為U版的講解。當時接觸到幾個項目,都需要用YOLOv3,由于每次都需要轉化,大概分别調用4、5個腳本吧,感覺很累,是以當時花了一段時間建構了一個一鍵從VOC轉U版YOLOv3格式的腳本庫: <code>https://github.com/pprp/voc2007_for_yolo_torch</code>。
到此時為止,我們項目就已經可以運作了,然後就是很多細節調整了。
紅外小目标的Anchor和COCO等資料集的Anchor是差距很大的,為了更好更快速的收斂,采用了BBuf總結的一套專門計算Anchor的腳本:
通過浏覽腳本就可以知道,Anchor和圖檔的輸入分辨率有沒有關系 這個問題了,當時這個問題有很多群友都在問。通過kmeans函數得到的結果實際上是歸一化到0-1之間的,然後Anchor的輸出是在此基礎上乘以輸入分辨率的大小。是以個人認為Anchor和圖檔的輸入分辨率是有關系的。
此外,U版也提供了Anchor計算,如下:
這個和超參數搜尋那篇采用的方法類似,也是一種類似遺傳算法的方法,通過一代一代的篩選找到合适的Anchor。以上兩種方法筆者并沒有對比,有興趣可以試試這兩種方法,對比看看。
Anchor這方面設定了三個不同的數量進行聚類:
3 anchor:
6 anchor:
9 anchor:
由于資料集是單類的,并且相對VOC等資料集來看,比較單一,是以不打算使用Darknet53這樣的深度神經網絡,采用的Baseline是YOLOv3-tiny模型,在使用原始Anchor的情況下,該模型可以在驗證集上達到[email protected]=93.2%,在測試集上達到[email protected]=86.9%的結果。
那接下來換Anchor,用上一節得到的新Anchor替換掉原來的Anchor,該改掉的模型為yolov3-tiny-6a:
Epoch
Model
P
R
F1
dataset
baseline
yolov3-tiny原版
0.982
0.939
0.932
0.96
valid
0.873
0.869
0.914
test
6a
yolov3-tiny-6a
0.973
0.98
0.984
0.977
0.936
0.925
0.915
0.931
可以看到幾乎所有的名額都提升了,這說明Anchor先驗的引入是很有必要的。
上邊已經分析過了,背景對目标檢測的結果還是有一定影響的,是以我們先後使用了幾種方法進行改進。
第一個:過采樣
通過統計不同背景的圖像的數量,比如以sea為背景的圖像隻有17張,而最多的cloudless_sky為背景的圖像有1300+張,這就産生了嚴重的不平衡性。顯然cloudless_sky為背景的很簡單,sea為背景的難度更大,這樣由于資料不平衡的原因,訓練得到的模型很可能也會在cloudless_sky這類圖檔上效果很好,在其他背景下效果一般。
是以首先要采用過采樣的方法,這裡的過采樣可能和别的地方的不太一樣,這裡指的是将某些背景數量小的圖檔通過複制的方式擴充。
baseline(os)
0.985
0.971
0.978
0.871
0.86
0.902
😦 可惜實驗結果不支援想法,一起分析一下。ps:os代表over sample
然後進行分背景測試,結果如下:
均衡後的分背景測試
data
num
model
mAP
0.924
0.996
0.981
0.959
495
0.927
0.771
0.85
510
0.923
0.935
0.893
0.929
0.957
0.95
0.933
0.953
0.943
0.833
0.831
0.885
0.993
0.987
0.952
0.941
0.955
從分背景結果來看,确實sea訓練資料很少的結果很好,mAP提高了2個點,但是complex_cloud等mAP有所下降。總結一下就是對于訓練集中資料很少的背景類mAP有提升,但是其他本身數量就很多的背景mAP略微下降或者保持。
第二個:在圖檔中任意位置複制小目标
修改後的版本位址:<code>https://github.com/pprp/SimpleCVReproduction/tree/master/SmallObjectAugmentation</code>
具體實作思路就是,先将所有小目标摳出來備用。然後在圖像上複制這些小目标,要求兩兩之間重合率不能達到一個門檻值并且複制的位置不能超出圖像邊界。
效果如下:(這個是示意圖,比較誇張,複制的個數比較多

這種做法來自當時比較新的論文《Augmentation for small object detection》,文中最好的結果是複制了1-2次。實際我們項目中也試過1次、2次、3次到多次的結果,都不盡如人意,結果太差就沒有記錄下來。。(話說論文中展示的效果最佳組合是原圖+增強後的圖,并且最好的結果也就提高了1個百分點)╮(╯﹏╰)╭
修改Backbone經常被群友問到這樣一件事,修改骨幹網絡以後無法加載預訓練權重了,怎麼辦?
有以下幾個辦法:
幹脆不加載,從頭訓練,簡單問題(比如紅外小目标)從頭收斂效果也不次于有預訓練權重的。
不想改代碼的話,可以選擇修改Backbone之後、YOLO Head之前的部分(比如SPP的位置屬于這種情況)
能力比較強的,可以改一下模型加載部分代碼,跳過你新加入的子產品,這樣也能加載(筆者沒試過,别找我)。
修改Backbone我們也從幾個方向入的手,分為注意力子產品、即插即用子產品、修改FPN、修改激活函數、用成熟的網絡替換backbone和SPP系列。
1. 注意力子產品
這個項目中使用的注意力子產品,大部分都在公号上寫過代碼解析,感興趣的可以翻看一下。筆者前一段時間公布了一個電子書《卷積神經網絡中的即插即用子產品》也是因為這個項目中總結了很多注意力子產品,是以開始整理得到的結果。具體子產品還在繼續更新:<code>https://github.com/pprp/SimpleCVReproduction</code>
當時實驗的子產品有:SE、CBAM等,由于當時Baseline有點高,效果并不十分理想。(注意力子產品插進來不可能按照預期一下就提高多少百分點,需要多調參才有可能超過原來的百分點)根據群友回報,SE直接插入成功率比較高。筆者在一個目标檢測比賽中見到有一個大佬是在YOLOv3的FPN的三個分支上各加了一個CBAM,最終超過Cascade R-CNN等模型奪得冠軍。
2. 即插即用子產品
注意力子產品也屬于即插即用子產品,這部分就說的是非注意力子產品的部分如 FFM、ASPP、PPM、Dilated Conv、SPP、FRB、CorNerPool、DwConv、ACNet等,效果還可以,但是沒有超過目前最好的結果。
3. 修改FPN
FPN這方面花了老久時間,參考了好多版本才搞出了一個dt-6a-bifpn(dt代表dim target紅外目标;6a代表6個anchor),令人失望的是,這個BiFPN效果并不好,測試集上效果更差了。可能是因為實作的cfg有問題,歡迎回報。
大家都知道通過改cfg的方式改網絡結構是一件很痛苦的事情,推薦一個可視化工具:
除此以外,為了友善查找行數,筆者寫了一個簡單腳本用于查找行數(獻醜了
我們也嘗試了隻用一個、兩個和三個YOLO Head的情況,結果是3>2>1,但是用3個和2個效果幾乎一樣,差異不大小數點後3位的差異,是以還是選用兩個YOLO Head。
4. 修改激活函數
YOLO預設使用的激活函數是leaky relu,激活函數方面使用了mish。效果并沒有提升,是以無疾而終了。
5. 用成熟的網絡替換backbone
這裡使用了ResNet10(第三方實作)、DenseNet、BBuf修改的DenseNet、ENet、VOVNet(自己改的)、csresnext50-panet(當時AB版darknet提供的)、PRN(作用不大)等網絡結構。
目前最強的網絡是dense-v3-tiny-spp,也就是BBuf修改的Backbone+原汁原味的SPP組合的結構完虐了其他模型,在測試集上達到了[email protected]=0.932、F1=0.951的結果。
6. SPP系列
這個得好好說說,我們三人調研了好多論文、參考了好多trick,大部分都無效,其中從來不會讓人失望的子產品就是SPP。我們對SPP進行了深入研究,在《卷積神經網絡中的各種池化操作》中提到過。
SPP是在SPPNet中提出的,SPPNet提出比較早,在RCNN之後提出的,用于解決重複卷積計算和固定輸出的兩個問題,具體方法如下圖所示:
在feature map上通過selective search獲得視窗,然後将這些區域輸入到CNN中,然後進行分類。
實際上SPP就是多個空間池化的組合,對不同輸出尺度采用不同的劃窗大小和步長以確定輸出尺度相同,同時能夠融合金字塔提取出的多種尺度特征,能夠提取更豐富的語義資訊。常用于多尺度訓練和目标檢測中的RPN網絡。
在YOLOv3中有一個網絡結構叫yolov3-spp.cfg, 這個網絡往往能達到比yolov3.cfg本身更高的準确率,具體cfg如下:
這裡的SPP相當于是原來的SPPNet的變體,通過使用多個kernel size的maxpool,最終将所有feature map進行concate,得到新的特征組合。
再來看一下官方提供的yolov3和yolov3-spp在COCO資料集上的對比:
可以看到,在幾乎不增加FLOPS的情況下,YOLOv3-SPP要比YOLOv3-608mAP高接近3個百分點。
分析一下SPP有效的原因:
從感受野角度來講,之前計算感受野的時候可以明顯發現,maxpool的操作對感受野的影響非常大,其中主要取決于kernel size大小。在SPP中,使用了kernel size非常大的maxpool會極大提高模型的感受野,筆者沒有詳細計算過darknet53這個backbone的感受野,在COCO上有效很可能是因為backbone的感受野還不夠大。
第二個角度是從Attention的角度考慮,這一點啟發自CSDN@小楞,他在文章中這樣講:
出現檢測效果提升的原因:通過spp子產品實作局部特征和全局特征(是以空間金字塔池化結構的最大的池化核要盡可能的接近等于需要池化的featherMap的大小)的featherMap級别的融合,豐富最終特征圖的表達能力,進而提高MAP。
Attention機制很多都是為了解決遠距離依賴問題,通過使用kernel size接近特征圖的size可以以比較小的計算代價解決這個問題。另外就是如果使用了SPP子產品,就沒有必要在SPP後繼續使用其他空間注意力子產品比如SK block,因為他們作用相似,可能會有一定備援。
在本實驗中,确實也得到了一個很重要的結論,那就是:
SPP是有效的,其中size的設定應該接近這一層的feature map的大小
口說無憑,看一下實驗結果:
SPP系列實驗
dt-6a-spp
0.99
0.983
0.948
0.951
直連+5x5
dt-6a-spp-5
0.93
直連+9x9
dt-6a-spp-9
0.904
直連+13x13
dt-6a-spp-13
0.995
0.989
直連+5x5+9x9
dt-6a-spp-5-9
0.988
0.937
0.91
直連+5x5+13x13
dt-6a-spp-5-13
0.938
直連+9x9+13x13
dt-6a-spp-9-13
0.934
0.907
目前的feature map大小就是13x13,實驗結果表示,直接使用13x13的效果和SPP的幾乎一樣,運算量還減少了。
loss方面嘗試了focal loss,但是經過調整alpha和beta兩個參數,不管用預設的還是自己慢慢調參,網絡都無法收斂,是以當時給作者提了一個issue: <code>https://github.com/ultralytics/yolov3/issues/811</code>
glenn-jocher說效果不好就别用:(
BBuf也研究了好長時間,發現focal loss在Darknet中可以用,但是效果也一般。最終focal loss也是無疾而終。此外還試着調整了ignore thresh,來配合focal loss,實驗結果如下(在AB版Darknet下完成實驗):
state
ignore=0.7
dt-6a-spp-fl
0.97
0.9755
0.9294
0.94
ignore=0.3
0.9874
0.89
0.92
0.9103
0.90
在這個實驗過程中,和BBuf讨論有了很多啟發,也進行了總結,在這裡公開出來,(可能部分結論不夠嚴謹,沒有經過嚴格對比實驗,感興趣的話可以做一下對比實驗)。
SPP層是有效的,Size設定接近feature map的時候效果更好。
YOLOv3、YOLOv3-SPP、YOLOv3-tiny三者在檢測同一個物體的情況下,YOLOv3-tiny給的該物體的置信度相比其他兩個模型低。(其實也可以形象化了解,YOLOv3-tiny的腦容量比較小,是以唯唯諾諾不敢确定)
個人感覺Concate的方法要比Add的方法更柔和,對小目标效果更好。本實驗結果上是DenseNet作為Backbone的時候效果是最佳的。
多尺度訓練問題,這個文中沒提。多尺度訓練對于尺度分布比較廣泛的問題效果明顯,比如VOC這類資料集。但是對于尺度單一的資料集反而有反作用,比如紅外小目标資料集目标尺度比較統一,都很小。
Anchor對模型影響比較大,Anchor先驗不合理會導緻更多的失配,進而降低Recall。
當時跟群友讨論的時候就提到一個想法,對于小目标來說,淺層的資訊更加有用,那麼進行FPN的時候,不應該單純将兩者進行Add或者Concate,而是應該以一定的比例完成,比如對于小目标來說,引入更多的淺層資訊,讓淺層網絡權重增大;大目标則相反。後邊通過閱讀發現,這個想法被ASFF實作了,而且想法比較完善。
PyTorch中的Upsample層是不可複現的。
有卡可以嘗試一下超參數進化方法。
PS: 以上内容不保證結論完全正确,隻是經驗性總結,歡迎入群讨論交流。
感謝BBuf和小武和我一起完成這個項目,感謝小武提供的資料和算法,沒有小武的支援,我們無法完成這麼多實驗。感謝BBuf的邀請,我才能加入這個項目,一起讨論對我的幫助非常大(怎麼沒早點遇見BB:)
雖然最後是爛尾了,但是學到了不少東西,很多文章都是在這個過程中總結得到的,在這個期間總結的文章有《CV中的Attention機制》、《從零開始學習YOLOv3》、《目标檢測和感受野的總結和想法》、《PyTorch中模型的可複現性》、《目标檢測算法優化技巧》等,歡迎去幹貨錦集中回顧。
以上是整個實驗過程的一部分,後邊階段我們還遇到了很多困難,想将項目往輕量化的方向進行,由于種種原因,最終沒有繼續下去,在這個過程中,總結一下教訓,實驗說明和備份要做好,修改的資料集、訓練得到的權重、當時的改動點要做好備份。現在回看之前的實驗記錄和cfg檔案都有點想不起來某些模型的改動點在哪裡了,還是整理的不夠詳細,實驗記錄太亂。
最後希望這篇文章能給大家提供一些思路。
官方代碼:https://github.com/ultralytics/yolov3
改進代碼:https://github.com/GiantPandaCV/yolov3-point
Focal Loss Issue: https://github.com/ultralytics/yolov3/issues/811
小目标增強庫(複制和粘貼的方式):https://github.com/pprp/SimpleCVReproduction/tree/master/SmallObjectAugmentation
pprp Github: https://github.com/pprp
BBuf Github:https://github.com/BBuf
以上涉及到的所有實驗結果已經整理成markdown檔案,請在背景回複“紅外”獲得。
代碼改變世界