基於keras的Yolov3最全詳解


參考Github源碼鏈接
Yolov3論文原文鏈接一,0二
Yolov3官網

最近在做Yolov3相關項目,看了很多資料。所以寫一篇總結體會,以便以后回顧查詢。

在這里插入圖片描述
YOLO,即 You Only Look Once 的縮寫,是一個基於卷積神經網絡(CNN)的目標檢測算法 。

yolo設計理念

yolo算法整體來說是采用CNN對目標進行end-to-end的檢測。流程如圖所示
在這里插入圖片描述
具體來說(基於YOLOV3)

  1. 輸入一張任意大小圖片,保持長寬比不變的情況下,縮放至 w 或 h達到416,再覆蓋在416 * 416的新圖上,作為網絡的輸入。即網絡的輸入是一張416 * 416,3通道的RGB圖。
  2. 運行網絡。YOLO的CNN網絡把圖片分成 S * S 個網格(yolov3多尺度預測,輸出3層,每層 S * S個網格,分別為13 * 13 ,26 * 26 ,52 * 52),然后每個單元格負責去檢測那些中心點落在該格子內的目標,如圖二所示。 每個單元格需要預測3*(4+1+B)個值。如果將輸入圖片划分為 SS 網格,那么每層最終預測值為 SS3(4+1+B) 大小的張量。類別數(coco集為80類),即B=80. 3 為每層anchorbox數量,4 為邊界框大小和位置(x , y , w ,h )1 為置信度。
  3. 通過NMS,非極大值抑制,篩選出框boxes,輸出框class_boxes和置信度class_box_scores,再生成類別信息classes,生成最終的檢測數據框,並返回

Yolov3網絡結構圖

在這里插入圖片描述

下面講一下訓練樣本的設置和loss的計算。

在這里插入圖片描述

訓練樣本設置

參考上面圖2,對於一個輸入圖像,比如4164163,相應的會輸出 13133 + 26263 + 52523 = 10647 個預測框。我們希望這些預測框的信息能夠盡量准確的反應出哪些位置存在對象,是哪種對象,其邊框位置在哪里。

在設置標簽y(10647個預測框 * (4+1+類別數) 張量)的時候,YOLO的設計思路是,對於輸入圖像中的每個對象,該對象實際邊框(groud truth)的中心落在哪個網格,就由該網格負責預測該對象。不過,由於設計了3種不同大小的尺度,每個網格又有3個先驗框,所以對於一個對象中心點,可以對應9個先驗框。但最終只選擇與實際邊框IOU最大的那個先驗框負責預測該對象(該先驗框的置信度=1),所有其它先驗框都不負責預測該對象(置信度=0)。同時,該先驗框所在的輸出向量中,邊框位置設置為對象實際邊框,以及該對象類型設置為1。

loss計算

loss主要有3個部分,置信度、邊框位置、對象類型。

首先需要注意的還是置信度的問題。上面說到對於一個實際對象,除了與它IOU最大的那個先驗框其置信度設為1,其它先驗框的置信度都是0。但是,還有一些先驗框與該對象實際邊框位置是比較接近的,它們依然有可能檢測到該對象,只不過並非最接近實際邊框。所以,這部分邊框的目標置信度不應該期望輸出0。但YOLO也不希望它們輸出1。所以,在計算loss的時候,就設置一個IOU閾值,超過閾值的(接近目標邊框但又不是IOU最大的)那些邊框不計入loss。低於閾值的那些邊框就要求置信度為0,也就是檢測到背景。

同時,對於檢測到對象的邊框,要計算其邊框位置的loss,以及對象類型的loss。對於那些檢測到背景的邊框,就只計算其置信度loss了,它的邊框位置和對象類型都沒有意義。

另外注意一下的是邊框位置計算要根據論文的設計做一些變換,參考下面圖。
在這里插入圖片描述

anchor box:

yolov3 anchor box一共有9個,由k-means聚類得到。在COCO數據集上,9個聚類是:(10 * 13);(16 * 30);(33 * 23);(30 * 61);(62 * 45); (59 * 119); (116 * 90); (156 * 198); (373 * 326)。

不同尺寸特征圖對應不同大小的先驗框。

13 * 13feature map對應【(116 * 90),(156 * 198),(373 * 326)】
26 * 26feature map對應【(30 * 61),(62 * 45),(59 * 119)】
52 * 52feature map對應【(10 * 13),(16 * 30),(33 * 23)】

