一、導言
在目標檢測任務中,損失函數的主要作用是衡量模型預測的邊界框(bounding boxes)與真實邊界框之間的匹配程度,并指導模型學習如何更精確地定位和分類目標。損失函數通常由兩部分構成:分類損失(用于判斷物體屬于哪個類別)和回歸損失(用于調整預測邊界框的位置和尺寸以更好地匹配真實目標)。一個好的損失函數能夠幫助模型快速且準確地收斂,提高檢測性能。
二、YOLO訓練中常見且有效的損失函數
1.SIOU (Sum of Intersection over Union)
SIOU不是一個廣泛認可的術語,但若假設這是對某種綜合IoU概念的提及,其潛在的優點可能在于嘗試結合不同IoU變體的優勢,比如同時考慮重疊區域、最小外包矩形、中心點距離等,以提供一個更全面的評估標準,可能在某些特定場景下提升檢測精度。
2.EIOU (Enhanced Intersection over Union)
EIOU是對IOU的一個增強版本,旨在進一步提升回歸損失的效果。它可能通過額外考慮邊界框尺寸、形狀或位置關系的度量,以更精細地引導邊界框的調整。EIOU的優點在于它能更有效地處理極端情況,如極度傾斜或部分重疊的目標,從而提高檢測的魯棒性和準確性。
3.DIOU (Distance Intersection over Union)
DIOU在傳統IOU的基礎上,加入了兩個邊界框中心點之間的歐幾里得距離,這有助于直接最小化預測框與真實框之間的距離,加快了收斂速度并改善了對密集對象和極端長寬比目標的檢測效果。其優點包括減少重疊區域之外的定位誤差,尤其在處理重疊少或無重疊情況時更為有效。
4.GIOU (Generalized Intersection over Union)
GIOU解決了IOU無法懲罰預測框未能完全覆蓋真實框的問題,通過計算預測框與真實框的最小外包矩形與它們交集的比值,促使預測框不僅盡可能重疊,而且形狀和大小也要更加接近真實框。GIOU的優點在于能有效引導框的擴展,尤其是在目標被嚴重遮擋或僅部分可見時,提升檢測的完整性。
5.CIOU (Complete Intersection over Union)
CIOU在GIOU的基礎上,進一步加入了邊界框中心點距離的懲罰項以及對寬高比的約束,形成了一個更為全面的損失函數。它不僅優化了重疊區域的測量,還解決了邊界框尺寸不一致的問題,從而在各種復雜場景下都能提供穩定的性能提升。CIOU的優點在于它是目前較為全面的回歸損失函數,能夠綜合考慮重疊、中心點距離和寬高比,提高了檢測的準確性和效率。
這些改進的IoU損失函數都是為了克服傳統IOU作為損失函數時存在的局限性,如只關注重疊區域而不考慮位置偏差或形狀不匹配的問題,通過不斷地優化,這些新提出的損失函數使得目標檢測系統的性能得到了顯著提升。
三、YOLOv7-tiny改進工作
了解二后,打開YOLOv7項目文件下的utils文件夾下的general.py,搜索def bbox_iou定位到如下行,
替換如下代碼為
class WIoU_Scale:''' monotonous: {None: origin v1True: monotonic FM v2False: non-monotonic FM v3}momentum: The momentum of running mean'''iou_mean = 1.monotonous = False # (false為v3,true為v2,none為v1)_momentum = 1 - 0.5 ** (1 / 7000)_is_train = Truedef __init__(self, iou):self.iou = iouself._update(self)@classmethoddef _update(cls, self):if cls._is_train: cls.iou_mean = (1 - cls._momentum) * cls.iou_mean + \cls._momentum * self.iou.detach().mean().item()@classmethoddef _scaled_loss(cls, self, gamma=1.9, delta=3):if isinstance(self.monotonous, bool):if self.monotonous:return (self.iou.detach() / self.iou_mean).sqrt()else:beta = self.iou.detach() / self.iou_meanalpha = delta * torch.pow(gamma, beta - delta)return beta / alphareturn 1def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, SIoU=False, EIoU=False, WIoU=False,Focal=False, alpha=1, gamma=0.5, scale=False, eps=1e-7):# Returns the IoU of box1 to box2. box1 is 4, box2 is nx4box2 = box2.T# Get the coordinates of bounding boxesif x1y1x2y2: # x1, y1, x2, y2 = box1b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3]b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3]else: # transform from xywh to xyxyb1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2# Intersection areainter = (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 Areaw1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + epsw2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + epsunion = w1 * h1 + w2 * h2 - inter + epsif scale:self = WIoU_Scale(1 - (inter / union))# IoU# iou = inter / union # ori iouiou = torch.pow(inter / (union + eps), alpha) # alpha iouif CIoU or DIoU or GIoU or EIoU or SIoU or WIoU:cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1) # convex (smallest enclosing box) widthch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1) # convex heightif CIoU or DIoU or EIoU or SIoU or WIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1c2 = (cw ** 2 + ch ** 2) ** alpha + eps # convex diagonal squaredrho2 = (((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4) ** alpha # center dist ** 2if CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47v = (4 / math.pi ** 2) * (torch.atan(w2 / h2) - torch.atan(w1 / h1)).pow(2)with torch.no_grad():alpha_ciou = v / (v - iou + (1 + eps))if Focal:return iou - (rho2 / c2 + torch.pow(v * alpha_ciou + eps, alpha)), torch.pow(inter / (union + eps),gamma) # Focal_CIoUelse:return iou - (rho2 / c2 + torch.pow(v * alpha_ciou + eps, alpha)) # CIoUelif EIoU:rho_w2 = ((b2_x2 - b2_x1) - (b1_x2 - b1_x1)) ** 2rho_h2 = ((b2_y2 - b2_y1) - (b1_y2 - b1_y1)) ** 2cw2 = torch.pow(cw ** 2 + eps, alpha)ch2 = torch.pow(ch ** 2 + eps, alpha)if Focal:return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2), torch.pow(inter / (union + eps),gamma) # Focal_EIouelse:return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2) # EIouelif SIoU:# SIoU Loss https://arxiv.org/pdf/2205.12740.pdfs_cw = (b2_x1 + b2_x2 - b1_x1 - b1_x2) * 0.5 + epss_ch = (b2_y1 + b2_y2 - b1_y1 - b1_y2) * 0.5 + epssigma = torch.pow(s_cw ** 2 + s_ch ** 2, 0.5)sin_alpha_1 = torch.abs(s_cw) / sigmasin_alpha_2 = torch.abs(s_ch) / sigmathreshold = pow(2, 0.5) / 2sin_alpha = torch.where(sin_alpha_1 > threshold, sin_alpha_2, sin_alpha_1)angle_cost = torch.cos(torch.arcsin(sin_alpha) * 2 - math.pi / 2)rho_x = (s_cw / cw) ** 2rho_y = (s_ch / ch) ** 2gamma = angle_cost - 2distance_cost = 2 - torch.exp(gamma * rho_x) - torch.exp(gamma * rho_y)omiga_w = torch.abs(w1 - w2) / torch.max(w1, w2)omiga_h = torch.abs(h1 - h2) / torch.max(h1, h2)shape_cost = torch.pow(1 - torch.exp(-1 * omiga_w), 4) + torch.pow(1 - torch.exp(-1 * omiga_h), 4)if Focal:return iou - torch.pow(0.5 * (distance_cost + shape_cost) + eps, alpha), torch.pow(inter / (union + eps), gamma) # Focal_SIouelse:return iou - torch.pow(0.5 * (distance_cost + shape_cost) + eps, alpha) # SIouelif WIoU:if Focal:raise RuntimeError("WIoU do not support Focal.")elif scale:return getattr(WIoU_Scale, '_scaled_loss')(self), (1 - iou) * torch.exp((rho2 / c2)), iou # WIoU https://arxiv.org/abs/2301.10051else:return iou, torch.exp((rho2 / c2)) # WIoU v1if Focal:return iou - rho2 / c2, torch.pow(inter / (union + eps), gamma) # Focal_DIoUelse:return iou - rho2 / c2 # DIoUc_area = cw * ch + eps # convex areaif Focal:return iou - torch.pow((c_area - union) / c_area + eps, alpha), torch.pow(inter / (union + eps),gamma) # Focal_GIoU https://arxiv.org/pdf/1902.09630.pdfelse:return iou - torch.pow((c_area - union) / c_area + eps, alpha) # GIoU https://arxiv.org/pdf/1902.09630.pdfif Focal:return iou, torch.pow(inter / (union + eps), gamma) # Focal_IoUelse:return iou # IoU
打開utils文件夾下的loss.py,搜索class ComputeLossOTA定位到如下行:
替換ComputeLossOTA下的該兩行為如下代碼
iou = bbox_iou(pbox.T, selected_tbox, x1y1x2y2=False, CIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, selected_tbox, x1y1x2y2=False, WIoU=True, scale=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, selected_tbox, x1y1x2y2=False, GIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, selected_tbox, x1y1x2y2=False, SIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, selected_tbox, x1y1x2y2=False, DIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, selected_tbox, x1y1x2y2=False, EIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, selected_tbox, x1y1x2y2=False, CIoU=True, Focal=True)#iou = bbox_iou(pbox.T, selected_tbox, x1y1x2y2=False, SIoU=True, Focal=True)#iou = bbox_iou(pbox.T, selected_tbox, x1y1x2y2=False, DIoU=True, Focal=True)#iou = bbox_iou(pbox.T, selected_tbox, x1y1x2y2=False, EIoU=True, Focal=True)#iou = bbox_iou(pbox.T, selected_tbox, x1y1x2y2=False, GIoU=True, Focal=True)if type(iou) is tuple:if len(iou) == 2:lbox += (iou[1].detach() * (1 - iou[0])).mean()iou = iou[0]else:lbox += (iou[0] * iou[1]).mean()iou = iou[-1]else:lbox += (1.0 - iou).mean() # iou loss
使用時,取消掉不要的注釋即可(如base是CIOU,你想使用SIOU,注釋掉CIOU這行,SIOU那行取消注釋即可)。
四、YOLOv7改進工作
?了解二后,打開YOLOv7項目文件下的utils文件夾下的general.py,搜索def bbox_iou定位到如下行,
替換如下代碼為
class WIoU_Scale:''' monotonous: {None: origin v1True: monotonic FM v2False: non-monotonic FM v3}momentum: The momentum of running mean'''iou_mean = 1.monotonous = False # (false為v3,true為v2,none為v1)_momentum = 1 - 0.5 ** (1 / 7000)_is_train = Truedef __init__(self, iou):self.iou = iouself._update(self)@classmethoddef _update(cls, self):if cls._is_train: cls.iou_mean = (1 - cls._momentum) * cls.iou_mean + \cls._momentum * self.iou.detach().mean().item()@classmethoddef _scaled_loss(cls, self, gamma=1.9, delta=3):if isinstance(self.monotonous, bool):if self.monotonous:return (self.iou.detach() / self.iou_mean).sqrt()else:beta = self.iou.detach() / self.iou_meanalpha = delta * torch.pow(gamma, beta - delta)return beta / alphareturn 1def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, SIoU=False, EIoU=False, WIoU=False,Focal=False, alpha=1, gamma=0.5, scale=False, eps=1e-7):# Returns the IoU of box1 to box2. box1 is 4, box2 is nx4box2 = box2.T# Get the coordinates of bounding boxesif x1y1x2y2: # x1, y1, x2, y2 = box1b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3]b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3]else: # transform from xywh to xyxyb1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2# Intersection areainter = (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 Areaw1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + epsw2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + epsunion = w1 * h1 + w2 * h2 - inter + epsif scale:self = WIoU_Scale(1 - (inter / union))# IoU# iou = inter / union # ori iouiou = torch.pow(inter / (union + eps), alpha) # alpha iouif CIoU or DIoU or GIoU or EIoU or SIoU or WIoU:cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1) # convex (smallest enclosing box) widthch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1) # convex heightif CIoU or DIoU or EIoU or SIoU or WIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1c2 = (cw ** 2 + ch ** 2) ** alpha + eps # convex diagonal squaredrho2 = (((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4) ** alpha # center dist ** 2if CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47v = (4 / math.pi ** 2) * (torch.atan(w2 / h2) - torch.atan(w1 / h1)).pow(2)with torch.no_grad():alpha_ciou = v / (v - iou + (1 + eps))if Focal:return iou - (rho2 / c2 + torch.pow(v * alpha_ciou + eps, alpha)), torch.pow(inter / (union + eps),gamma) # Focal_CIoUelse:return iou - (rho2 / c2 + torch.pow(v * alpha_ciou + eps, alpha)) # CIoUelif EIoU:rho_w2 = ((b2_x2 - b2_x1) - (b1_x2 - b1_x1)) ** 2rho_h2 = ((b2_y2 - b2_y1) - (b1_y2 - b1_y1)) ** 2cw2 = torch.pow(cw ** 2 + eps, alpha)ch2 = torch.pow(ch ** 2 + eps, alpha)if Focal:return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2), torch.pow(inter / (union + eps),gamma) # Focal_EIouelse:return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2) # EIouelif SIoU:# SIoU Loss https://arxiv.org/pdf/2205.12740.pdfs_cw = (b2_x1 + b2_x2 - b1_x1 - b1_x2) * 0.5 + epss_ch = (b2_y1 + b2_y2 - b1_y1 - b1_y2) * 0.5 + epssigma = torch.pow(s_cw ** 2 + s_ch ** 2, 0.5)sin_alpha_1 = torch.abs(s_cw) / sigmasin_alpha_2 = torch.abs(s_ch) / sigmathreshold = pow(2, 0.5) / 2sin_alpha = torch.where(sin_alpha_1 > threshold, sin_alpha_2, sin_alpha_1)angle_cost = torch.cos(torch.arcsin(sin_alpha) * 2 - math.pi / 2)rho_x = (s_cw / cw) ** 2rho_y = (s_ch / ch) ** 2gamma = angle_cost - 2distance_cost = 2 - torch.exp(gamma * rho_x) - torch.exp(gamma * rho_y)omiga_w = torch.abs(w1 - w2) / torch.max(w1, w2)omiga_h = torch.abs(h1 - h2) / torch.max(h1, h2)shape_cost = torch.pow(1 - torch.exp(-1 * omiga_w), 4) + torch.pow(1 - torch.exp(-1 * omiga_h), 4)if Focal:return iou - torch.pow(0.5 * (distance_cost + shape_cost) + eps, alpha), torch.pow(inter / (union + eps), gamma) # Focal_SIouelse:return iou - torch.pow(0.5 * (distance_cost + shape_cost) + eps, alpha) # SIouelif WIoU:if Focal:raise RuntimeError("WIoU do not support Focal.")elif scale:return getattr(WIoU_Scale, '_scaled_loss')(self), (1 - iou) * torch.exp((rho2 / c2)), iou # WIoU https://arxiv.org/abs/2301.10051else:return iou, torch.exp((rho2 / c2)) # WIoU v1if Focal:return iou - rho2 / c2, torch.pow(inter / (union + eps), gamma) # Focal_DIoUelse:return iou - rho2 / c2 # DIoUc_area = cw * ch + eps # convex areaif Focal:return iou - torch.pow((c_area - union) / c_area + eps, alpha), torch.pow(inter / (union + eps),gamma) # Focal_GIoU https://arxiv.org/pdf/1902.09630.pdfelse:return iou - torch.pow((c_area - union) / c_area + eps, alpha) # GIoU https://arxiv.org/pdf/1902.09630.pdfif Focal:return iou, torch.pow(inter / (union + eps), gamma) # Focal_IoUelse:return iou # IoU
打開utils文件夾下的loss.py,搜索class ComputeLoss:定位到如下行:
?
替換該兩行為如下代碼
iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, CIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, WIoU=True, scale=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, GIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, SIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, DIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, EIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, CIoU=True, Focal=True)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, SIoU=True, Focal=True)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, DIoU=True, Focal=True)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, EIoU=True, Focal=True)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, GIoU=True, Focal=True)if type(iou) is tuple:if len(iou) == 2:lbox += (iou[1].detach() * (1 - iou[0])).mean()iou = iou[0]else:lbox += (iou[0] * iou[1]).mean()iou = iou[-1]else:lbox += (1.0 - iou).mean() # iou loss
使用時,取消掉不要的注釋即可(如base是CIOU,你想使用SIOU,注釋掉CIOU這行,SIOU那行取消注釋即可)。
五、YOLOv5改進工作
了解二后,打開YOLOv5項目文件下的utils文件夾下的metrics.py,搜索def bbox_iou定位到如下行,
將該函數替換為如下代碼
class WIoU_Scale:''' monotonous: {None: origin v1True: monotonic FM v2False: non-monotonic FM v3}momentum: The momentum of running mean'''iou_mean = 1.monotonous = False # (false為v3,true為v2,none為v1)_momentum = 1 - 0.5 ** (1 / 7000)_is_train = Truedef __init__(self, iou):self.iou = iouself._update(self)@classmethoddef _update(cls, self):if cls._is_train: cls.iou_mean = (1 - cls._momentum) * cls.iou_mean + \cls._momentum * self.iou.detach().mean().item()@classmethoddef _scaled_loss(cls, self, gamma=1.9, delta=3):if isinstance(self.monotonous, bool):if self.monotonous:return (self.iou.detach() / self.iou_mean).sqrt()else:beta = self.iou.detach() / self.iou_meanalpha = delta * torch.pow(gamma, beta - delta)return beta / alphareturn 1def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, SIoU=False, EIoU=False, WIoU=False,Focal=False, alpha=1, gamma=0.5, scale=False, eps=1e-7):# Returns the IoU of box1 to box2. box1 is 4, box2 is nx4box2 = box2.T# Get the coordinates of bounding boxesif x1y1x2y2: # x1, y1, x2, y2 = box1b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3]b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3]else: # transform from xywh to xyxyb1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2# Intersection areainter = (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 Areaw1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + epsw2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + epsunion = w1 * h1 + w2 * h2 - inter + epsif scale:self = WIoU_Scale(1 - (inter / union))# IoU# iou = inter / union # ori iouiou = torch.pow(inter / (union + eps), alpha) # alpha iouif CIoU or DIoU or GIoU or EIoU or SIoU or WIoU:cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1) # convex (smallest enclosing box) widthch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1) # convex heightif CIoU or DIoU or EIoU or SIoU or WIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1c2 = (cw ** 2 + ch ** 2) ** alpha + eps # convex diagonal squaredrho2 = (((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4) ** alpha # center dist ** 2if CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47v = (4 / math.pi ** 2) * (torch.atan(w2 / h2) - torch.atan(w1 / h1)).pow(2)with torch.no_grad():alpha_ciou = v / (v - iou + (1 + eps))if Focal:return iou - (rho2 / c2 + torch.pow(v * alpha_ciou + eps, alpha)), torch.pow(inter / (union + eps),gamma) # Focal_CIoUelse:return iou - (rho2 / c2 + torch.pow(v * alpha_ciou + eps, alpha)) # CIoUelif EIoU:rho_w2 = ((b2_x2 - b2_x1) - (b1_x2 - b1_x1)) ** 2rho_h2 = ((b2_y2 - b2_y1) - (b1_y2 - b1_y1)) ** 2cw2 = torch.pow(cw ** 2 + eps, alpha)ch2 = torch.pow(ch ** 2 + eps, alpha)if Focal:return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2), torch.pow(inter / (union + eps),gamma) # Focal_EIouelse:return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2) # EIouelif SIoU:# SIoU Loss https://arxiv.org/pdf/2205.12740.pdfs_cw = (b2_x1 + b2_x2 - b1_x1 - b1_x2) * 0.5 + epss_ch = (b2_y1 + b2_y2 - b1_y1 - b1_y2) * 0.5 + epssigma = torch.pow(s_cw ** 2 + s_ch ** 2, 0.5)sin_alpha_1 = torch.abs(s_cw) / sigmasin_alpha_2 = torch.abs(s_ch) / sigmathreshold = pow(2, 0.5) / 2sin_alpha = torch.where(sin_alpha_1 > threshold, sin_alpha_2, sin_alpha_1)angle_cost = torch.cos(torch.arcsin(sin_alpha) * 2 - math.pi / 2)rho_x = (s_cw / cw) ** 2rho_y = (s_ch / ch) ** 2gamma = angle_cost - 2distance_cost = 2 - torch.exp(gamma * rho_x) - torch.exp(gamma * rho_y)omiga_w = torch.abs(w1 - w2) / torch.max(w1, w2)omiga_h = torch.abs(h1 - h2) / torch.max(h1, h2)shape_cost = torch.pow(1 - torch.exp(-1 * omiga_w), 4) + torch.pow(1 - torch.exp(-1 * omiga_h), 4)if Focal:return iou - torch.pow(0.5 * (distance_cost + shape_cost) + eps, alpha), torch.pow(inter / (union + eps), gamma) # Focal_SIouelse:return iou - torch.pow(0.5 * (distance_cost + shape_cost) + eps, alpha) # SIouelif WIoU:if Focal:raise RuntimeError("WIoU do not support Focal.")elif scale:return getattr(WIoU_Scale, '_scaled_loss')(self), (1 - iou) * torch.exp((rho2 / c2)), iou # WIoU https://arxiv.org/abs/2301.10051else:return iou, torch.exp((rho2 / c2)) # WIoU v1if Focal:return iou - rho2 / c2, torch.pow(inter / (union + eps), gamma) # Focal_DIoUelse:return iou - rho2 / c2 # DIoUc_area = cw * ch + eps # convex areaif Focal:return iou - torch.pow((c_area - union) / c_area + eps, alpha), torch.pow(inter / (union + eps),gamma) # Focal_GIoU https://arxiv.org/pdf/1902.09630.pdfelse:return iou - torch.pow((c_area - union) / c_area + eps, alpha) # GIoU https://arxiv.org/pdf/1902.09630.pdfif Focal:return iou, torch.pow(inter / (union + eps), gamma) # Focal_IoUelse:return iou # IoU
打開utils文件夾下的loss.py,搜索ciou
替換該兩行為
iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, CIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, WIoU=True, scale=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, GIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, SIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, DIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, EIoU=True) # iou(prediction, target)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, CIoU=True, Focal=True)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, SIoU=True, Focal=True)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, DIoU=True, Focal=True)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, EIoU=True, Focal=True)#iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, GIoU=True, Focal=True)if type(iou) is tuple:if len(iou) == 2:lbox += (iou[1].detach() * (1 - iou[0])).mean()iou = iou[0]else:lbox += (iou[0] * iou[1]).mean()iou = iou[-1]else:lbox += (1.0 - iou).mean() # iou loss
使用時,取消掉不要的注釋即可(如base是CIOU,你想使用SIOU,注釋掉CIOU這行,SIOU那行取消注釋即可)。
六、一些注意的點
采用WIOU進行訓練時,默認采用的是WIOUv3
想要訓練WIOUv1、v2時將該行改為none、true即可。
更多文章產出中,主打簡潔和準確,歡迎關注我,共同探討!