FreeAnchor:令anchor自由匹配標籤的策略

前言

本文將要介紹一種為訓練樣本分配標籤的策略,這種策略稱作 FreeAnchor注意不是 anchor free 哦!FreeAnchor 是用於 anchor-based 體系下的策略,那麼它到底free在哪裡呢?anchor還能玩起freestyle?

是這樣的,FreeAnchor 指的是在訓練過程中讓anchor能夠根據模型當前的表現來自由匹配標籤,而非基於硬性規則為anchor分配標籤。什麼叫基於硬性規則?最常見的就是基於IoU的規則,即當anchor和某個gt box的IoU超過預設的閥值時,就將其作為這個gt的正樣本(也就是將這個gt的類別分配給該anchor作為標籤)。若anchor匹配到了多個gt boxes,那麼可以將IoU最大的那個gt分配給anchor。

OK,與基於硬性規則分配標籤相比,FreeAnchor的優勢在哪裡呢?通常情況下,使用硬性規則來分配標籤並無大礙,但是在一些場景下,這樣訓練出來的模型效果並不好,而使用FreeAnchor卻能克服這個問題,下面就讓CW為大家開啟這場知識盛宴吧!

附:
FreeAnchor: Learning to Match Anchors for Visual Object Detection
code


目錄

1. 提出問題:基於硬性規則分配標籤帶來的問題
2. 設計新方案:怎樣才算是好的方案
i). 保證召回率
ii). 提高精度
iii). 兼容NMS
3. 具體方法:極大似然估計
i). 召回率似然函數
ii). 精度似然函數

-Saturated Linear 函數

iii). 從似然函數到損失函數

-Mean-Max 函數

4. 實施行動:源碼實現

基於硬性規則分配標籤帶來的問題

用前文提到的基於IoU的規則來舉例說明,看下面這張圖。目標物是月亮,綠色框代表其gt box,紅色框代表anchor,直觀上來看兩者重疊部分還蠻大的,在這種規則下,通常會將這個gt分配給anchor。然而我們可以看到,anchor框內的區域幾乎不包含有月亮的部分,大部分都是黑色的背景,從而模型在這個框內看到的也大部分是屬於背景的特徵,但是在這種規則下卻硬要這個anchor去負責預測月亮,豈非「強anchor所難」..

偏心的月亮.png

另外,特別是在訓練初期,網絡接近於隨機預測,基於這個anchor回歸出來的proposal很可能如下綠色框所示(畫工比較有個性別吐槽..):

網絡初期預測結果.png

但是此時的規則卻將這個object標籤分配給它去計算loss,模型難免會說:太難了吧~!

因此,對於像上述月亮這種「偏心」(即目標物中心不在gt box幾何中心)的物體,這種基於IoU來為訓練樣本分配標籤的做法顯得很不友好。


怎樣才算是好的方案

和談戀愛一樣,強求是不會有幸福的,那麼怎樣的匹配方式才好呢?我們推崇自由匹(戀)配(愛)。

保證召回率

首先要保證的是召回率(Recall),就像考試做題,不要留空白,能答上來的就寫上,不能答上來的也盡量扯。對於每個gt,至少要有一個anchor去匹配,也就是至少要有一個anchor對應的proposal負責預測它。

提高精度

精度(Precision)的計算公式是TP/(TP+FP),要提高精度最直觀的方式是盡量減少FP(False-Positive)FP就是那些定位錯誤卻預測為目標物體的proposals。因此,對於定位錯誤(不好)的那些proposals,我們要將其分類為背景。

兼容NMS

大部分目標檢測的後處理都會用到NMS,它會將預測框排序,使得分類置信度高的排在前面,然後每次都以置信度最高的為基準,去掉與其重疊度(通常用IoU作評判)高的冗餘框。因此,FreeAnchor策略希望能夠兼容NMS,避免在這個過程中有預測框定位得很好但是由於在分類上的得分不夠高而被幹掉了,定位好的才是靚仔,這可是看臉的世界。


極大似然估計

OK,想法是有了,那麼具體的方法呢?

作者很優秀,將這個問題設計成極大似然估計問題,極大似然估計是用頻率來描述概率的一種思想,在這裡就是在訓練過程中使用模型的預測結果去尋找合適的目標,從而再反過來推斷模型的參數。

在anchor-based體系下的目標檢測任務中,loss函數通常設計為如下形式:

目標檢測通用loss.png

其中A_{+}和A_{-}分別表示正負樣本anchor集,B表示目標物體集合,L^{cls}和L^{loc}分別表示正樣本anchor對應的類別預測和回歸預測的損失,C_{ij}的是非0即1,等於1代表anchor j 和object i 匹配,反之亦然。L^{bg}代表負樣本anchor對應到背景的分類預測損失。
作者構思的最大似然估計也是從這個公式下手進行設計的:

