目標檢測——yolov4損失函數


損失函數

yolo損失分為3個部分類別損失、置信度損失、位置損失

1. 類別損失

只有有目標的地方才會有類別判斷,從而才會有類別損失,所以需要解決兩個問題:1.有目標的地方;2.類別損失

1.1有目標的地方:object_mask

object_mask根據 y_true(真實值)確定,如何通過前處理編碼y_true,通過計算實際框(ground_truth)與anchor框的iou來確定

achor的9個框分為3組,分別負責下小目標(8倍下采樣)、中目標(16倍下采樣)、大目標(32倍下采樣) ,計算每個框與anchor框的iou,iou最大的anchor負責回歸這個真實框,

以13*13 (32倍下采樣)為例,整幅圖被分為13*13個gird,真實框的信息應該放在哪個grid里面呢?答案是真實框的中心落在哪個grid里面,這個grid就負責存儲這個框的所有信息,

包括(x, y, h, w),(confidence=1),(class)。object_mask,顧名思義,目標掩碼,即有目標的地方為true,所以 object_mask = y_true[l][..., 4:5]

2.1類別損失

類型損失,一般采用交叉熵損失,在目標檢測中,采用二元交叉熵損失,對每一個類別計算交叉熵損失,進行求和;

class_loss = object_mask * K.binary_crossentropy(true_class_prob, raw_pred[..., 5:], from_logits=True)
class_loss = K.sum(class_loss) / mf

此處為什么不采用softmax交叉熵損失呢?此處筆者也不清楚,歡迎有答案的同學留言交流。我猜測是因為各個類別之間相互獨立,不是非A即B的關系

所以沒有采用softmax,將所有類別的概率之和調整為1。

2.位置損失

目標檢測的一項重要任務就是確定目標的位置,即(x, y, h, w),所以損失值的計算中包含位置損失

通常計算位置損失有

