對PyramidBox的理解小記

  首先介紹一下PyramidBox,這是百度研發的人臉檢測深度學習算法,感覺BAT裏,百度在算法方面還是非常有實力的。根據官方數據,今年三月份這個盒子在世界最權威的人臉檢測公開評測集 WIDER FACE 的「Easy」、「Medium」和「Hard」三項評測子集中均榮膺榜首刷新業內最好成績。《PyramidBox: A Context-assisted Single Shot Face Detector》——環境輔助的單步人臉檢測器,文章很新,今年三月份發的。這裏提供一下論文鏈接:https://arxiv.org/abs/1803.07737?context=cs以及demo鏈接:https://github.com/EricZgw/PyramidBox

  首先解釋一下什麼是single-shot。這裏有single-shot(單步) 和multi-shot(多步),有single-scale(單尺度)和multi-scale(多尺度)。圖1a圖多步單尺度檢測,b圖單步多尺度檢測,c圖單步單尺度檢測。Scale的single/multi對應是否是同一特徵層檢測出的結果。Shot的single/multi對應是否是多輸入。藍色層視爲Input,multi-shot將同一輸入進行縮放,縮放爲原來的1/2、1/4等,single-shot對輸入不作處理。

 

1
圖1

 

 

2
圖2

 

PyramidBox的網絡結構如圖2。希望在這裏簡單介紹一下它的網絡結構、環境輔助的預測模塊、文章創新成分PyramidAnchor以及聯合的訓練方法。

    網絡結構先看圖2的虛框conv。這裏不得不提VGG16網絡。在介紹VGG網絡前,介紹卷積神經網絡的一些基本概念。

(1)卷積是什麼?

 

3
圖3

橙色框(3x3)爲卷積核,它在綠色圖上一格格移動(所以這裏步長爲1),橙色框相當於對應綠色框內值的係數,對應相乘再相加就能得到卷積值(對應粉色框內的一個值)。這樣一輪過後我們發現image變小了,從5x5變成了3x3。

(2)什麼是池化?

 

4
圖4

和前面一樣,池化也是三個矩陣間的運算。它的目的是直觀得將輸入層變小。不過這時核的移動間沒有重合,沒有與各自係數相乘並相加的操作,我覺得是一種比較特別的“卷積”吧。那Pooled feature值怎麼得來的呢?有好幾種方法,一種是直接取紅色框裏最大值稱做max pooling,用不同框裏的最大值組成pooled feature層。如圖5。

 

5
圖5

 

(3)什麼是步長?

步長就是卷積核每次移動的距離。在圖示裏,它每次移動多少格,步長就是多少。我們可以發現,步長越大,輸出的結果面積越小。

(4)什麼是卷積核?

就是圖3中橙色框,有時候我們要提取的特徵非常多和廣,需要用更多的不同的橙色框來掃,所以能得到不同的特徵層(粉色層)。這裏我們知道,特徵層的個數就是卷積核的個數。

(5)什麼是Padding?

padding中文就是填充的意思,顧名思義在圖3中我們由5x5的輸入得到3x3輸出,如果我們要輸入輸出的大小不變,就可以在輸入層外邊加一圈“0”。這樣5x5變成7x7,用一樣的3x3卷積核,以步長爲1的方式卷積,就能得到5x5的輸出了。如圖6。

6
圖6

 

 

具備了這些概念,回到VGG網絡。16表示層數(圖7中所有的黑色層和藍色層,也即圖8中的所有conv層和fc層)。

 

7
圖7

 

 

8
圖8

我們拿第一個黑色層(也就是VGG16中的第一層裏的第一小層,即conv1_1)來剖析。我們有了一個224x224的彩色圖片,因爲色彩有RGB三個值,故有三個通道(R通道、G通道、B通道)。

 

9
圖9

每個(黃色的)卷積核在綠色長方體中移動,分別對應27個數和卷積核上的係數分別相乘,再相加,利用padding技術另輸出的大小依然爲224x224.至此我們利用一個卷積核輸出了224x224x1的卷積層(即一層)。同理我們用64個不同的卷積核做相同處理,能得到64個224x224x1的卷積層,堆疊起來就是224x224x64。

那圖7裏的紅色層(也即圖8裏的pool層)是什麼,看起來它的作用是將前一階段得到的卷積層的尺寸減半(長寬各爲原來一半)。看名字知道這是個池化層,拿第一個池化層剖析,我們能得到conv1_2的結果是224x224x64。(以後有時間補充con1_2層做了什麼)用步長爲2的2x2核(看作一個2x2大小的二維面)移動在每個維度上,最終得到112x112x64。如圖10。

 

10
圖10

圖2網絡的①框部分就明瞭了。進入框②部分。這個部分第一個層是個全連接層。看名字conv_fc7,論文中介紹這一層是VGG16中的fc6和fc7層轉換來的。後面兩個又是兩個卷積層讓網絡變得更深了。文章裏沒有說爲什麼要這麼設計,可能這就是非常玄乎的“最好選擇”吧。

這裏介紹一下全連接層。即圖7的藍色層(也即圖8的fc層),PyramidBox中並沒有全部引用VGG16的網絡結構,它有點像集各家所長,把各個已知網絡的特長集爲一體(像使用了與 S^{3}FD完全相同的主幹網絡,包括基礎卷積層和額外卷積層;將 VGG16 中的 fc6 層和 fc7 層做了轉化;在基於anchor機制的網絡上進行改造的PyramidAnchor;以及後面提到的由max-out改進得到的max-in-out由FPN改進得到LFPN,用 DSSD 中的殘差預測模塊替換了 SSH 中的環境模塊的卷積層等等這裏先引申介紹全連接層的作用。

拿VGG16的fc4096舉例:經過卷積,ReLU後得到3x3x5的輸出如何變成1x4096形式呢?ReLU是一種激活函數,就是將卷積結果(這裏假設爲x)在成爲下一層的卷積層的值之前經過一個函數:max(0,x),x若小於等於0,結果爲0;x若大於0,則爲x。又跑偏了...重新回到全連接層。

 

11
圖11

如圖11我們是如何將3x3x5的卷積變成1x1x4096的呢?

 

12
圖12

從圖12我們可以看出,用一個3x3x5的卷積核做卷積,將結果求和就是一個fully connected layer 的一個神經元的輸出,這個輸出就是一個值。因爲我們有4096個神經元。我們實際就是用一個3x3x5x4096的卷積層去卷積激活函數的輸出。

它把特徵表示整合到一起,輸出爲一個值。

這樣做的目的就是大大減少特徵位置對分類帶來的影響。爲什麼這麼說?

舉個例子:

 

13
圖13

  從圖13我們可以看出,貓在不同的位置,輸出的feature值相同,但是位置不同。因爲目標檢測對於系統來說,特徵值相同,但是特徵值位置不同,那分類結果也可能不一樣。這時全連接層filter的作用就相當於喵在哪我不管,我只要喵,於是我讓filter去把這個喵找到,實際就是把feature map 整合成一個值,這個值大,有喵,這個值小,那就可能沒喵。和這個喵在哪關係不大了,魯棒性有大大增強。因爲空間結構特性被忽略了,所以全連接層不適合用於在方位上找Pattern的任務,比如segmentation。

  全連接層中一層的一個神經元就可以看成一個多項式,我們用許多神經元去擬合數據分佈,但是隻用一層fully connected layer 有時候沒法解決非線性問題,而如果有兩層或以上fully connected layer就可以很好地解決非線性問題了。我們都知道,全連接層之前的作用是提取特徵,全理解層的作用是分類,我們現在的任務是去區別一圖片是不是貓。

 

14
圖14

  假設這個神經網絡模型已經訓練完了,全連接層已經知道怎麼檢測一隻貓,即它已經掌握了貓的特徵。

 

15
圖15

當我們得到(圖15的)以上特徵——貓頭、貓尾、貓腿等,我就可以判斷這個東東是貓了。全連接層的作用主要就是實現分類。

 

 

16
圖16

從圖16,我們可以看出紅色的神經元表示這個特徵被找到了(激活了)。同一層的其他神經元,要麼貓的特徵不明顯,要麼沒找到。當我們把這些找到的特徵組合在一起,發現最符合要求的是貓。ok,我認爲這是貓了。那我們又是怎麼認得這是貓頭,這是貓尾的呢?一樣的道理。就是把貓頭的這麼些子特徵找到,比如眼睛啊,耳朵啊。如圖17。

 

17
圖17

當我們找到這些特徵,神經元就被激活了(圖18紅色圓圈)這細節特徵又是怎麼來的?就是從前面的卷積層,下采樣層來的。

 

18
圖18

可以看出全連接層參數特多——圖裏密密麻麻的線。(可佔整個網絡參數80%左右)

全連接層對模型影響參數就是三個:

1.全接解層的總層數(長度)

2.單個全連接層的神經元數(寬度)

3.激活函數

順利進入第③個部分。這裏是個LFPN。先介紹一下FPN(Feature Pyramid Networks)。FPN採用特徵金字塔做目標檢測的網絡,PyramidBox涉及的論文很大程度(網絡結構,設計上)都與之相同。這裏提供論文feature pyramid networks for object detection接:https://arxiv.org/abs/1612.03144

如圖19所示。FPN(圖19d)是single-shot,特徵抽取的過程像金字塔一樣,低層的感受野小,特徵抽取度小,高層感受野大,特徵抽取度大。在此基礎上,FPN從最高層開始,將特徵層往下融合,並在各個融合層上分別predict。

 

19
圖19

問題是如何從上往下融合特徵層。圖19裏可以看到。因爲相鄰特徵層長寬差兩倍,融合大概是先把上一層的特徵層兩倍上採樣(理解爲放大兩倍),再將下一層用1x1卷積核卷積(目的是升維,因爲相鄰兩層的維度或者說通道數也不一樣,下層的維度比較低),在大小和維度均一致後再相加進行融合。具體操作如圖20。

 

20
圖20

 

21
圖21

 

這裏延伸出來的問題是1x1卷積核是怎麼進行升維或者降維的。1x1conv我認爲這裏省略了維度,如果輸入的通道是n,那麼卷積核就是1x1xn,將相同位置不同通道乘上係數後相加,得到一個層。如圖22所示,輸入爲4x4x3,用2個1x1x3的核就能得到4x4x2的結果從而實現降維。同理用4個1x1x3的核得到4x4x4的結果從而實現升維。結果的維度和核的個數相同。

 

22
圖22

那2x up(即兩倍上採樣)是什麼操作?(有時間補充,佔個坑)

那麼爲什麼PyramidBox不和FPN一樣從最高層開始往下融合?圖2示它從中間層開始往下融合。這裏先介紹一下感受野。

 

23
圖23

圖23上橘色層(從左往右第二層)上的每個單位是紅色層部分圖像的收集,這個單位它看不到紅色層其他地方,感受野是最小的,最高層(從左往右第五層)這個藍點相當於把整張圖片的信息都收入囊中了,它觀察者着整張圖。我們總結出金字塔式的特徵層,越往上感受野越大。至於爲什麼要從中間開始融合特徵層,舉個例子:大家知道麥田怪圈是佔地面積很大的一種神祕現象吧,世界未解之謎之一......(扯遠了)。我如果站在麥田裏(相當於處在低層),站在怪圈中,我只能看見一個線段,圖案太大了我瞧不出來是個什麼東西。

如果我有一個朋友他有20米高(相當於處在中層),他能看到的比我能看到的多,他能告訴我這個圖案是個西瓜。我們兩個合作就既能看清細節又能知道環境的語義,這是融合的目的。那如果我朋友他有2000米高,或者他坐在飛機上(相當於處在高層),他從飛機上往下看,他看到麥田也只是個綠點了。我倆互通有無也不知道是畫的是啥。網絡是一樣的道理,它從中部開始向下融合,中部的感受野大概是最高層的一半,就比較合適。

放在人臉的檢測上同理,不是所有的高層級特徵都一定對檢測較小的人臉有幫助。首先,較小的,模糊的,被遮擋的人臉與較大的,清晰的,完整的人臉有不同的紋理特徵。所以,直接用高層級特徵來提升檢測器在較小人臉上的表現是過於簡單粗暴的。第二,高層級特徵是從缺少環境的區域中提取出來的,並且可能引入噪聲信息。比如,在 PyramidBox 的主幹層裏,層級最高的兩層 conv7_2 和 conv6_2 的感受野分別是 724 和 468,而訓練圖像的輸入尺寸是 640。這意味着上面兩層只包含大尺度的人臉而且缺少環境特徵,所以可能對檢測中等和小尺寸的人臉沒什麼幫助。

所以到這裏,我們用LFPN,得到了加強版的特徵層。

圖2的框③也解決啦,來到④⑤,這裏準備放在一起講,還是上圖。

 

24
圖24

如圖24所示,這是一個CPM(Context-sensitive Prediction Module)。 Inception-ResNet 得到啓發,其中Inception使網絡變得更寬,Resnet使網絡變得更深。我們當然可以同時借鑑既獲得網絡變寬的收益又獲得網絡變深的收益。那麼ResNet 是如何讓網絡變得更深的呢?Inception又是如何讓網絡變得更寬的呢?先說Resnet爲什麼會出現呢?是因爲非常深的網絡在增加更多層時會表現得更差。可是網絡不是越深越好嗎?因爲更深的模型意味着可以學出更多東西,帶來精度的提升假設我們已經構建了一個 n 層網絡,並且實現了一定準確度。那麼一個 n+1 層網絡至少也應該能夠實現同樣的準確度——只要簡單複製前面 n 層,再在最後一層增加一層恆等映射就可以了。類似地,n+2、n+3 和 n+4 層的網絡都可以繼續增加恆等映射,然後實現同樣的準確度。但是在實際情況下,這些更深度的網絡基本上都會表現得更差。ResNet的作者將這些問題歸結成了一個單一的假設:直接映射是難以學習的。而且他們提出了一種修正方法:不再學習從 x 到 H(x) 的基本映射關係,而是學習這兩者之間的差異,也就是「殘差(residual)」。然後,爲了計算 H(x),我們只需要將這個殘差加到輸入上即可。

假設殘差爲 F(x)=H(x)-x,那麼現在我們的網絡不會直接學習 H(x) 了,而是學習 F(x)+x。

這就帶來了你可能已經見過的著名 ResNet(殘差網絡)模塊如圖25

 

25
圖25

ResNet 的每一個「模塊(block)」都由一系列層和一個「捷徑(shortcut)」連接組成,這個「捷徑」將該模塊的輸入和輸出連接到了一起。然後在元素層面上執行「加法(add)」運算,如果輸入和輸出的大小不同,那就可以使用零填充或投射(通過 1×1 卷積)來得到匹配的大小。

回到我們的思想實驗,這能大大簡化我們對恆等層的構建。直覺上就能知道,比起從頭開始學習一個恆等變換,學會使 F(x) 爲 0 並使輸出仍爲 x 要容易得多。一般來說,ResNet 會給層一個「參考」點 x,以 x 爲基礎開始學習。這一想法在實踐中的效果好得讓人吃驚。

Inception是如何使網絡變得更寬的呢?我們知道不同類型的層會提取不同種類的信息。5×5 卷積核的輸出中的信息就和 3×3 卷積核的輸出不同,那怎麼知道到底是5x5的卷積結果好還是3x3的卷積結果好,Inception 模塊是個非常認真不怕累的好模塊,它就都試了一遍,如圖26它並行計算同一輸入映射上的多個不同變換,並將它們的結果都連接到單一一個輸出。換句話說,對於每一個層,Inception 都會執行 5×5 卷積變換、3×3 卷積變換和最大池化。然後該模型的下一層會決定是否以及怎樣使用各個信息。大家是不是看出來問題在哪了呢?計算時間和成本都是很貴的,性能boss說你這樣“燒錢”我養不起你。

 

26
圖26

爲了生存下去,Inception使用 1x1 卷積來執行降維如圖27的1x1 convolutions。比如,使用 20 個 1×1 過濾器,一個大小爲 64×64×100(具有 100 個特徵映射)的輸入可以被壓縮到 64×64×20。通過減少輸入映射的數量,Inception 可以將不同的層變換並行地堆疊到一起

所以用ResnetInception從而得到既深又寬(寬指有很多並行操作)的網絡。

 

27
圖27

圖24的三個輸出分別輸出臉部、頭部和身體的特徵層(臉部4(用於分類)+4(用於迴歸定位)、頭部2(用於分類)+4(用於迴歸定位)、身體2(用於分類)+4(用於迴歸定位)),concatenate就是舒芙蕾蛋糕一樣把這20層堆疊起來。用於圖27所示的Cls和Reg的輸出——即對分類和定位的預測。

④就到這裏,它的輸出爲w_{l}\times h _{l}\times c_{l},(l=0,1,...,5),其中 w_{l}=h _{l}=640/2^{2+l}是對應的特徵尺寸,通道尺寸 c_{l}=20。這裏每個通道的特徵分別被用來分類和迴歸面部,頭部和身體。人臉的分類需要 4 (=cp_{l}+cn_{l})個通道,其中 cp_{l}cn_{l}分別是前景和背景的 max-in-out 標籤,滿足

 

此外,頭部和身體的分類各需要兩個通道,面部、頭部和身體的定位各需要 4 個通道。爲什麼第0層的特徵層是1、3的分配,非0層的是3、1的分配呢?

還是用圖來說明:圖28中我們可以看到在一張640x640圖片上所能產生的不同size的anchor的數量,顯然尺寸小的anchor佔了絕大比例,這也是false positive的主要來源。

 

28
圖28

如圖29所示,anchor分爲positive anchor和negative anchor。Positive anchor指框住了目標或物體的anchor(或者說前景),negative anchor就是內容爲背景的anchor。低層anchor數量大,能框住小物體的能力大,但是失敗的anchor也比其他層多(因爲基數大),所以失敗比就越高。

 

29
圖29

爲了減少小目標所產生的false positive,S^{3}FD採用了圖30的方法來加強對小目標的區分即max-out(注意PyramidBox中爲max-in-out)對每個anchor分類的預測都打個分,後面有講到如何預測。

 

30
圖30

Max-out就是把許多作爲negative anchor 的可能性中最大值挑出來作爲最終預測它爲negative anchor的打分。Max-in-out就是把positive和negative anchor都做此處理,在正負樣本上都使用這個策略。那爲什麼negative anchor會有不同的打分呢?可以想象成是對anchor謹慎地做了多遍預測,這樣它被判斷爲negative的概率就高了,之前說過false positive在低層很高,這樣操作之後能讓預測的準確率提升。

在上面我們提到CPM產生的特徵層上進行分類和定位的預測。這裏不得不先提這篇文章的創新——Pyramid Anchor。不過據我觀察,它和傳統的anchor其實差不多,只不過它在這名字前加了個Pyramid,有點像Java裏的子類和父類的關係吧。子類繼承父類,同時繼承了父類的方法和屬性,但是長江後浪推前浪,子類自己做了些適應具體環境的改變。爸爸anchor是做什麼的?兒砸PyramidAnchor又做了什麼改變呢?

傳統anchor的本質就是.......將相同尺寸的輸出,往底層倒推得到不同尺寸的輸入31是anchor三種不同的窗口尺寸——128^{2}256^{2}512^{2}在每一個尺寸下,都取三種不同的長寬比(1:1,1:2,2:1),這樣我們這裏得到了9種面積尺寸各不相同的anchor。那我們拿這些小框框做什麼呢?框東西!用來框東西!它就像一個漁網在漫漫像素海里撈魚,而且這漁網還能變大變小,變長變寬。而且特徵層的尺寸決定了其上的anchor數量,也就是說特徵圖上每一個點不是在原始圖像上都能反應一塊區域碼?以這個區域的中心點生成9個同心的不同尺寸形狀的anchor。每一個特徵層的點都能派生出9個anchor,那麼w\times l的特徵層上就能有w\times l\times 9個anchor,讓檢測目標逃無可逃!喵~

 

31
圖31

 

 

32
圖32

 

介紹了anchor,再介紹如何基於anchor做分類和定位的預測。圖32非常形象地展示了anchor是如何被預測類別和位置的。對每個anchor進行類別上的預測(是前景或背景的概率,並且預測在每個anchor基礎上物體的位置,用四個參數來表示。)我們在feature map滑動一個mini-network,這個network輸入是3 * 3 * 256,經過3 * 3 * 256 * 256的卷積,得到1 * 1 * 256的低維向量;接下來進行分支:①Classification:經過1 * 1 * 256 * 18的卷積核,得到1 * 1 * 18的feature vector,分別代表9個proposals的是/不是Object的概率(這裏有一個疑惑,爲什麼要生成一對?生成一個是Object的概率不就好了?也許是爲了設計方便?);②Regression:經過1 * 1 * 256 * 36的卷積核,得到1 * 1 * 36的feature vector,分別代表9個proposals的(center_x,center_y,w,d)。當然在本文的PyramidBox中並沒有9個anchor的設計。

那Pyramid Anchor是什麼呢?提醒一句爲了省事,PyramidBox裏涉及的anchor其實都是Pyramid Anchor。特徵層每個單元對應在原圖裏的中心點,以這個中心點爲中心以每層anchor的大小的固定的尺寸能產生1個anchor而不是9個。對每個anchor我們都給他打三個label。對於一個原始圖像中在目標區域 region_{target}的目標人臉,考慮 anchor_{ij}即第i個特徵層的第j個anchor,步長爲 s_{i},我們定義第 k 個 pyramid anchor 的標籤爲

 

gs2

{s_{pa}}^{k}是金字塔anchors的步長 (k = 0, 1, … , K),anchor_{ij}\cdot s_{i}表示 anchor_{ij}在原始圖像中對應的區域,anchor_{ij}\cdot s_{i}\cdot {s_{pa}}^{k}表示對應的以步長爲 {s_{pa}}^{k}進行下采樣的區域。閾值與其他基於 anchor 的檢測器相同。在我們的實驗中,設置超參數 s_{pa}=2,因爲相鄰的預測模塊的步長是 2。此外,設置 threshold = 0.35,K = 2。這樣 label0, label1, label2就分別是面部、頭部和身體的標籤。

 

來到⑤。如圖33,這裏主要是講怎麼用得到的Cls和Reg生成損失函數。

 

 

 

33
圖33

作爲對多邊框損失的一般化,我們將一張圖片的 PyramidBox 損失函數定義爲:

gs3

其中第 k 個 pyramid-anchor 損失是

其中 k 是 pyramid-anchors 的編號 (k = 0, 1, 2 分別表示面部、頭部和身體),i 是 anchor 的編號,p_{k,i} 表示 anchor i 是第 k 個目標 (面部、頭部或身體) 的預測概率。ground-truth 標籤定義爲

例如,當 k = 0 時,ground-truth 標籤等於 Fast R-CNN 中的標籤。當 k≥1 時,根據下采樣 anchors 和 ground-truth 人臉的匹配決定對應的標籤。此外,t_{k,i}是一個 4 維向量,表示預測得到的邊框的座標。t_{k,i}^{*}表示與一個陽性 anchor 相關聯的 ground-truth 邊框,定義爲

 

如圖34,臉部、頭部、身體的ground-truth 邊框是這樣被標註的。

 

34
圖33

是對 Fast R-CNN 的一個自然的泛化。分類損失 L_{k,cls}是有臉和無臉兩種類型間的對數損失。迴歸損失 L_{k,reg}是 Fast R-CNN 中定義的平滑 L1 損失。p_{k,i}^{*}\cdot L_{k,reg}意味着迴歸損失只在 anchors 爲陽性時被激活。兩項損失通過 N_{k,cls},N_{k,reg}歸一化,\lambda\lambda _{k}是平衡權重。

博客目前比較粗糙,後期會精化改善。謝謝瀏覽!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章