最大似然公式轉換(i).png

由於C_{ij}非0即1,因此上式可繼續轉化為如下:

最大似然公式轉換(ii).png

其中各形式的P就代表對應損失的似然概率,似然概率越大,損失函數越小
到目前為止,以上還是基於硬性規則來分配標籤的,C_{ij}就是根據IoU的規則來確定其值是0還是1的,而且P^{cls}和P^{loc}是分開優化的,FreeAnchor希望的是,能夠在訓練過程中讓anchor根據模型當前表現自由地匹配相應的標籤,同時定位好的proposal在分類上的得分也要高,於是還需要進一步的設計。


召回率似然函數

在上一節說過,首先要保證召回率。對於每個目標物體,我們都為其選擇k(原作中k=50)個和其IoU最大的anchor作為候選正樣本,然後定義優化召回率對應的似然函數如下:

召回率似然函數.png

P(\theta){ij}^{cls}表示分類置信度,代表候選anchor j 屬於object i 的概率;P(\theta){ij}^{loc}表示定位置信度,代表候選anchor j 定位object i的得分符號.png代表的是,對於每個object i,計算其k個候選anchors的分類置信度與定位置信度乘積,然後取最大值;整體來看,P(\theta)_{recall}就是所有object所得最大置信度的乘積。
從這個公式可以看出,FreeAnchor將分類置信度與定位置信度放在一起進行優化

精度似然函數

接着,為了提高精度,定義精度似然函數如下:

精度似然函數.png

符號i.png代表anchor j(對應的proposal)屬於背景的置信度,注意這個置信度是從定位方面去衡量的,反映的是定位的好壞程度,定位得越差(proposal與object的IoU越小),這個值就越大;P(\theta){j}^{bg}代表anchor j (對應的預測結果)屬於背景的概率,對應背景的分類置信度。
雖然明白了公式中各項的意義,但你可能還是有點懵,為什麼優化精度要這樣設計呢?
這樣來看,若一個anchor定位比較差,明明深圳在廣東省你卻將bbox定位到北京去了,它對應的符號i.png值就比較大,那麼我們肯定希望將它分類成背(北)景(京),即它對應的P(\theta)
{j}^{bg}要儘可能大,否則它將成為一個FP(定位差卻分類成前景),這樣才能使乘積符號ii.png降下來,從而讓符號iii.png的值變大,而P(\theta)_{precision}就是對每個anchor j都進行這樣的計算,最後乘起來,有聯合概率的意思。
總地來說,就是希望定位差的anchor(對應的預測結果)被分類成背景

Saturated Linear 函數

作者定義符號i.png的公式如下:

符號iv.png

P{a_{j}->b_{i}}表示anchor j 能匹配object i 的概率,而max_{i}P{a_{j}->b_{i}}表示anchor j與每個物體計算匹配概率,取其中的最大值。作者認為,P{a_{j}->b_{i}}的定義應該滿足以下3個性質:

i). anchor j 與 object i 的IoU越大,這個概率值應該越大;
ii). anchor j 與 object i 的IoU小於預設的閥值時,這個值應該被置為0;
iii). 對於每個object i,有且只有一個anchor j 滿足P{a_{j}->b_{i}}=1

前面說到過,P{a_{j}->b_{i}}反映的是anchor定位的好壞程度,以上性質與這個考慮也是相吻合的。另外,這些性質也能兼容NMS。
最終,其計算方式被設計為一個稱作saturated linear的函數,形式如下:

Saturated Linear Function 公式.png
Saturated Linear Function 示意圖.png

從似然函數到損失函數

最終的似然概率函數是召回率似然概率函數與精度似然概率函數乘積:

似然概率函數.png

講似然概率函數講得有點high..我們還是要回到模型訓練中來,既然要訓練就離不開loss函數,因此需要將這個似然函數轉換為loss的形式去優化:

似然函數轉換成loss函數.png

Mean-Max 函數

你有沒有發現,對於符號.png,每個object只會從其候選anchors中選出最大的符號v.png參與訓練。這樣,對於訓練初始階段來說,參與訓練的anchors樣本貌似就太少了。另外,在訓練初期,網絡參數隨機初始化,所有anchors的置信度都比較低,具有最高置信度的anchor也不一定是匹配程度最好的anchor。因此,需要讓更多的anchors參與到訓練中來,待訓練得差不多(模型已經成為老司機)了,再選max的來訓練。
為了解決這個問題,作者機智地設計了一個Mean-Max函數來取代Max函數,公式如下:

Mean-Max函數公式.png