1. L1 Loss 平均絕對誤差(Mean Absolute Error, MAE

梯度值為1或-1,在接近准確值時,會以learning_rate在准確值附近波動,比較難獲得准確效果

2. L2 Loss  均方誤差損失(Mean Square Error, MSE

在距離准確值較遠的地方梯度值較大,訓練初期收斂難度大,容易受到噪聲的干擾

3. Smooth L1 Loss

克服了以上兩種損失函數的缺點,但將x,y,h,w作為獨立的變量的看待,割裂了他們之間的相對關系

4. IoU Loss

考慮重合面積,可以較好的反應預測框和真實框的接近程度,但是但二者不相交時,損失值恆為1

5. GIoU Loss

考慮了不重合部分的面積對於損失的影響

6. DIoU Loss

考慮了中心點的偏移,即兩個框中心的距離與兩個框最遠距離的比值

7. CIoU Loss

考慮了長和寬的比值

在yoloV4中,采用了CIou Loss

def box_ciou(b1, b2):

    b1_xy = b1[..., :2]
    b1_wh = b1[..., 2:4]
    b1_wh_half = b1_wh / 2.

    b1_mins = b1_xy - b1_wh_half
    b1_maxes = b1_xy + b1_wh_half

    b2_xy = b2[..., :2]
    b2_wh = b2[..., 2:4]
    b2_wh_half = b2_wh / 2.

    b2_mins = b2_xy - b2_wh_half
    b2_maxes = b2_xy + b2_wh_half

    intersect_mins = K.maximum(b1_mins, b2_mins)
    intersect_maxes = K.minimum(b1_maxes, b2_maxes)

    intersect_wh = K.maximum(intersect_maxes-intersect_mins, 0.)
    # 兩個框相交部分面積
    intersect_area = intersect_wh[..., 0] * intersect_wh[..., 1]

    b1_area = b1_wh[..., 0] * b1_wh[..., 1]

    b2_area = b2_wh[..., 0] * b2_wh[..., 1]

    union_area = b1_area + b2_area - intersect_area
    # 兩個框的iou
    iou = intersect_area / K.maximum(union_area, K.epsilon())

    # 兩個框中心點的距離
    center_distance = K.sum(K.square((b1_xy - b2_xy)), axis=-1)

    enclose_mins = K.minimum(b1_mins, b2_mins)
    enclose_maxes = K.maximum(b1_maxes, b2_maxes)
    enclose_wh = K.maximum(enclose_maxes - enclose_mins, 0.0)
     
    # 兩個框的最遠距離
    enclose_diagonal = K.sum(K.square(enclose_wh), axis=-1)
   
    # 計算DIOU(CIOU的前半部分)
    ciou = iou - 1.0 * (center_distance) / K.maximum(enclose_diagonal, K.epsilon())
   
   # 計算兩個框的長寬比的差值的平方
    v = 4*K.square(tf.math.atan2(b1_wh[..., 0], K.maximum(b1_wh[..., 1],K.epsilon())) - tf.math.atan2(b2_wh[..., 0], K.maximum(b2_wh[..., 1],K.epsilon()))) / (math.pi * math.pi)

    alpha = v / K.maximum((1.0 - iou + v), K.epsilon())
    ciou = ciou - alpha * v

    ciou = K.expand_dims(ciou, -1)
    return ciou                                
ciou_loss = object_mask * box_loss_scale * (1 - ciou)
ciou_loss = K.sum(ciou_loss) / mf

其中 box_loss_scale 為 (2 - 對應真實框的面積),范圍為(1-2),當真實框的面積越大,box_loss_scale越小,意味着對大框的偏差容忍度越大。

解決了以上問題以后,我們還有一個重要問題沒有解決,預測框的(x, y, h, w)如何得到?

在yolo中,我們的(x,y)是通過對應grid左上角偏移得到;(h,w)是通過對對應anchor的長寬縮放得到,

box_xy = (K.sigmoid(feats[..., :2]) + grid) / K.cast(grid_shape[..., ::-1], K.dtype(feats))
box_wh = K.exp(feats[..., 2:4]) * anchors_tensor / K.cast(input_shape[..., ::-1], K.dtype(feats))

前半部分(斜體加粗),公式轉化如圖所示

 

后半部分,box_xy 除以grid_shape 將中心點坐標轉化為(0-1),與y_true中中心點的坐標的編碼對應,同樣轉化為(0-1),即中心點相對於輸入圖像的位置;同樣也是作歸一化處理;box_hw 除以input_shape 將長寬轉化為(0-1),與y_true中長寬的編碼對應。

3.置信度損失

置信度損失分為兩個部分,有目標的置信度損失,無目標的置信度損失

3.1 有目標的置信度損失

有目標的地方,即object_mask,

置信度損失:采用二元交叉熵損失

K.binary_crossentropy(object_mask, raw_pred[..., 4:5]

總的損失為

object_mask * K.binary_crossentropy(object_mask, raw_pred[..., 4:5], from_logits=True)

3.2 無目標的置信度損失

無目標的地方,即(1-object_mask)

(1 - object_mask) * K.binary_crossentropy(object_mask, raw_pred[..., 4:5], from_logits=True)

存在一個問題,因為一張圖中大部分是背景,即大部分是負樣本,如果所有的負樣本都參與計算,會極大的放大負樣本的損失,導致訓練結果偏向於負樣本,

所以在計算無目標的置信度損失時只會選擇部分負樣本,如何選擇負樣本?原則是計算預測值框和真實值框的iou,每個預測值的每個grid中都有三個框(以13*13)為例,每個真實值(一幅圖)中有那個框

依次計算iou,會得到(13*13*3*n)個iou,選取最大的iou作為預測值和真實值的iou,得到的維度為(13,13,3,1),設置一個iou閾值,小於此閾值的視為負樣本,其實質筆者認為是一種隨機取樣的方法。

def loop_body(b, ignore_mask):
    true_box = tf.boolean_mask(y_true[l][b, ..., 0:4], object_mask_bool[b, ..., 0])

    iou = box_iou(pred_box[b], true_box)

    best_iou = K.max(iou, axis=-1)

    # 13, 13, 3
    ignore_mask = ignore_mask.write(b, K.cast(best_iou<ignore_thresh, K.dtype(true_box)))

    return b+1, ignore_mask

得到ignore_mask ,所以無目標的置信度損失為:

confidence_loss = object_mask * K.binary_crossentropy(object_mask, raw_pred[..., 4:5], from_logits=True) + \
(1 - object_mask) * K.binary_crossentropy(object_mask, raw_pred[..., 4:5], from_logits=True) * ignore_mask
confidence_loss = K.sum(confidence_loss) / mf

所以最終的目標檢測損失為三者的損失之和:

loss += location_loss + confidence_loss + class_loss
 
        

 



 

 

 

 

 





免責聲明!

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



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