
本文基于YOLOv13 官方仓库iMoonLab/yolov13ultralytics 8.3.63 fork实测整理Windows/CPU 环境全程可跑。损失函数不碰网络结构所以本篇与 v11 在数据通路层面高度一致但v13 的bbox_iou已经叠过一层 WIoU 补丁DIoU 分支被if DIoU:包住、内层if CIoU or DIoU扩展为包含 WIoUMPDIoU 是在这层修复之上再加分支改动点、插入位置、调用签名在 v13 里必须重新讲清楚。前言损失函数篇的 MPDIoUMinimum Point Distance IoU最小点距离交并比2023arxiv 2308.08962思路很清奇CIoU/DIoU/EIoU/SIoU 一路走来几何惩罚项越叠越多——中心距离、长宽比、宽高一致性全都要算。MPDIoU 反其道而行之把边界框退化成两个点左上角点和右下角点只最小化这两对点的距离。公式里没有atan、没有指数、没有包围框面积是所有 IoU 系列损失里计算最简单的一个。v13 角度的关键提醒本篇不是孤立的补丁而是叠加在上一篇 WIoU 补丁之上。v13 的 WIoU 修复已经把 DIoU 的返回包进if DIoU:分支、并把内层if CIoU or DIoU:扩展为if CIoU or DIoU or WIoU:MPDIoU 分支必须插在所有分支之后、return iou # IoU之前否则不会被命中。另外 v13 检测损失仍是ultralytics/utils/loss.py与 v11 一致bbox_iou仍位于ultralytics/utils/metrics.py所以这篇补丁直接在 v13 上生效。专栏目录YOLOv13改进目录一览含 v11 全系列专栏地址YOLO改进专栏——持续更新各方向即插即用改进一、MPDIoU 原理1.1 最小点距离把预测框 $B^{prd}$ 和真值框 $B^{gt}$ 各用两个点表示——左上角点$(x^l, y^l)$ 和右下角点$(x^r, y^r)$。定义两对点之间的归一化距离$$d_1^2 \frac{(x_1^l - x_2^l)^2 (y_1^l - y_2^l)^2}{h^2 w^2}, \qquad d_2^2 \frac{(x_1^r - x_2^r)^2 (y_1^r - y_2^r)^2}{h^2 w^2}$$其中 $h, w$ 是特征图 / 输入图像的尺寸归一化用本文实现默认feat_hfeat_w640。注意与论文一致分母是 $h^2 w^2$两维平方和的归一化不是单维。1.2 MPDIoU 计算公式$$MPDIoU IoU - d_1^2 - d_2^2$$直觉理解IoU 管重合得够不够两个最小点距离管角点对没对齐。当两框完全重合时 $d_1 d_2 0$MPDIoU 退化为纯 IoU框的位置或大小一旦有偏差会立刻体现在角点距离上。损失函数即 $L_{MPDIoU} 1 - MPDIoU$。v13 版强调三点它直接在bbox_iou内部完成与 CIoU/DIoU/WIoU 共享同一套b1_x1/b1_y1/b1_x2/b1_y2左上、右下坐标变量无需任何额外解析惩罚项按特征图尺寸 $h^2w^2$ 归一化因此feat_h/feat_w必须设成实际输入分辨率默认 640否则归一化口径失真计算量极小——只有两次坐标差的平方和、一次除法没有任何三角/指数运算对 v13 这种大检测头几乎零开销。二、v13 改动点三处MPDIoU 在 v13 上涉及metrics.py签名 分支 /loss.py/tal.py三处改动全部是纯损失侧不碰 yaml 与网络结构**ultralytics/utils/metrics.py**在bbox_iou已有 WIoU 补丁的基础上先扩展函数签名追加MPDIoUFalse, feat_h640, feat_w640再在最后一个return iou # IoU之前插入 MPDIoU 分支**ultralytics/utils/loss.py**BboxLoss.forward里把训练用的 IoU 调用从 CIoU 切到MPDIoUTruev13 检测损失文件与 v11 一致**ultralytics/utils/tal.py**Task-Aligned AssignerTAL正样本分配器里也用到了 IoU 度量必须同步改成MPDIoUTrue否则打分标准不一致会拖累分配质量。⚠️v13 新坑bbox_iou的 WIoU 补丁已经重排了分支顺序DIoU 被if DIoU:单独包住、内层if CIoU or DIoU or WIoU:。MPDIoU 用的是独立if MPDIoU:而非elif并且必须放在最末return iou之前因为它与 CIoU/DIoU/WIoU 互斥、又依赖前序算好的iou与角点坐标。放错位置会被前面的return短路跳过。三、完整补丁代码CODE BLOCK A —ultralytics/utils/metrics.py的bbox_iou签名WIoU 补丁之后签名已经带了 WIoU / scale 参数。在此基础上再扩展一次追加MPDIoUFalse, feat_h640, feat_w640- def bbox_iou(box1, box2, xywhTrue, GIoUFalse, DIoUFalse, CIoUFalse, WIoUFalse, scaleFalse, eps1e-7): def bbox_iou(box1, box2, xywhTrue, GIoUFalse, DIoUFalse, CIoUFalse, WIoUFalse, scaleFalse, MPDIoUFalse, feat_h640, feat_w640, eps1e-7):CODE BLOCK B — 在bbox_iou内、最终return iou # IoU之前插入分支if MPDIoU: # MPDIoU 最小点距离 https://arxiv.org/abs/2308.08962 mpdiou_hw_pow feat_h ** 2 feat_w ** 2 d1 (b2_x1 - b1_x1).pow(2) (b2_y1 - b1_y1).pow(2) d2 (b2_x2 - b1_x2).pow(2) (b2_y2 - b1_y2).pow(2) return iou - d1 / mpdiou_hw_pow - d2 / mpdiou_hw_pow注意这里用的是if而不是旧 v11 写法里的elif——因为 v13 的 WIoU 补丁已经把 DIoU/CIoU/WIoU 的分支结构重排MPDIoU 必须作为独立且最末的判断紧挨return iou。CODE BLOCK C —ultralytics/utils/loss.py的BboxLoss.forwardWIoU 补丁之后把训练用的 IoU 计算行改为如下单值返回不处理元组iou bbox_iou(pred_bboxes[fg_mask], target_bboxes[fg_mask], xywhFalse, MPDIoUTrue) loss_iou ((1.0 - iou) * weight).sum() / target_scores_sumCODE BLOCK D —ultralytics/utils/tal.py的 TAL 分配器把分配器里的bbox_iou调用从CIoUTrue改为MPDIoUTruereturn bbox_iou(gt_bboxes, pd_bboxes, xywhFalse, MPDIoUTrue).squeeze(-1).clamp_(0)三处改完即可训练无需任何模块注册——损失函数改进不碰网络结构正是它迁移成本最低的原因。四、成功运行结果训练命令Python 与 CLI 皆可yolo detect train modelyolov13n.yaml datamydata.yaml epochs100 imgsz640 batch16from ultralytics import YOLO model YOLO(yolov13n.yaml) model.train(datamydata.yaml, epochs100, imgsz640, batch16)本文在YOLOv13 官方仓库8.3.63 fork应用上述四段补丁后实测Windows / CPU冒烟验证✅ 断言 1 — 两框完全重合 (box1 box2): MPDIoU 1.0000 纯 IoU 1.0000 → 相等 (d1d20退化为纯 IoU) PASS ✅ 断言 2 — 预测框相对真值框偏移 50px (feat_hfeat_w640): MPDIoU 0.2439 纯 IoU 0.2500 → 0.2439 0.2500 PASS 点距离惩罚对未对齐框压低了分数符合公式预期 ✅ 断言 3 — YOLOv13n 基线仍可正常 build: YOLOv13n baseline: 2,494,151 params → 补丁不破坏模型 PASS✅三条断言全部通过① 重合时 MPDIoU 退化为纯 IoU1.0000 1.0000② 偏移 50px 时 MPDIoU 0.2439 严格低于纯 IoU 0.2500点距离惩罚生效③ YOLOv13n 基线构建照常参数量 2,494,151 与补丁前一致说明损失侧改动不影响结构。损失函数参数量增量计算特点v13 实测CIoU基线0三分量惩罚 atanWIoU v3前置补丁0动态非单调聚焦MPDIoU0最小点距离计算最简依赖 feat_h/feat_w 归一化⚠️重要提醒feat_h/feat_w默认640如果你的imgsz不是 640务必在bbox_iou调用处传实际值CLI/代码里统一口径否则归一化分母 $h^2w^2$ 失真MPDIoU 的惩罚幅度会偏强或偏弱。loss.py与tal.py两处调用都要传同样的数值保持训练损失与正样本分配打分标准一致。五、总结v13 上落地 MPDIoU 的三条核心 takeaways叠在 WIoU 补丁之上分支必须插在return iou # IoU之前、用独立if MPDIoU:不要写成elif否则被前面的 DIoU/CIoU/WIoU return 短路跳过三处联动metrics.py签名分支、loss.py训练损失、tal.py分配器三者都要切到MPDIoUTrue只改一处会打分标准不一致归一化口径要对齐输入分辨率feat_hfeat_w必须等于imgsz否则惩罚项尺度失真——零参数的代价是这一处超参必须手动保真。MPDIoU 用两个点重新定义了边界框回归的目标函数是奥卡姆剃刀式的改进砍掉全部复杂几何分量只留角点距离。它与 WIoU 代表损失改进的两个方向——WIoU 改权重分配MPDIoU 改几何度量两者在 v13 上甚至可以继续组合消融。专栏目录YOLOv13改进目录一览含 v11 全系列 专栏地址YOLO改进专栏——持续更新各方向即插即用改进觉得有帮助的话点赞收藏关注三连支持一下评论区欢迎交流你的实验结果~