在各項值都較小趨近相同時,函數輸出值近似於均值;當其中某項值較大,而其它項較小,並且差異明顯時,函數輸出值就傾向於這個較大的值。相當於從mean過渡到max的效果,正好與訓練前期和後期模型輸出的置信度對應起來,妙哉妙哉~!

Mean-Max函數示意圖.png

除了使用Mean-Max函數取代Max函數,還對loss中的第二項使用Focal Loss,同時為loss中的每項都加上相應的權重:

最終的loss函數.png


源碼實現

費了不少口水(抱歉,忘了我是在碼字,不需要動嘴..),對於coder來說,只知道理論不會寫代碼相當於什麼都不知道,來吧,看看代碼怎麼寫。哦,對了,添一句,以下實現基於Pytorch框架。

這裡我使用一個類來封裝,先把需要的參數進行初始化:

FreeAnchorLoss(i).png

然後loss的計算封裝在__call__()方法里,這樣能將這個類對象當作函數來調用:

FreeAnchorLoss(ii).png

這裡我的實現兼容了FPN多尺度,classifications和regressions分別代表分類和回歸預測,anchors包含了特徵金字塔所有層級的anchors,annotations是圖像的標註,包括目標物體的bbox和類別。

輸入進來的是一個batch的數據,為了思路更清晰,對每張圖片依次進行計算:

FreeAnchorLoss(iii).png

由於在標籤製作時,為了使得一個batch的標註能組成一個tensor,於是我將各張圖片的目標物體數目填充到一致,對於填充的物體,其類別標籤設置為-1,這樣就能將其和真實的物體區分出來。
接下來先計算P(\theta)_{ij}^{cls},也就是候選anchors(對應的proposals)的分類置信度。注意這裡要將每個object的候選anchors對應的置信度設置到object的對應類別下(這裡使用了Pytorch的gather()方法)。

計算.png

然後計算P(\theta)_{ij}^{loc},代表候選anchors(對應的proposals)的定位好壞程度。

計算ii.png

紅框部分與前文所述的公式對應:

候選anchors的回歸損失公式.png

順便貼下smooth l1 loss的實現:

smooth l1 loss.png

有了以上兩個似然概率,我們已經可以將loss公式中的第一項計算出來了,這部分稱作positive loss,因為其是針對正樣本的,要求它對應的似然概率越大越好(loss當然還是越小越好):

positive_loss.png

其中positive_bag_loss的實現如下:

positive_bag_loss.png

先將聯合概率輸入Mean-Max函數計算,得到轉換後的概率,然後使用二元交叉熵計算損失,這裡直接將目標值設置為1,因為此處輸入到交叉熵函數的預測變量是概率,我們希望這個概率越大越好。
loss中的第一項已經搞定,是時候從第二項下手了,先計算P{a_{j}->b_{i}}:

計算iii.png

注意這裡要取消梯度!因為FreeAnchor的思想正是根據網絡的預測結果來動態分配標籤,所謂似然估計正是如此。另一個紅框部分對應的就是saturated linear函數。

有了P{a_{j}->b_{i}},計算max_{i}P{a_{j}->b_{i}}自然水到渠成:

計算v.png

這裡可能有點繞,在實現的時候,這個概率並不是如公式般將anchor與object對應起來,而是將這個值設置在anchor與object對應的類別下,這是因為這個概率需要與網絡的分類預測輸出乘在一起(element-wise multiply),維度需要對應起來。作者在實現這部分時用了稀疏矩陣(torch.sparse_coo_tensor),沒那麼好理解,CW改成了這種比較low的形式,雖然計算速度可能稍受影響,但相對來說更直觀、易理解。

至此,每張圖像需要的計算已完工,下面可以來匯總下結果,還是先處理loss中的第一項:

一個batch的positive loss.png

接着是loss中的第二項,稱作negative loss,最後把兩項loss乘上對應權重加起來得到最終的loss:

一個batch的negative loss與總loss.png

注意這裡實現的時候,對應於公式中1-P(\theta)_{j}^{bg}的部分,我們直接使用網絡的分類預測就OK了。哦,放心,CW不會漏了negative_bag_loss的:

negative_bag_loss.png

別被名字騙了,實質上就是一個focal loss,與positive_bag_loss類似,其中也用到了二元交叉熵,不同的是,這次的目標值設置為0,因為這裡針對的是FP,既然是FP當然希望它輸出的置信度越小越好。
至於以上box_encode和box_decode的部分,這裡就不貼出來了,了解anchor-based算法的應該都知道,隨便三兩下就碼出來了。


End

如今,像FreeAnchor這種在訓練過程中引導網絡自由學習匹配標籤的策略越來越多,突破了傳統基於hard規則分配標籤的束縛,咋一看倒是越來越智能了,希望這個世界早日從人工弱智進化到人工智能,乾巴爹酷納塞!