yolov8的nms中multi-label功能为什么不是真正的multi-label(补充)

上文详解yolov8的nms中multi-label功能为什么不是真正的multi-label任务实现说到在yolov8的detection训练过程都是以每个像素最大面积真实目标框来作为loss的target来计算损失率和训练的,所以无法对重叠的多类别框进行训练,即使由nms产生的multi-label框,也不是真正的multi-label网络。

        训练过程中,决定是否同时训练两个标签的是标签分配策略TaskAlignedAssigner过程。标签分配最关键的一步是select_highest_overlaps函数,它将获得在每个像素点上面积最大的唯一GT,target_gt_idx。往后target_labels, target_bboxes, target_scores都由self.get_targets函数产生。
        那么在select_highest_overlaps函数中是什么决定或产生了最后的target_gt_idx呢?在代码中可以很明显看出:
        

def select_highest_overlaps(mask_pos, overlaps, n_max_boxes):
    # (b, n_max_boxes, h*w) -> (b, h*w)
    fg_mask = mask_pos.sum(-2)
    if fg_mask.max() > 1:  # one anchor is assigned to multiple gt_bboxes
        mask_multi_gts = (fg_mask.unsqueeze(1) > 1).repeat([1, n_max_boxes, 1])  # (b, n_max_boxes, h*w)
        max_overlaps_idx = overlaps.argmax(1)  # (b, h*w)
        is_max_overlaps = F.one_hot(max_overlaps_idx, n_max_boxes)  # (b, h*w, n_max_boxes)
        is_max_overlaps = is_max_overlaps.permute(0, 2, 1).to(overlaps.dtype)  # (b, n_max_boxes, h*w)
        mask_pos = torch.where(mask_multi_gts, is_max_overlaps, mask_pos)  # (b, n_max_boxes, h*w)
        fg_mask = mask_pos.sum(-2)
    # find each grid serve which gt(index)
    target_gt_idx = mask_pos.argmax(-2)  # (b, h*w)
    return target_
### YOLOv8 中集成 DIoU-NMS 的方法 要在 YOLOv8 后处理中实现 DIoU-NMS 方法,可以通过修改其源码来完成。以下是具体的操作方式: #### 修改 `non_max_suppression` 函数 YOLOv8 使用的非极大值抑制 (NMS) 实现通常位于工具模块中(如 `ultralytics/yolo/utils/ops.py` 或类似的文件路径),其中定义了一个名为 `non_max_suppression` 的函数。为了支持 DIoU-NMS,需要调整该函数。 以下是一个基于 YOLOv5 和 YOLOv8 的代码示例,展示如何将 DIoU-NMS 集成到后处理阶段[^1]: ```python import torch def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False, multi_label=True, diou_nms=True): """ 执行非极大值抑制 (NMS),可以选择使用 DIoU-NMS。 参数: prediction: 模型预测结果 (batch_size, num_boxes, [xywh, obj_conf, class_scores]) conf_thres: 置信度阈值 iou_thres: IoU 阈值 classes: 是否过滤特定类别 agnostic: 类别无关 NMS multi_label: 多标签分类模式 diou_nms: 是否启用 DIoU-NMS 返回: list of detections, on (n,6) tensor per image [xyxy, conf, cls] """ # 初始化变量 nc = prediction.shape[2] - 5 # 数字类别的数量 xc = prediction[..., 4] > conf_thres # 候选框筛选条件 # 输出列表初始化 output = [torch.zeros((0, 6), device=prediction.device)] * prediction.shape[0] for xi, x in enumerate(prediction): # 对每张图片的结果进行迭代 x = x[xc[xi]] # 过滤掉低置信度候选框 if not x.shape[0]: continue # 计算 xyxy 格式的边界框坐标 box = xywh2xyxy(x[:, :4]) # 如果启用了多标签,则按类别分别处理 if multi_label: i, j = (x[:, 5:] > conf_thres).nonzero(as_tuple=False).T x = torch.cat((box[i], x[i, j + 5, None], j[:, None].float()), 1) else: # 单一最高分数类别 conf, j = x[:, 5:].max(1, keepdim=True) x = torch.cat((box, conf, j.float()), 1)[conf.view(-1) > conf_thres] # 排序并执行 NMS n = x.shape[0] # 当前图像中的检测数 if not n: continue c = x[:, 5:6] * (0 if agnostic else max_wh) # 类别偏移 boxes, scores = x[:, :4] + c, x[:, 4] # 调整后的盒子和得分 if diou_nms: from utils.metrics import bbox_iou # 导入 DIoU 计算函数 ious = bbox_iou(boxes.unsqueeze(1), boxes.unsqueeze(0), x1y1x2y2=False, CIoU=True) # 计算 DIoU 矩阵 selected_indices = [] while True: _, idx = scores.max(0) selected_indices.append(idx.item()) if len(selected_indices) >= n or scores[idx] < conf_thres: break mask = ious[idx] <= iou_thres scores = scores[mask.squeeze()] boxes = boxes[mask.squeeze()] x = x[selected_indices] else: from torchvision.ops import nms indices = nms(boxes, scores, iou_thres) x = x[indices] output[xi] = x return output ``` #### 关键点说明 1. **DIoU 计算**: 上述代码通过调用 `bbox_iou` 函数实现了 DIoU 的计算逻辑[^1]。如果未找到对应的函数,可以从 YOLOv5 的 `utils/metrics.py` 文件复制其实现。 2. **自定义 NMS 循环**: 在启用 DIoU-NMS 的情况下,手动构建循环以逐步选择最优目标,并剔除与其他目标重叠率超过设定阈值的对象。 3. **兼容性**: 新增参数 `diou_nms` 控制是否启用 DIoU-NMS,默认设置为 False,以便保持原有功能不变。 --- ### 注意事项 - 若发现性能瓶颈,建议测试不同硬件平台下的运行效率,因为 DIoU-NMS 可能会稍微增加计算开销。 - 确保导入的辅助函数(如 `bbox_iou`)已正确配置于项目目录下。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值