原因:

  • 特征圖越大,感受野越小。對小目標越敏感,所以選用小的anchor box。
  • 特征圖越小,感受野越大。對大目標越敏感,所以選用大的anchor box。

邊框預測:

預測tx ty tw th

對tx和ty進行sigmoid,並加上對應的offset(下圖Cx, Cy)
對th和tw進行exp,並乘以對應的錨點值
對tx,ty,th,tw乘以對應的步幅,即:416/13, 416 ⁄ 26, 416 ⁄ 52
最后,使用sigmoid對Objectness和Classes confidence進行sigmoid得到0~1的概率,之所以用sigmoid取代之前版本的softmax,原因是softmax會擴大最大類別概率值而抑制其他類別概率值
在這里插入圖片描述

(tx,ty) :目標中心點相對於該點所在網格左上角的偏移量,經過sigmoid歸一化。即值屬於【0,1】。如圖約(0.3 , 0.4)

(cx,cy):該點所在網格的左上角距離最左上角相差的格子數。如圖(1,1)

(pw,ph):anchor box 的邊長

(tw,th):預測邊框的寬和高

PS:最終得到的邊框坐標值是bx,by,bw,bh.而網絡學習目標是tx,ty,tw,th

Loss

YOLOv3中有一個參數是ignore_thresh,在ultralytics版版的YOLOv3中對應的是train.py文件中的iou_t參數(默認為0.225)。
正負樣本是按照以下規則決定的:

  • 如果一個預測框與所有的Ground Truth的最大IoU<ignore_thresh時,那這個預測框就是負樣本。
  • 如果Ground Truth的中心點落在一個區域中,該區域就負責檢測該物體。將與該物體有最大IoU的預測框作為正樣本(注意這里沒有用到ignore thresh,即使該最大IoU<ignore thresh也不會影響該預測框為正樣本)

在YOLOv3中,Loss分為三個部分:

  • 一個是xywh部分帶來的誤差,也就是bbox帶來的loss ,在ultralytics版版的YOLOv3中,使用的是GIOU
  • 一個是置信度帶來的誤差,也就是obj帶來的loss。lobj代表置信度,即該bounding box中是否含有物體的概率。在yolov3代碼中obj loss可以通過arc來指定,有兩種模式:

如果采用default模式,使用BCEWithLogitsLoss,將obj loss和cls loss分開計算:

BCEobj = nn.BCEWithLogitsLoss(pos_weight=ft([h['obj_pw']]), reduction=red)
if 'default' in arc:  # separate obj and cls
    lobj += BCEobj(pi[..., 4], tobj)  # obj loss
    # pi[...,4]對應的是該框中含有目標的置信度,和giou計算BCE
    # 相當於將obj loss和cls loss分開計算

如果采用BCE模式,使用的也是BCEWithLogitsLoss, 計算對象是所有的cls loss:

BCE = nn.BCEWithLogitsLoss(reduction=red)
elif 'BCE' in arc:  # unified BCE (80 classes)
    t = torch.zeros_like(pi[..., 5:])  # targets
    if nb:
        t[b, a, gj, gi, tcls[i]] = 1.0 # 對應正樣本class置信度設置為1
        lobj += BCE(pi[..., 5:], t)#pi[...,5:]對應的是所有的class
  • 最后一個是類別帶來的誤差,也就是class帶來的loss。如果是單類的情況,cls loss=0,如果是多類的情況,也分兩個模式:

如果采用default模式,使用的是BCEWithLogitsLoss計算class loss。

BCEcls = nn.BCEWithLogitsLoss(pos_weight=ft([h['cls_pw']]), reduction=red)
# cls loss 只計算多類之間的loss,單類不進行計算
if 'default' in arc and model.nc > 1:
    t = torch.zeros_like(ps[:, 5:])  # targets
    t[range(nb), tcls[i]] = 1.0 # 設置對應class為1
    lcls += BCEcls(ps[:, 5:], t)  # 使用BCE計算分類loss

如果采用CE模式,使用的是CrossEntropy同時計算obj loss和cls loss。

CE = nn.CrossEntropyLoss(reduction=red)
elif 'CE' in arc:  # unified CE (1 background + 80 classes)
    t = torch.zeros_like(pi[..., 0], dtype=torch.long)  # targets
    if nb:
    t[b, a, gj, gi] = tcls[i] + 1 # 由於cls是從零開始計數的,所以+1
    lcls += CE(pi[..., 4:].view(-1, model.nc + 1), t.view(-1))
    # 這里將obj loss和cls loss一起計算,使用CrossEntropy Loss

三部分總結下來就是下圖:
在這里插入圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM