對三層作監督,分別重點檢測大中小物體。
如果從未接觸過檢測算法,一定會對YOLOv3有別於其它CNN的諸多方面深表驚奇。驚奇可能意味着巧妙,也可能意味着不合理或者局限。在YOLOv3身上二者兼備。
Output and loss
需要監督的輸出層如下。The shape of the detection kernel is 1 x 1 x (B x (5 + C) ).
這里有如下令人驚奇之處。
- 輸出格式。訓練,總是把預測輸出與ground truth作比對。我們通常碰到的任務,一個樣本通常只(預測)輸出一個值,例如,分類中的類別,回歸中的實值。而YOLOv3的預測輸出N個結構(可以把它理解為c語言的struct),N= cell number * B個,其中B一個cell能預測的bounding box數目(即每一層的anchor數目,實現中一般是取為3)。cell number三層分別為13*13, 26*26, 52*52。結構中有3類成員:bounding box attributes (x, y, w, h),置信度,類別。總共有(5+C)個,5是4 bounding box attributes and one object confidence,C是類個數。
- feature map用途。通常CNN的feature map往往只存在hidden層,最后在輸出層通過full connection層或者average polling層轉換為vector。而YOLOv3的feature map直接作為輸出。通常不同channel用於表示圖像的不同特征。而YOLOv3的不同channel不僅可以表達是圖像特征,例如人、車這種類別,還可以表達坐標和置信度。
很多情況下,我們不創新,並不是沒有想法,而是沒有想到可以這么實現。有時,我們說,在網絡結構上改進余地不大,但在怎么使用網絡來作表征上,YOLOv3大大拓寬了我們的思路。
以上說過,YOLOv3的輸出結構中有3個,bbox attribute, object confidence, class score。loss就是以上三部分的加權和,其中bbox attribute (x, y, w, h)用MSE,后二者用交叉熵。
看起來比較簡單,里面還是有些trick。
首先,output有cell number * B(對第一層是13*13*3)個這樣的結構,而ground truth才有目標個數(假定對一幅圖的最大檢測目標個數為20)個。13*13*3與20如何作MSE或者交叉熵?通常我們能想到的是,對13*13*3作某種grouping算法得出與ground truth相同shape的scalar或者tensor與ground truth比較。但YOLOv3的作法正好與此相反,是為20個找到13*13*3個格子中的20格,來安放ground truth,然后把其余格子全部置0。如何找到這些格子呢?對於width和height這2個維度很容易,就是根據中心點重合。而對於depth(即B)這個維度,它是找到與gound truth的bbox有最大IOU的anchor box對應的格式。這里第一處用到IOU。它有一個局限,一個格子只能容納一個目標。假如一個人坐在一張椅子上,中心位置和寬高大小比例都相若,本來同屬於一個格子,那么即使打標時打了2個標,在訓練時,也只有一個標(樣本)會生效,后面一個樣本會覆蓋前面一個樣本。從設計上就注定了訓練時的這種局限。不過,這不是什么大問題,頂多就是浪費了一個訓練樣本而已。那么在預測時,能否檢測出2個來?設計上是可以的,因為結構中包括了C個class score。但我看到的有的編碼實現都只保留class score最大的那個,這是可以作微改進的。
其次,不知你有沒有注意到,object confidence有點奇怪,不僅算法奇怪,它的存在就很奇怪。BBOX可以用回歸,class可以用交叉熵,怎么突然冒出個confidence?它是對目標從屬於哪個格子的confidence,還是對(x, y, w, h)的值的confidence?YOLOv1論文上有解釋,These confidence scores reflect how confident the model is that the box contains an object and also how accurate it thinks the box is that it predicts. Formally we define confidence as Po * IOU.
在計算confidence的loss時,對於正樣本(即該格子有目標),計交叉熵,這很正常。對於負樣本(即該格子沒有目標),只有bbox與ground truth的IOU小於閾值ignore threshold(通常取為0.5),才計交叉熵。這里第一處用到threshold,第二處用到IOU。為啥對正負樣本區別對待呢?我的理解是,對於有目標的格子,如果預測出有目標的可能性低,即輸出值的Po小,不正常,需要作懲罰。而對於沒目標的格子,如果預測出有目標的可能性高,即輸出值的Po高,這有可能是正常的,因為目標的中心點不在這個格子,可能在附近的格子,是否需要懲罰要視情況而定。如果IOU小於閾值,說明附近的格子沒有目標,Po高不正常,需要懲罰,即參與計算交叉熵。大於閾值,說明附近的格子有目標,Po高正常,不需要處罰,即計算交叉熵時忽略。這一點與我看到的文章的說法以及同事們的看法正好相反,而與我理解的keras代碼和pytorch代碼一致。
這里還有一個問題,上文中提到,對於沒有包含目標的格子,它的5+C全部置0,因此bbox也為0,那如何計算它與預測輸出的bbox的IOU呢?實際上,此處計算IOU時,它不是與本格子的ground truth的bbox計算IOU,而是與所有目標的bbox都計算IOU,並取最大值。YOLOv1論文上的這段話the confidence prediction represents the IOU between the predicted box and any ground truth box.證實了該解釋。
總結一下loss公式。
loss = bbox loss + confidence loss + class loss
bbox loss =
其中,bx, by, bw, bh是我們預測的x,y中心坐標,寬度和高度。lx, ly, lw, lh是ground truth的x,y中心坐標,寬度和高度。 代表該格子是否有目標,有為1,無為0。
confidence loss =
其中,同上,分別為object confidence的ground truth和預測輸出的概率,為二者的交叉熵,m為mask,即如上段中所說,正樣本恆為1,負樣本依條件而0或1。
class loss =
其中,同上,C為類個數,p(c), q(c)分別為各類的ground truth和預測輸出的概率,KL同上。
盡管在道理上解釋得通,我覺得不太合理,一方面過於復雜,另一方面多了個超參ignore threshold。也許有簡潔的改進方案,object confidence這個loss可以反過來算,不是把預測輸出值與ground truth雙方統一到格子上,而是統一到目標(即最多20個)上來。
最后再提醒一下,一個沒有被ground truth占的格子,它不參與計算BBOX的loss和class的loss,但參與計算object confidence的loss。
預測
For an image of size 416 x 416, YOLO predicts ((52 x 52) + (26 x 26) + 13 x 13)) x 3 = 10647 bounding boxes. 這么多個預測輸出如何縮減到目標個數呢?經過2道工序。
- object confidence threshold
過濾掉小於object confidence threshold的格子。這里第二處用到threshold。
- NMS,即Non-maximum Suppression
大名鼎鼎的NMS的目的是消除掉不同格子中預測出的同一個目標。
一般介紹Non-Maximum Suppression的文章會這樣介紹NMS算法。首先,NMS計算出每一個bounding box的面積,然后根據score進行排序,把score最大的bounding box作為隊列中。(這里的score = object confidence * class score, class score實際是指P(Class | Object), 因此P(Class) = P(Object) * P(Class | Object))接下來,計算其余bounding box與當前最大score與box的IoU,去除IoU大於設定的nms threshold的bounding box。這里第三處用到IOU和threshold。然后重復上面的過程,直至候選bounding box為空。
NMS就這么簡單?有沒有忽略了什么重要的東西?會不會發生這種情況,過於鄰近的N個目標中N-1個被無辜地過濾掉?為了防止這種可能,NMS在過濾時分類過濾的,即在同一個類的檢測輸出中執行上述算法。即便如此,仍然避免不了過於鄰近的N個同類目標中N-1個被無辜地過濾掉。這是另一個局限。
順便說一下,NMS僅用於預測,並未用於訓練。
anchor box
我們面臨2個疑問
- 為何需要有anchor box?
It might make sense to predict the width and the height of the bounding box, but in practice, that leads to unstable gradients during training.
因此,需要pre-defined default bounding box作為錨點。
bx,by,bw,bh是我們預測的x,y中心坐標,寬度和高度。 tx,ty,tw,th是網絡輸出的內容。 cx和cy是網格的左上角坐標。 pw和ph是anchor box的寬度和高度。
- anchor box是怎么來的?
Instead of choosing priors by hand, we run k-means clustering on the training set bounding boxes to automatically find good priors.
k-means無論是算中心還是重新選擇cluster,都會用到距離,我們通常見到的距離是歐氏距離。但這里是BBOX,BBOX間怎么算距離呢?
d(box; centroid) = 1 - IOU(box; centroid)。這是第四處用到IOU。
YOLOv3整個思路讓人匪夷所思。正如它的名字,You Only Look Once,它不是先切割再分類。實際上,它是根據中心的一個格子來預測它的BBOX和分類,這怎么可能呢?