FreeAnchor:令anchor自由匹配標簽的策略(附源碼實現(xiàn))

Date: 2020/11/25

Coder: CW

Foreword:

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

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

OK,與基于硬性規(guī)則分配標簽相比,F(xiàn)reeAnchor的優(yōu)勢在哪里呢?通常情況下,使用硬性規(guī)則來分配標簽并無大礙,但是在一些場景下,這樣訓練出來的模型效果并不好,而使用FreeAnchor卻能克服這個問題,下面就讓CW為大家開啟這場知識盛宴吧!


Contents

I. 提出問題:基于硬性規(guī)則分配標簽帶來的問題

II. 設計新方案:怎樣才算是好的方案

? ? i). 保證召回率

? ? ii). 提高精度

? ? iii). 兼容NMS

III. 具體方法:極大似然估計

? ? i). 召回率似然函數(shù)

? ? ii). 精度似然函數(shù)

? ? ? ? -Saturated Linear 函數(shù)

? ? iii). 從似然函數(shù)到損失函數(shù)

? ? ? ? -Mean-Max 函數(shù)

IV. 實施行動:源碼實現(xiàn)


基于硬性規(guī)則分配標簽帶來的問題

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

“偏心”的月亮

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

網(wǎng)絡初期預測結(jié)果

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

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


怎樣才算是好的方案

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


保證召回率

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

提高精度

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

兼容NMS

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


極大似然估計

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

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

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

目標檢測通用loss函數(shù)

其中A_{+} A_{-} 分別表示正負樣本anchor集,B表示目標物體集合,L^{cls} 和 L^{loc}? 分別表示正樣本anchor對應的類別預測和回歸預測的損失,C_{ij} \in {0,1},等于1代表anchor j 和object i 匹配,反之亦然,L^{bg} 代表負樣本anchor對應到背景的分類預測損失。

作者構(gòu)思的最大似然估計也是從這個公式下手進行設計的:

最大似然公式轉(zhuǎn)換(i)

由于C_{ij} \in {0,1},因此上式可繼續(xù)轉(zhuǎn)化為如下:

最大似然公式轉(zhuǎn)換(ii)

其中各形式的P就代表對應損失的似然概率,似然概率越大,損失函數(shù)越小

到目前為止,以上還是基于硬性規(guī)則來分配標簽的,C_{ij} 就是根據(jù)IoU的規(guī)則來確定其值是0還是1的,而且P^{cls} 和 P^{loc}? 是分開優(yōu)化的,F(xiàn)reeAnchor希望的是,能夠在訓練過程中讓anchor根據(jù)模型當前表現(xiàn)自由地匹配相應的標簽,同時定位好的proposal在分類上的得分也要高,于是還需要進一步的設計。


召回率似然函數(shù)

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

召回率似然函數(shù)

P(\theta )_{ij}^{cls}表示分類置信度,代表候選anchor j 屬于object i 的概率;P(\theta )_{ij}^{loc} 表示定位置信度,代表候選anchor j 定位object i的得分;max_{a_{j}\in A_{i}? } (P(\theta )_{ij}^{cls}P(\theta )_{ij}^{loc} )代表的是,對于每個object i,計算其k個候選anchors的分類置信度與定位置信度乘積,然后取最大值;整體來看,P(\theta )_{recall} 就是所有object所得最大置信度的乘積。

從這個公式可以看出,F(xiàn)reeAnchor將分類置信度與定位置信度放在一起進行優(yōu)化。


精度似然函數(shù)

接著,為了提高精度,定義精度似然函數(shù)如下:

精度似然函數(shù)

