目標檢測演算法之RetinaNet(引入Focal Loss)

  • 2019 年 12 月 4 日
  • 筆記

前言

今天來介紹一下目標檢測演算法中RetinaNet,這篇論文是CVPR2018的作品,Kaiming He大神也是作者之一,同時這篇論文提出的Focal Loss也對工程上訓練更好的目標檢測模型做出了很大貢獻,所以我們嘗試理解一下這篇論文的思想。論文地址為:https://arxiv.org/pdf/1708.02002.pdf

研究背景

前面我們介紹了一些One-Stage目標檢測演算法和Two-Stage目標檢測演算法,這些演算法在精度和速度上都各有特點,現在我們畫個圖總結一下之前介紹的各種演算法的速度和精度:

可以看到One-Stage演算法的精度相對於Two_Stage偏低,然後作者把這種問題的原因歸結於正負類別不平衡(簡單難分類別不平衡)。因此論文通過重新設計標準的交叉熵損失來解決這種難易樣本不平衡的問題,即文章的核心Focal Loss。結合了Focal Loss的One-Stage的目標檢測器被稱為RetinaNet,該檢測器在COCO數據集上MAP值可以和FPN(特徵金字塔目標檢測器,前面介紹過,推文地址為:https://mp.weixin.qq.com/s/4KT6huH6gFAautE3weZENA)和MaskRCNN接近。

一些問題?

什麼是hard/esay postive/negtive example?

網上找到一張圖解釋在目標檢測任務的一張圖中什麼是hard/easy postive/negtive example。

候選框可以分成postive/negtive兩類。當bbox(由anchor加上偏移量得到)與ground truth間的IOU大於我們設置的閾值(一般取0.5)時,會認為該bbox屬於positive example,如果IOU小於下門限就認為該bbox屬於negative example。

為什麼One-Stage檢測演算法精度偏低?

論文認為One-Stage演算法準確度低是由於類別失衡引起的。因為在一張普通圖片中,目標的所佔的比例遠遠小於背景所佔的比例,所以兩類候選框例子中以negtive example為主。這就導致了:

  • (1)針對所有的negtive example,數量過多造成它的loss太大,以至於主導了損失函數,不利於收斂。
  • (2)針對單個negtive example來說,大多數的negative example不在前景和背景的過渡區域上,分類很明確(這種易分類的negative稱為easy negative),訓練時對應的背景類score會很大,換句話說就是單個example的loss很小,反向計算時梯度小。梯度小造成easy negative example對參數的收斂作用很有限,我們更需要loss大的對參數收斂影響也更大的example,即hard positive/negative example。

因此如果One-Stage演算法如果無腦的將所有bbox拿去做分類損失,因為bbox中屬於background的bbox太多了,所以如果分類器無腦地把所有bbox統一歸類為background,accuracy也可以刷得很高。這就導致分類器訓練失敗了,自然檢測精度就偏低了。對於YOLO和SSD來講,他們也確實沒有無腦將所有的bbox拿去做分類損失,如在SSD中利用Hard-Negtive-Mining的方式將正負樣本的比例控制在1:3,YOLO通過損失函數中權重懲罰的方式增大正樣本對損失函數的影響等。但它們雖然可以處理第1個問題,但對於第2個問題就無能為了,這也是Focal Loss出現的原因。

Faster-RCNN為什麼精度更高?

Faster-RCNN在FPN階段會根據前景分數提出最可能是前景的example,這就會濾除大量背景概率高的easy negtive樣本,這便解決了上面提出的第2個問題。同時,在生成樣本給ROIPooling層的時候,會據IOU的大小來調整positive和negative example的比例,比如設置成1:3,這樣防止了negative過多的情況(同時防止了easy negative和hard negative),就解決了前面的第1個問題。因此,相對於One-Stage檢測器,Faster-RCNN的精度更高。

Focal Loss

論文引入了Focal Loss來解決難易樣本數量不平衡。One-Stage的模板檢測器通常會產生10k數量級的框,但只有極少數是正樣本,正負樣本數量非常不平衡。我們在計算分類的時候常用的損失——交叉熵的公式如下:

為了解決正負樣本數量不平衡的問題,我們經常在交叉熵損失前面加一個參數,即:

雖然平衡了正負樣本的數量,但實際上,目標檢測中大量的候選目標都是易分樣本。這些樣本的損失很低,但是由於數量極不平衡,易分樣本的數量相對來講太多,最終主導了總的損失。

因此,這篇論文認為易分樣本(即,置信度高的樣本)對模型的提升效果非常小,模型應該主要關注與那些難分樣本 。所以Focal Loss橫空出世了。一個簡單的想法就是只要我們將高置信度(p)樣本的損失降低一些就好了吧?也即是下面的公式:

我們取等於2來只管感受一下,如果,那麼,,損失降低了1000倍。最終Focal Loss還結合了公式(2),這很好理解,公式(3)解決了難易樣本的不平衡,公式(2)解決了正負樣本的不平衡,將公式(2)與(3)結合使用,同時解決正負難易2個問題!所以最終Focal Loss的形式如下:

下面這張圖展示了Focal Loss取不同的時的損失函數下降。

實驗結果展示,當,時,效果最好,這樣損失函數訓練的過程中關注的樣本優先順序就是正難>負難>正易>負易了。

RetinaNet

說完了Focal Loss就回到文章RetinaNet,Focal Loss與ResNet-101-FPN backbone結合就構成了RetinaNet(one-stage檢測器),RetinaNet在COCO test-dev上達到39.1mAP,速度為5FPS。下圖展示了RetinaNet的網路結構:

訓練RetinaNet時有幾個值得注意的關鍵點:

  • 訓練時FPN每一級的所有example都被用於計算Focal Loss,loss值加到一起用來訓練。
  • 測試時FPN每一級只選取score最大的1000個example來做nms。
  • 整個結構不同層的head部分(上圖中的c和d部分)共享參數,但分類和回歸分支間的參數不共享。
  • 分類分支的最後一級卷積的bias初始化成前面提到的-log((1-π)/π。

RetinaNet和當時流行的檢測演算法速度和精度對比如下,可以看到從速度和精度都完成了對其他演算法的壓制:

在這裡插入圖片描述

實驗

Table1是關於RetinaNet和Focal Loss的一些實驗結果。其中(a)是在交叉熵的基礎上加上參數,就表示傳統的交叉熵,可以看出當a=0.75的時候效果最好,AP值提升了0.9。(b)是對比不同的參數和的實驗結果,可以看出隨著的增加,AP提升比較明顯。(c)是anchor對AP值的影響。(d)是通過和OHEM的對比可以看出最好的Focal Loss比最好的OHEM提高了3.2AP。這裡OHEM1:3表示在通過OHEM得到的minibatch上強制positive和negative樣本的比例為1:3,通過對比可以看出這種強制的操作並沒有提升AP。(e)加入了運算時間的對比,可以和前面的Figure2結合起來看,速度方面也有優勢。Table2表示RetinaNet和One-Stage檢測器的比較,可以看到RetinaNet也是毫不順色的。

程式碼實現

keras版本:https://github.com/fizyr/keras-retinanet pytorch版本: https://github.com/yhenon/pytorch-retinanet caffe-focal loss: https://github.com/chuanqi305/FocalLoss

後記

今天講了目標檢測演算法中的RetinaNet,希望可以對Focal Loss有清晰的了解,在工程上使用Focal Loss也是一種訓練其他One-Stage檢測器的有效方法。今天就講到這裡啦。


歡迎關注我的微信公眾號GiantPadaCV,期待和你一起交流機器學習,深度學習,影像演算法,優化技術,比賽及日常生活等。