目标检测之正负样本详解

本文详细介绍了目标检测算法中的正负样本分配和采样策略,包括 Faster R-CNN 的 RPN 和 RCNN 部分,以及 YOLOv3 的方法。关键步骤涉及 assigner 和 sampler,对每个 Anchor 分配属性,然后根据预设阈值选择正负样本进行训练。Faster R-CNN 中的 RPN 使用特定参数设置和在线困难样例挖掘策略,而 YOLOv3 则通过统一 anchor 和 gt 的中心点计算 iou。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

对于目标检测算法而言,正负样本的分配,采样策略以及正负样本的数量和比例的设置等,对算法的精度有着显著的影响,了解其机制和原理便于我们加深对算法的了解和后续对算法的优化改进.
在检测算法中正负样本的设置主要包含两个关键的步骤:
1.assigner:为每一个先验框[anchor]分配属性

  • 正样本
  • 负样本
  • 其它[即不当成正样本又不当成负样本处理,忽略]

2.sampler:采取某种策略[如随机采样]从分配好的正负样本中选出对应数量的正负样本进行训练

Faster RCNN—RPN

1.参数设置:

以下相关参数的设置和代码的讲解,来源于mmdetection

    rpn=dict(
        assigner=dict(
            type='MaxIoUAssigner',
            pos_iou_thr=0.7, #正样本阈值
            neg_iou_thr=0.3, #负样本阈值
            min_pos_iou=0.2, #最低正样本阈值
            ignore_iof_thr=0.3),
        sampler=dict(
            type='RandomSampler',
            num=256,  #总数量
            pos_fraction=0.5,  #比例
            neg_pos_ub=-1,
            add_gt_as_proposals=False), #是否将gt添加到正样本中
        allowed_border=128, #允许anchor尺寸超过图像边缘的最大像素
        pos_weight=-1, #正样本的权重,如果小于0则为1,大于0则为对应设置的值
        debug=False),

2. 整体步骤:

2.1.处理掉一些中心点坐标超过边界过多、宽高尺寸过大的anchor

inside_flags = anchor_inside_flags(flat_anchors, valid_flags,
                                       img_meta['img_shape'][:2],
                                       cfg.allowed_border)   #128
anchors = flat_anchors[inside_flags.type(torch.bool), :]

def anchor_inside_flags(flat_anchors,
                        valid_flags,
                        img_shape,
                        allowed_border=0):
    img_h, img_w = img_shape[:2]
    if allowed_border >= 0:
        inside_flags = valid_flags & \
            (flat_anchors[:, 0] >= -allowed_border).type(torch.uint8) & \
            (flat_anchors[:, 1] >= -allowed_border).type(torch.uint8) & \
            (flat_anchors[:, 2] < img_w + allowed_border).type(torch.uint8) & \
            (flat_anchors[:, 3] < img_h + allowed_border).type(torch.uint8)
    else:
        inside_flags = valid_flags
    return inside_flags

2.2.assign :为每一个Anchor分配属性:
0–负样本
-1—忽略,既不是正样本也不是负样本
positive number— assigned gt[与哪一个gt_bbox对应,存放的是对应gt_bbox的索引] 
计算步骤:
1)计算gt_bbox【g,4】与anchor_bbox[k,4]的iou,得到一个【g,k】的矩阵。

overlaps = bbox_overlaps(gt_bboxes, bboxes)

2)初始化属性矩阵,将所有anchor置为-1

assigned_gt_inds =overlaps.new_full((num_bboxes, ),-1,dtype=torch.long)

3)计算每一个Anchor与gt的最大iou和索引

max_overlaps, argmax_overlaps = overlaps.max(dim=0)

4)计算每一个gt与anchor的最大iou和索引

gt_max_overlaps, gt_argmax_overlaps = overlaps.max(dim=1)

5)遍历所有anchor,若iou<neg_iou_thr[0.3],将其置为0,当成负样本处理;若iou>pos_iou_thr[0.7],将其置为对应gt的索引,当成正样本处理;iou在两者之间的还是置为-1,忽略。

assigned_gt_inds[(max_overlaps >= 0) & (max_overlaps < self.neg_iou_thr)] = 0
pos_inds = max_overlaps >= self.pos_iou_thr
assigned_gt_inds[pos_inds] = argmax_overlaps[pos_inds] + 1 #[**此处对索引进行了加1操作]**

6)遍历所有的gt,若最大iou大于min_pos_iou[0.2],将其置为正样本(一个GT可能有多个或者一个anchor与之匹配)

if gt_max_overlaps[i] >= self.min_pos_iou:
                if self.gt_max_assign_all: #true
                    max_iou_inds = overlaps[i, :] == gt_max_overlaps[i]  #(与该GT的iou等于最大iou的bbox都分配到该gt)
                    assigned_gt_inds[max_iou_inds] = i + 1
                else:
                    assigned_gt_inds[gt_argmax_overlaps[i]] = i + 1

7)将输出结果写入AssignResult类中。

    class AssignResult(object):
        def __init__(self, num_gts, gt_inds, max_overlaps, labels=None):
            self.num_gts = num_gts  正样本数量
            self.gt_inds = gt_inds  anchor属性(-1;no care 0 : 负样本  1-based:与该框匹配的gt)
            self.max_overlaps = max_overlaps每一个候选框与gt的最大iou
            self.labels = labels anchor的类别

2.3.samper: 在分好属性的anchor中按照一定的策略挑选出对应数量的正负样本框
计算步骤
1)计算期望的正样本数量:总数量*比例

num_expected_pos = int(self.num * self.pos_fraction)

2)sample_pos: 生成正样本,如果正样本数量 < 预期数量,则输出所有正样本索引【一般达不到预期】;如果正样本 > 期望数,则在正样本中随机选取对应数量的正样本[此处采用的随机抽样的方法选取正样本]

pos_inds = self.pos_sampler._sample_pos(assign_result, num_expected_pos, bboxes=bboxes, **kwargs)
def _sample_pos(self, assign_result, num_expected, **kwargs):
    """Randomly sample some positive samples."""
    pos_inds = torch.nonzero(assign_result.gt_inds > 0)  #取出正样本的索引
    if pos_inds.numel() != 0:
        pos_inds = pos_inds.squeeze(1)
    if pos_inds.numel() <= num_expected:
        return p
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值