<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ?(附代碼)YOLOv4損失函數(shù)全面解析

          共 10223字,需瀏覽 21分鐘

           ·

          2021-05-31 20:35

          全網(wǎng)搜集目標(biāo)檢測文章,人工篩選最優(yōu)價值內(nèi)容

          編者薦語
          YOLO V4相較于YOLO V3做了很多小創(chuàng)新,堪稱目標(biāo)檢測tricks萬花筒。在了解YOLO V4結(jié)構(gòu)的前提下,根據(jù)網(wǎng)絡(luò)的輸出和標(biāo)簽信息進(jìn)行損失函數(shù)的設(shè)定,實現(xiàn)網(wǎng)絡(luò)參數(shù)的更新,一個完整的YOLO V4模型訓(xùn)練過程就可以被復(fù)現(xiàn)了。
          轉(zhuǎn)載自 | 計算機(jī)視覺聯(lián)盟

          1.前言



          如果您對YOLO V4的結(jié)構(gòu)比較感興趣,建議您可以結(jié)合代碼以及我的這篇文章進(jìn)行消化。代碼是基于Keras版本的,結(jié)構(gòu)很清晰,鏈接如下:

          YOLO V4 Keras:https:github.com/Ma-Dan/keras-yolo4


          YOLO V4原文中提到,在進(jìn)行bounding box regression的時候,傳統(tǒng)的目標(biāo)檢測模型(比如YOLO V3)等,都是直接根據(jù)預(yù)測框真實框中心點坐標(biāo)以及寬高信息設(shè)定MSE(均方誤差)損失函數(shù)的。為了方便大家理解,下面給出了YOLO V3的總損失函數(shù)。


          YOLO V3的損失函數(shù)


          可以看出,第一行的兩個,就是用在bounding box regression的損失函數(shù)MSE。有關(guān)該損失函數(shù)的具體解析可以見我文章《YOLO V3 深度解析 (下)》(https://zhuanlan.zhihu.com/p/138857662),這里就不進(jìn)行贅述。



          2. IOU損失函數(shù)理論部分



          鑒于MSE存在的一些問題,比如原文中提到

          However, to directly estimate the coordinate values of each point of the BBox is to treat these points as independent variables, but in fact does not consider the integrity of the object itself.

          意思就是MSE損失函數(shù)將檢測框中心點坐標(biāo)寬高等信息作為獨立的變量對待的,但是實際上他們之間是有關(guān)系的。從直觀上來說,框的中心點和寬高的確存在著一定的關(guān)系。所以解決方法是使用IOU損失代替MSE損失。

          接著作者就IOU損失依次提到了以下的一些的損失函數(shù)。


          • (1)IOU損失
          • (2)GIOU損失
          • (3)DIOU損失
          • (4)CIOU損失


          (1)IOU損失

          其中IOU損失定義非常簡單,即1與預(yù)測框A和真實框B之間交并比的差值



          但是這樣該損失函數(shù)會有一些問題,該損失函數(shù)只在bounding box重疊的時候才管用,在他們沒有重疊情況下,將不會提供滑動梯度。(這句話摘自論文《Distance-IoU Loss: Faster and Better Learning for Bounding Box Regression》)

          (2)GIOU損失

          其實GIOU的全稱叫做 :generalized IoU loss。提出來是為了緩解上述IOU損失在檢測框不重疊時出現(xiàn)的梯度問題。定義也是比較簡單的,就在在原來的IOU損失的基礎(chǔ)上加上一個懲罰項,公式如下:




          上式中A是預(yù)測框,B是真實框,C是A和B的最小包圍框,A,B,C的關(guān)系具體如下圖所示。



          A,B,C含義

          那么該懲罰項的意思就是下圖右邊黃色區(qū)域的比值。



          懲罰項含義

          雖然GIOU可以解決檢測框非重疊造成的梯度消失問題,但是他還存在以下的限制,這里我們依舊是參考CIOU論文中的內(nèi)容。



          GIOU回歸過程

          上圖中綠色真實框黑色先驗框Anchor藍(lán)色預(yù)測框。預(yù)測框是以先驗框為基礎(chǔ)進(jìn)行位置移動和大小縮放的。可以看出來,GIOU首先嘗試增大預(yù)測框的大小,使得它能夠與真實框有所重疊(如上圖中間所示),然后才能進(jìn)行上述公式中  的計算。那么這樣做的話,會消耗大量的時間在預(yù)測框嘗試與真實框接觸上,這會影響損失的收斂速度。所以DIOU和GIOU的提出解決了上述GIOU的問題。

          (3)DIOU

          DIOU和CIOU都出自論文《Distance-IoU Loss: Faster and Better Learning for Bounding Box Regression》(https://link.zhihu.com/?target=https%3A//arxiv.org/abs/1911.08287)。作者說他直接在IOU損失的基礎(chǔ)上加了一個簡單的懲罰項,用來最小化兩個檢測框中心點的標(biāo)準(zhǔn)化距離, 這樣可以加速損失的收斂過程。如下圖所示為GIOU和DIOU的對比。



          紅色框是DIOU損失中的預(yù)測框。可以很明顯的看出,DIOU的收斂速度較GIOU更快。

          那么有關(guān)DIOU的定義是怎么樣的呢?下面給出公式定義:




          相比于IOU損失,DIOU損失也多出了一個懲罰項  。該懲罰項具體的參數(shù)含義為


          • A : 預(yù)測框 B:真實框
          •  : 預(yù)測框中心點坐標(biāo)  :真實框中心點坐標(biāo)
          •  是歐式距離的計算
          • c 為 A , B 最小包圍框對角線長度


          我給出了下圖,便于大家理解。

          所以兩個框距離越遠(yuǎn),DIOU越接近2,距離越近,DIOU越接近0

          提出DIOU還不夠,作者進(jìn)一步地提出了CIOU(Complete IoU Loss)。

          (4)CIOU

          CIOU作者考慮的更加全面一些,DIOU考慮到了兩個檢測框的中心距離。而CIOU考慮到了三個幾何因素,分別為


          • (1)重疊面積
          • (2)中心點距離
          • (3)長寬比


          這里仔細(xì)觀察,會發(fā)現(xiàn),CIOU比DIOU多了一個長寬比的信息,那么CIOU的公式定義如下:




          那么這個  對長寬比的懲罰項了。論文中提到,  是一個正數(shù),  用來測量長寬比的一致性(v measures the consistency of aspect ratio)。具體定義如下:



          上述公式中,參數(shù)說明如下:


          •  和  為真實框的寬、高
          •  和  為預(yù)測框的寬、高


          若真實框和預(yù)測框的寬高相似,那么  為0,該懲罰項就不起作用了。所以很直觀地,這個懲罰項作用就是控制預(yù)測框的寬高能夠盡可能快速地與真實框的寬高接近。

          那么至此,有關(guān)YOLO V4損失函數(shù)的理論部分就說完了。

          3.IOU損失函數(shù)的實戰(zhàn)部分

          說完了上述四個IOU理論部分,我們回歸其在YOLO V4框架中的位置并進(jìn)行解析。結(jié)合keras的代碼,如下為CIOU損失函數(shù)的定義。

          def bbox_ciou(boxes1, boxes2):'''    計算ciou = iou - p2/c2 - av    :param boxes1: (8, 13, 13, 3, 4)   pred_xywh    :param boxes2: (8, 13, 13, 3, 4)   label_xywh    :return:


             舉例時假設(shè)pred_xywh和label_xywh的shape都是(1, 4)    '''


          # 變成左上角坐標(biāo)、右下角坐標(biāo)    boxes1_x0y0x1y1 = tf.concat([boxes1[..., :2] - boxes1[..., 2:] * 0.5,                                 boxes1[..., :2] + boxes1[..., 2:] * 0.5], axis=-1)    boxes2_x0y0x1y1 = tf.concat([boxes2[..., :2] - boxes2[..., 2:] * 0.5,                                 boxes2[..., :2] + boxes2[..., 2:] * 0.5], axis=-1)'''    逐個位置比較boxes1_x0y0x1y1[..., :2]和boxes1_x0y0x1y1[..., 2:],即逐個位置比較[x0, y0]和[x1, y1],小的留下。    比如留下了[x0, y0]    這一步是為了避免一開始w h 是負(fù)數(shù),導(dǎo)致x0y0成了右下角坐標(biāo),x1y1成了左上角坐標(biāo)。    '''    boxes1_x0y0x1y1 = tf.concat([tf.minimum(boxes1_x0y0x1y1[..., :2], boxes1_x0y0x1y1[..., 2:]),                                 tf.maximum(boxes1_x0y0x1y1[..., :2], boxes1_x0y0x1y1[..., 2:])], axis=-1)    boxes2_x0y0x1y1 = tf.concat([tf.minimum(boxes2_x0y0x1y1[..., :2], boxes2_x0y0x1y1[..., 2:]),                                 tf.maximum(boxes2_x0y0x1y1[..., :2], boxes2_x0y0x1y1[..., 2:])], axis=-1)


          # 兩個矩形的面積    boxes1_area = (boxes1_x0y0x1y1[..., 2] - boxes1_x0y0x1y1[..., 0]) * (                boxes1_x0y0x1y1[..., 3] - boxes1_x0y0x1y1[..., 1])    boxes2_area = (boxes2_x0y0x1y1[..., 2] - boxes2_x0y0x1y1[..., 0]) * (                boxes2_x0y0x1y1[..., 3] - boxes2_x0y0x1y1[..., 1])


          # 相交矩形的左上角坐標(biāo)、右下角坐標(biāo),shape 都是 (8, 13, 13, 3, 2)    left_up = tf.maximum(boxes1_x0y0x1y1[..., :2], boxes2_x0y0x1y1[..., :2])    right_down = tf.minimum(boxes1_x0y0x1y1[..., 2:], boxes2_x0y0x1y1[..., 2:])


          # 相交矩形的面積inter_area。iou    inter_section = tf.maximum(right_down - left_up, 0.0)    inter_area = inter_section[..., 0] * inter_section[..., 1]    union_area = boxes1_area + boxes2_area - inter_area    iou = inter_area / (union_area + K.epsilon())


          # 包圍矩形的左上角坐標(biāo)、右下角坐標(biāo),shape 都是 (8, 13, 13, 3, 2)    enclose_left_up = tf.minimum(boxes1_x0y0x1y1[..., :2], boxes2_x0y0x1y1[..., :2])    enclose_right_down = tf.maximum(boxes1_x0y0x1y1[..., 2:], boxes2_x0y0x1y1[..., 2:])


          # 包圍矩形的對角線的平方    enclose_wh = enclose_right_down - enclose_left_up    enclose_c2 = K.pow(enclose_wh[..., 0], 2) + K.pow(enclose_wh[..., 1], 2)


          # 兩矩形中心點距離的平方    p2 = K.pow(boxes1[..., 0] - boxes2[..., 0], 2) + K.pow(boxes1[..., 1] - boxes2[..., 1], 2)


          # 增加av。加上除0保護(hù)防止nan。    atan1 = tf.atan(boxes1[..., 2] / (boxes1[..., 3] + K.epsilon()))    atan2 = tf.atan(boxes2[..., 2] / (boxes2[..., 3] + K.epsilon()))    v = 4.0 * K.pow(atan1 - atan2, 2) / (math.pi ** 2)    a = v / (1 - iou + v)


             ciou = iou - 1.0 * p2 / enclose_c2 - 1.0 * a * v    return ciou

          以上,代碼原作者也是做了一個非常詳細(xì)的代碼注釋呀。可以看出,該函數(shù)定義和理論部分一致,特別是最后一行代碼,和我們理論部分說的一模一樣哈。

          ciou = iou - 1.0 * p2 / enclose_c2 - 1.0 * a * v

          該CIOU函數(shù)定義被用在求解總損失函數(shù)上了,我們知道YOLO V3的損失函數(shù)主要分為三部分,分別為:


          • (1)bounding box regression損失
          • (2)置信度損失
          • (3)分類損失


          YOLO V4相較于YOLO V3,只在bounding box regression做了創(chuàng)新,用CIOU代替了MSE,其他兩個部分沒有做實質(zhì)改變。其代碼分別定義如下:

          (1)bounding box regression損失

          def loss_layer(conv, pred, label, bboxes, stride, num_class, iou_loss_thresh):    conv_shape = tf.shape(conv)    batch_size = conv_shape[0]    output_size = conv_shape[1]    input_size = stride * output_size    conv = tf.reshape(conv, (batch_size, output_size, output_size,                             3, 5 + num_class))    conv_raw_prob = conv[:, :, :, :, 5:]


             pred_xywh = pred[:, :, :, :, 0:4]    pred_conf = pred[:, :, :, :, 4:5]


             label_xywh = label[:, :, :, :, 0:4]    respond_bbox = label[:, :, :, :, 4:5]    label_prob = label[:, :, :, :, 5:]


             ciou = tf.expand_dims(bbox_ciou(pred_xywh, label_xywh), axis=-1)  # (8, 13, 13, 3, 1)    input_size = tf.cast(input_size, tf.float32)


             # 每個預(yù)測框xxxiou_loss的權(quán)重 = 2 - (ground truth的面積/圖片面積)    bbox_loss_scale = 2.0 - 1.0 * label_xywh[:, :, :, :, 2:3] * label_xywh[:, :, :, :, 3:4] / (input_size ** 2)    ciou_loss = respond_bbox * bbox_loss_scale * (1 - ciou)  # 1. respond_bbox作為mask,有物體才計算xxxiou_loss

          (2)置信度損失

              


          # 2. respond_bbox作為mask,有物體才計算類別loss    prob_loss = respond_bbox * tf.nn.sigmoid_cross_entropy_with_logits(labels=label_prob, logits=conv_raw_prob)


          (3)分類損失    # 3. xxxiou_loss和類別loss比較簡單。重要的是conf_loss,是一個focal_loss    # 分兩步:第一步是確定 grid_h * grid_w * 3 個預(yù)測框 哪些作為反例;第二步是計算focal_loss。    expand_pred_xywh = pred_xywh[:, :, :, :, np.newaxis, :]  # 擴(kuò)展為(?, grid_h, grid_w, 3,   1, 4)    expand_bboxes = bboxes[:, np.newaxis, np.newaxis, np.newaxis, :, :]  # 擴(kuò)展為(?,      1,      1, 1, 150, 4)    iou = bbox_iou(expand_pred_xywh, expand_bboxes)  # 所有格子的3個預(yù)測框 分別 和 150個ground truth  計算iou。(?, grid_h, grid_w, 3, 150)    max_iou = tf.expand_dims(tf.reduce_max(iou, axis=-1), axis=-1)  # 與150個ground truth的iou中,保留最大那個iou。(?, grid_h, grid_w, 3, 1)


             # respond_bgd代表  這個分支輸出的 grid_h * grid_w * 3 個預(yù)測框是否是 反例(背景)    # label有物體,respond_bgd是0。沒物體的話:如果和某個gt(共150個)的iou超過iou_loss_thresh,respond_bgd是0;如果和所有g(shù)t(最多150個)的iou都小于iou_loss_thresh,respond_bgd是1。    # respond_bgd是0代表有物體,不是反例;權(quán)重respond_bgd是1代表沒有物體,是反例。    # 有趣的是,模型訓(xùn)練時由于不斷更新,對于同一張圖片,兩次預(yù)測的 grid_h * grid_w * 3 個預(yù)測框(對于這個分支輸出)  是不同的。用的是這些預(yù)測框來與gt計算iou來確定哪些預(yù)測框是反例。    # 而不是用固定大小(不固定位置)的先驗框。    respond_bgd = (1.0 - respond_bbox) * tf.cast(max_iou < iou_loss_thresh, tf.float32)


             # 二值交叉熵?fù)p失    pos_loss = respond_bbox * (0 - K.log(pred_conf + K.epsilon()))    neg_loss = respond_bgd  * (0 - K.log(1 - pred_conf + K.epsilon()))


             conf_loss = pos_loss + neg_loss    # 回顧respond_bgd,某個預(yù)測框和某個gt的iou超過iou_loss_thresh,不被當(dāng)作是反例。在參與“預(yù)測的置信位 和 真實置信位 的 二值交叉熵”時,這個框也可能不是正例(label里沒標(biāo)這個框是1的話)。這個框有可能不參與置信度loss的計算。    # 這種框一般是gt框附近的框,或者是gt框所在格子的另外兩個框。它既不是正例也不是反例不參與置信度loss的計算。(論文里稱之為ignore)


          最后對上述的三個損失取個平均即可,如下

              ciou_loss = tf.reduce_mean(tf.reduce_sum(ciou_loss, axis=[1, 2, 3, 4]))  # 每個樣本單獨計算自己的ciou_loss,再求平均值    conf_loss = tf.reduce_mean(tf.reduce_sum(conf_loss, axis=[1, 2, 3, 4]))  # 每個樣本單獨計算自己的conf_loss,再求平均值    prob_loss = tf.reduce_mean(tf.reduce_sum(prob_loss, axis=[1, 2, 3, 4]))  # 每個樣本單獨計算自己的prob_loss,再求平均值

          至此,結(jié)合代碼,有關(guān)YOLO V4損失函數(shù)的實戰(zhàn)部分也就說完了!



          4.小結(jié)



          本文結(jié)合了四個IOU損失理論定義,以及CIOU在YOLO V4中代碼定義,詳細(xì)地分析了DIOU損失CIOU損失。在當(dāng)前目標(biāo)檢測模型中,這樣的損失函數(shù)的確能夠提高模型的表現(xiàn),所以我認(rèn)為后面這種損失函數(shù)會大量替代MSE損失函數(shù)做bounding box regression,所以弄懂并理解它們是有必要的。


          ?------------------------------------------------

          雙一流大學(xué)研究生團(tuán)隊創(chuàng)建,一個專注于目標(biāo)檢測與深度學(xué)習(xí)的組織,希望可以將分享變成一種習(xí)慣。

           

          整理不易,點贊三連!

          瀏覽 62
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲视频在线播放免费 | 亚洲一区福利在线 | 亚洲欧美精品性爱 | 在线观看国产成人AV一天堂 | 黄色免费高清视频 |