P\{a_{j}\in A_{-}? \}代表anchor j(對應的proposal)屬于背景的置信度,注意這個置信度是從定位方面去衡量的,反映的是定位的好壞程度,定位得越差(proposal與object的IoU越?。@個值就越大;P(\theta )_{j}^{bg} 代表anchor j (對應的預測結(jié)果)屬于背景的概率,對應背景的分類置信度。

雖然明白了公式中各項的意義,但你可能還是有點懵,為什么優(yōu)化精度要這樣設計呢?

這樣來看,若一個anchor定位比較差,明明深圳在廣東省你卻將bbox定位到北京去了,它對應的P\{a_{j}\in A_{-}? \}值就比較大,那么我們肯定希望將它分類成背(北)景(京),即它對應的P(\theta )_{j}^{bg} 要盡可能大,否則它將成為一個FP(定位差卻分類成前景),這樣才能使乘積P\{a_{j}\in A_{-}? \}(1-P(\theta )_{j}^{bg} )降下來,從而讓1-P\{a_{j}\in A_{-}? \}(1-P(\theta )_{j}^{bg} )的值變大,而P(\theta )_{precision} 就是對每個anchor j都進行這樣的計算,最后乘起來,有聯(lián)合概率的意思。

總地來說,就是希望定位差的anchor(對應的預測結(jié)果)被分類成背景。


Saturated Linear 函數(shù)

作者定義P\{a_{j}\in A_{-}? \}的公式如下:

定義

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

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定位的好壞程度,以上性質(zhì)與這個考慮也是相吻合的。另外,這些性質(zhì)也能兼容NMS。

最終,其計算方式被設計為一個稱作saturated linear的函數(shù),形式如下:

Saturated Linear Function 公式
Saturated Linear Function 示意圖


從似然函數(shù)到損失函數(shù)

最終的似然概率函數(shù)是召回率似然概率函數(shù)與精度似然概率函數(shù)乘積

似然概率函數(shù)

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

似然函數(shù)轉(zhuǎn)換成loss函數(shù)


Mean-Max 函數(shù)

你有沒有發(fā)現(xiàn),對于max_{a_{j}\in A_{i}? } (P(\theta )_{ij}^{cls}P(\theta )_{ij}^{loc} ),每個object只會從其候選anchors中選出最大的P(\theta )_{ij}^{cls}P(\theta )_{ij}^{loc}參與訓練。這樣,對于訓練初始階段來說,參與訓練的anchors樣本貌似就太少了。另外,在訓練初期,網(wǎng)絡參數(shù)隨機初始化,所有anchors的置信度都比較低,具有最高置信度的anchor也不一定是匹配程度最好的anchor。因此,需要讓更多的anchors參與到訓練中來,待訓練得差不多(模型已經(jīng)成為老司機)了,再選max的來訓練。

為了解決這個問題,作者機智地設計了一個Mean-Max函數(shù)來取代Max函數(shù),公式如下:

Mean-Max函數(shù)公式

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

Mean-Max函數(shù)示意圖


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

最終的loss函數(shù)

源碼實現(xiàn)

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

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

FreeAnchorLoss(i)

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

FreeAnchorLoss(ii)

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

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

FreeAnchorLoss(iii)

由于在標簽制作時,為了使得一個batch的標注能組成一個tensor,于是我將各張圖片的目標物體數(shù)目填充到一致,對于填充的物體,其類別標簽設置為-1,這樣就能將其和真實的物體區(qū)分出來。

接下來先計算P(\theta )_{ij}^{cls},也就是候選anchors(對應的proposals)的分類置信度。注意這里要將每個object的候選anchors對應的置信度設置到object的對應類別下(這里使用了Pytorch的gather()方法)。

計算

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

計算

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

候選anchors的回歸損失公式

順便貼下smooth l1 loss的實現(xiàn):

smooth l1 loss

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

positive_loss

其中positive_bag_loss的實現(xiàn)如下:

positive_bag_loss

先將聯(lián)合概率輸入Mean-Max函數(shù)計算,得到轉(zhuǎn)換后的概率,然后使用二元交叉熵計算損失,這里直接將目標值設置為1,因為此處輸入到交叉熵函數(shù)的預測變量是概率,我們希望這個概率越大越好。

loss中的第一項已經(jīng)搞定,是時候從第二項下手了,先計算P\{a_{j}->b_{i}? \}

計算

注意這里要取消梯度!因為FreeAnchor的思想正是根據(jù)網(wǎng)絡的預測結(jié)果來動態(tài)分配標簽,所謂似然估計正是如此。另一個紅框部分對應的就是saturated linear函數(shù)。

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

計算

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

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

一個batch的positive loss

接著是loss中的第二項,稱作negative loss,最后把兩項loss乘上對應權(quán)重加起來得到最終的loss:

一個batch的negative loss與總loss

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

negative_bag_loss

別被名字騙了,實質(zhì)上就是一個focal loss,與positive_bag_loss類似,其中也用到了二元交叉熵,不同的是,這次的目標值設置為0,因為這里針對的是FP,既然是FP當然希望它輸出的置信度越小越好。

至于以上box_encode和box_decode的部分,這里就不貼出來了,了解anchor-based算法的應該都知道,隨便三兩下就碼出來了。


End

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容