YOLOv5改进实战 | 更换损失函数(三)之MPDIOU(2023最新IOU)篇


YOLOv5改进实战 | 更换损失函数(三)之MPDIOU(2023最新IOU)篇_第1张图片


前言

本文使用的YOLOv5版本为v7.0,该版本为YOLOv5最新版本,默认损失函数采用的是CIoU。本章节主要介绍如何将MPDIoU损失函数应用于目标检测YOLOv5模型。


YOLOv5改进损失函数系列:

YOLOv5改进实战(1)| 更换损失函数(一)之EIoU、Alpha-IoU、SIoU篇
YOLOv5改进实战(2)| 更换损失函数(二)之WIOU(Wise IoU)篇
YOLOv5改进实战(3)| 更换损失函数(三)之MPDIOU(2023最新IOU)篇
YOLOv5改进实战(6)| 更换损失函数(四)之NWD(小目标检测)篇


目录

  • 一、MPDIoU
  • 二、代码实现
    • 添加损失函数
    • 更换MPDIoU

一、MPDIoU

论文链接:MPDIoU: A Loss for Efficient and Accurate Bounding Box Regression

MPDIoU是一种基于最小点距离的新型边界框相似度比较度量标准,直接最小化预测边界框与实际标注边界框之间的左上角和右下角点距离。MPDIoU包含了现有损失函数中考虑的所有相关因素,即重叠 或非重叠区域、中心点距离、宽高偏差,同时简化计算过程。
d 1 2 = ( x 1 p r d − x 1 g t ) 2 + ( y 1 p r d − y 1 g t ) 2 d_1^2=\left ( x_1^{prd} -x_1^{gt} \right ) ^2+\left ( y_1^{prd}-y_1^{gt} \right ) ^2 d12=(x1prdx1gt)2+(y1prdy1gt)2

d 2 2 = ( x 2 p r d − x 2 g t ) 2 + ( y 2 p r d − y 2 g t ) 2 d_2^2=\left ( x_2^{prd} -x_2^{gt} \right ) ^2+\left ( y_2^{prd}-y_2^{gt} \right ) ^2 d22=(x2prdx2gt)2+(y2prdy2gt)2

M P D I o U = I O U − d 1 2 w 2 + h 2 − d 2 2 w 2 + h 2 MPDIoU = IOU - \frac{d_1^2}{w^2+h^2} - \frac{d_2^2}{w^2+h^2} MPDIoU=IOUw2+h2d12w2+h2d22
YOLOv5改进实战 | 更换损失函数(三)之MPDIOU(2023最新IOU)篇_第2张图片
L M P D I o U = 1 − M P D I o U L_{MPDIoU} = 1 - MPDIoU LMPDIoU=1MPDIoU

二、代码实现

添加损失函数

  1. 更换损失函数主要修改metrics.py文件中的bbox_iou函数
    • 源代码如下:
      def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7):
         # Returns Intersection over Union (IoU) of box1(1,4) to box2(n,4)
      
         # Get the coordinates of bounding boxes
         if xywh:  # transform from xywh to xyxy
             (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1)
             w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2
             b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_
             b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_
         else:  # x1, y1, x2, y2 = box1
             b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, -1)
             b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, -1)
             w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
             w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
      
         # Intersection area
         inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \
                 (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0)
      
         # Union Area
         union = w1 * h1 + w2 * h2 - inter + eps
      
         # IoU
         iou = inter / union
         if CIoU or DIoU or GIoU:
             cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1)  # convex (smallest enclosing box) width
             ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1)  # convex height
             if CIoU or DIoU:  # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
                 c2 = cw ** 2 + ch ** 2 + eps  # convex diagonal squared
                 rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4  # center dist ** 2
                 if CIoU:  # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
                     v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2)
                     with torch.no_grad():
                         alpha = v / (v - iou + (1 + eps))
                     return iou - (rho2 / c2 + v * alpha)  # CIoU
                 return iou - rho2 / c2  # DIoU
             c_area = cw * ch + eps  # convex area
             return iou - (c_area - union) / c_area  # GIoU https://arxiv.org/pdf/1902.09630.pdf
         return iou  # IoU
      
    • 替换成以下代码
      def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, MDPIoU=False, hw=None, eps=1e-7):
          # Returns Intersection over Union (IoU) of box1(1,4) to box2(n,4)
          
          # Get the coordinates of bounding boxes
          if xywh:  # transform from xywh to xyxy
              (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, 1), box2.chunk(4, 1)
              w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2
              b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_
              b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_
          else:  # x1, y1, x2, y2 = box1
              b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, 1)
              b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, 1)
              w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1
              w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1
      
          # Intersection area
          inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \
                  (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0)
      
          # Union Area
          union = w1 * h1 + w2 * h2 - inter + eps
      
          # IoU
          iou = inter / union
          if CIoU or DIoU or GIoU:
              cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1)  # convex (smallest enclosing box) width
              ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1)  # convex height
              if CIoU or DIoU:  # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
                  c2 = cw ** 2 + ch ** 2 + eps  # convex diagonal squared
                  rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4  # center dist ** 2
                  if CIoU:  # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
                      v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / (h2 + eps)) - torch.atan(w1 / (h1 + eps)), 2)
                      with torch.no_grad():
                          alpha = v / (v - iou + (1 + eps))
                      return iou - (rho2 / c2 + v * alpha)  # CIoU
                  return iou - rho2 / c2  # DIoU
              c_area = cw * ch + eps  # convex area
              return iou - (c_area - union) / c_area  # GIoU https://arxiv.org/pdf/1902.09630.pdf
          elif MDPIoU:
              d1 = (b2_x1 - b1_x1) ** 2 + (b2_y1 - b1_y1) ** 2
              d2 = (b2_x2 - b1_x2) ** 2 + (b2_y2 - b1_y2) ** 2
              return iou - d1 / hw - d2 / hw  # MPDIoU
          return iou  # IoU
      

更换MPDIoU

按照上述更改metrics.py文件中的bbox_iou函数后,在utils/loss.py中,找到ComputeLoss类中的__call__()函数
YOLOv5改进实战 | 更换损失函数(三)之MPDIOU(2023最新IOU)篇_第3张图片

# MPDIoU
iou = bbox_iou(pbox, tbox[i], MDPIoU=True, hw=tobj.size()[2] * tobj.size()[3]).squeeze()

在这里插入图片描述

你可能感兴趣的:(YOLO改进系列,#,YOLOv5改进系列,YOLO)