| """Wise-IoU v1 动态聚焦权重 — 正确的 ultralytics 8.4.46 集成方式 |
| |
| ultralytics 8.4.46 的 BboxLoss.forward 直接用 iou 标量: |
| loss_iou = ((1.0 - iou) * weight).sum() / target_scores_sum |
| 不支持元组返回。因此 patch BboxLoss.forward,在 weight 中融入 β。 |
| """ |
| import torch |
| import torch.nn.functional as F |
|
|
|
|
| def _wise_beta(box1, box2, eps=1e-7): |
| """计算宽高比偏差动态聚焦系数 β,归一化使 batch 均值≈1。""" |
| b1_x1, b1_y1, b1_x2, b1_y2 = box1.unbind(-1) |
| b2_x1, b2_y1, b2_x2, b2_y2 = box2.unbind(-1) |
| w1 = (b1_x2 - b1_x1).clamp(min=eps) |
| h1 = (b1_y2 - b1_y1).clamp(min=eps) |
| w2 = (b2_x2 - b2_x1).clamp(min=eps) |
| h2 = (b2_y2 - b2_y1).clamp(min=eps) |
| rw = (w1 / w2).clamp(0.1, 10) |
| rh = (h1 / h2).clamp(0.1, 10) |
| raw = (rw - 1) ** 2 + (rh - 1) ** 2 |
| return (raw / (raw.mean() + eps)).detach().unsqueeze(-1) |
|
|
|
|
| def patch_wise_iou(): |
| """Patch BboxLoss.forward 以融入 Wise-IoU β 动态权重。 |
| |
| 只在 BboxLoss.forward 中把 weight 乘以 β,其余逻辑不变。 |
| 不替换 bbox_iou,依然使用 CIoU 作为 iou 值(更稳定)。 |
| """ |
| import ultralytics.utils.loss as los |
| from ultralytics.utils.loss import bbox_iou, bbox2dist, DFLoss |
| from ultralytics.utils.tal import dist2bbox |
|
|
| def _wise_forward( |
| self, |
| pred_dist, |
| pred_bboxes, |
| anchor_points, |
| target_bboxes, |
| target_scores, |
| target_scores_sum, |
| fg_mask, |
| imgsz, |
| stride, |
| ): |
| weight = target_scores.sum(-1)[fg_mask].unsqueeze(-1) |
| beta = _wise_beta(pred_bboxes[fg_mask], target_bboxes[fg_mask]) |
| weighted = weight * beta |
| iou = bbox_iou(pred_bboxes[fg_mask], target_bboxes[fg_mask], xywh=False, CIoU=True) |
| loss_iou = ((1.0 - iou) * weighted).sum() / target_scores_sum |
|
|
| if self.dfl_loss: |
| target_ltrb = bbox2dist(anchor_points, target_bboxes, self.dfl_loss.reg_max - 1) |
| loss_dfl = self.dfl_loss( |
| pred_dist[fg_mask].view(-1, self.dfl_loss.reg_max), |
| target_ltrb[fg_mask], |
| ) * weight |
| loss_dfl = loss_dfl.sum() / target_scores_sum |
| else: |
| target_ltrb = bbox2dist(anchor_points, target_bboxes) |
| target_ltrb = target_ltrb * stride |
| target_ltrb[..., 0::2] /= imgsz[1] |
| target_ltrb[..., 1::2] /= imgsz[0] |
| pred_dist = pred_dist * stride |
| pred_dist[..., 0::2] /= imgsz[1] |
| pred_dist[..., 1::2] /= imgsz[0] |
| loss_dfl = ( |
| F.l1_loss(pred_dist[fg_mask], target_ltrb[fg_mask], reduction="none").mean(-1, keepdim=True) * weight |
| ) |
| loss_dfl = loss_dfl.sum() / target_scores_sum |
|
|
| return loss_iou, loss_dfl |
|
|
| los.BboxLoss.forward = _wise_forward |
| print("[WiseIoU] BboxLoss.forward 已替换为 Wise-IoU v1 动态权重版本") |
|
|