神经网络——IoU & NMS & 正负样本均衡

IoU

IoU(Intersection over Union),又称重叠度/交并比。

神经网络——IoU & NMS & 正负样本均衡_第1张图片

即上图中的 intersection/Union,代码实现:

# one pre, one gt
def IoU(pred_box, gt_box):
    ixmin = max(pred_box[0], gt_box[0])
    iymin = max(pred_box[1], gt_box[1])
    ixmax = min(pred_box[2], gt_box[2])
    iymax = min(pred_box[3], gt_box[3])
    inter_w = np.maximum(ixmax - ixmin + 1., 0)
    inter_h = np.maximum(iymax - iymin + 1., 0)

    inters = inter_w * inter_h

    uni = ((pred_box[2] - pred_box[0] + 1.) * (pred_box[3] - pred_box[1] + 1.) +
           (gt_box[2] - gt_box[0] + 1.) * (gt_box[3] - gt_box[1] + 1.) - inters)

    ious = inters / uni

    return ious

# multi pre, one gt
def maxIoU(pred_box, gt_box):
    ixmin = np.maximum(pred_box[:, 0], gt_box[0])
    iymin = np.maximum(pred_box[:, 1], gt_box[1])
    ixmax = np.minimum(pred_box[:, 2], gt_box[2])
    iymax = np.minimum(pred_box[:, 3], gt_box[3])
    inters_w = np.maximum(ixmax - ixmin + 1., 0)  # 逐元素求最大值和最小值 broadcasting
    inters_h = np.maximum(iymax - iymin + 1., 0)  # 逐元素求最大值和最小值 broadcasting

    inters = inters_w * inters_h

    uni = ((pred_box[:, 2] - pred_box[:, 0] + 1.) * (pred_box[:, 3] - pred_box[:, 1] + 1.) +
           (gt_box[2] - gt_box[0] + 1.) * (gt_box[3] - gt_box[1] + 1.) - inters)

    ious = inters / uni
    iou = np.max(ious)
    iou_id = np.argmax(ious)

    return iou, iou_id

# multi pre, multi gt
def box_IoU(pred_box, gt_boxes):
    result = []
    for gt_box in gt_boxes:
        temp = []
        ixmin = np.maximum(pred_box[:, 0], gt_box[0])
        iymin = np.maximum(pred_box[:, 1], gt_box[1])
        ixmax = np.minimum(pred_box[:, 2], gt_box[2])
        iymax = np.minimum(pred_box[:, 3], gt_box[3])
        inters_w = np.maximum(ixmax - ixmin + 1., 0)  # 逐元素求最大值和最小值 broadcasting
        inters_h = np.maximum(iymax - iymin + 1., 0)  # 逐元素求最大值和最小值 broadcasting

        inters = inters_w * inters_h

        uni = ((pred_box[:, 2] - pred_box[:, 0] + 1.) * (pred_box[:, 3] - pred_box[:, 1] + 1.) +
               (gt_box[2] - gt_box[0] + 1.) * (gt_box[3] - gt_box[1] + 1.) - inters)

        ious = inters / uni
        iou = np.max(ious)
        iou_id = np.argmax(ious)

        temp.append(iou)
        temp.append(iou_id)
        result.append(temp)
    return result

以及与 IoU 相关的一些损失函数:

目标检测回归损失函数简介:SmoothL1/IoU/GIoU/DIoU/CIoU Loss - 知乎

收藏 | 目标检测回归损失函数总结

目标检测回归损失函数简介:SmoothL1/IoU/GIoU/DIoU/CIoU Loss

由数据标注引出的问题:边界框的概率分布,模型预测出的边界框的不确定度。

​​​​​​一文了解目标检测边界框概率分布 - 知乎

对 Bounding Box 的高斯分布建模。

武汉大学提出NWD:小目标检测新范式,抛弃IoU-Based暴力涨点(登顶SOTA)

NMS

NMS(non-maximum suppression),非极大值抑制。检测模型输出的检测结果中,有很多都是多余的,是对同一个物体的重复预测,因此需要用 NMS 来抑制掉一些。具体做法是:

  1. 模型的每一个输出 output 都包含回归预测 bbox pre,分类预测 cls pre 和分类预测得分 cls score。将模型的所有输出按 cls pre 进行划分。
  2. 对每一个类别的所有输出,按 cls score 对其进行排序,每次取出一个得分最高的 output。与剩余所有的输出计算 IoU 值,将 IoU 值达到阈值的输出全部过滤掉,不再参与下述步骤。
  3. 在过滤后剩下的输出中取出 cls score 第二大的 output,重复步骤2的操作,再选出第三大的 output,重复步骤2的操作,直到遍历完该类别的所有输出。
  4. 重复步骤2和步骤3,遍历完所有类别的所有输出,得到最终的检测结果。

每一个类别过滤的代码实现:

def py_cpu_nms(dets, thresh):
    """Pure Python NMS baseline."""
    x1 = dets[:, 0]                     # pred bbox top_x
    y1 = dets[:, 1]                     # pred bbox top_y
    x2 = dets[:, 2]                     # pred bbox bottom_x
    y2 = dets[:, 3]                     # pred bbox bottom_y
    scores = dets[:, 4]              # pred bbox cls score

    areas = (x2 - x1 + 1) * (y2 - y1 + 1)    # pred bbox areas
    order = scores.argsort()[::-1]              # 对pred bbox按score做降序排序,对应step-2

    keep = []    # NMS后,保留的pred bbox
    while order.size > 0:
        i = order[0]          # top-1 score bbox
        keep.append(i)   # top-1 score的话,自然就保留了
        xx1 = np.maximum(x1[i], x1[order[1:]])   # top-1 bbox(score最大)与order中剩余bbox计算NMS
        yy1 = np.maximum(y1[i], y1[order[1:]])
        xx2 = np.minimum(x2[i], x2[order[1:]])
        yy2 = np.minimum(y2[i], y2[order[1:]])

        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        ovr = inter / (areas[i] + areas[order[1:]] - inter)      # 无处不在的IoU计算~~~

        inds = np.where(ovr <= thresh)[0]     # 这个操作可以对代码断点调试理解下,结合step-3,我们希望剔除所有与当前top-1 bbox IoU > thresh的冗余bbox,那么保留下来的bbox,自然就是ovr <= thresh的非冗余bbox,其inds保留下来,作进一步筛选
        order = order[inds + 1]   # 保留有效bbox,就是这轮NMS未被抑制掉的幸运儿,为什么 + 1?因为ind = 0就是这轮NMS的top-1,剩余有效bbox在IoU计算中与top-1做的计算,inds对应回原数组,自然要做 +1 的映射,接下来就是step-4的循环

    return keep    # 最终NMS结果返回

以及 NMS 的变体:

一文打尽目标检测NMS——精度提升篇 - 知乎

NMS也能玩出花样来…… - 知乎

正负样本均衡

OHEM、Focal Loss、ATSS

Adaptive Training Sample Selection (ATSS) - 知乎

你可能感兴趣的:(神经网络,深度学习,计算机视觉)