码迷,mamicode.com
首页 > 其他好文 > 详细

NMs之后正负样本(及真正例)的确定和map的计算

时间:2020-09-11 14:15:31      阅读:46      评论:0      收藏:0      [点我收藏+]

标签:end   回归   desc   tuples   指标   生成   根据   因此   正负样本   

"""
评价模型的核心函数:根据得到的正负样本,输出:P,R,map等
"""

#验证集或测试集都可以用
def evaluate(model, path, iou_thres, conf_thres, nms_thres, img_size, batch_size):
    model.eval()

    # Get dataloader
    dataset = ListDataset(path, img_size=img_size, augment=False, multiscale=False)
    dataloader = torch.utils.data.DataLoader(
        dataset, batch_size=batch_size, shuffle=False, num_workers=2, collate_fn=dataset.collate_fn
    )

    Tensor = torch.cuda.FloatTensor if torch.cuda.is_available() else torch.FloatTensor

    labels = []
    sample_metrics = []  # List of tuples (TP, confs, pred)
    for batch_i, (_, imgs, targets) in enumerate(tqdm.tqdm(dataloader, desc="Detecting objects")):
    #将dataloader迭代器枚举出来,一个batch一个batch的操作
        # Extract labels
        labels += targets[:, 1].tolist()
        # Rescale target,训练时图片有个固定尺寸,因此原图像的尺度标注也需要放缩
        targets[:, 2:] = xywh2xyxy(targets[:, 2:])#不同数据标注方法的结果转换
        targets[:, 2:] *= img_size


        imgs = Variable(imgs.type(Tensor), requires_grad=False)

        with torch.no_grad():
            outputs = model(imgs)
            outputs = non_max_suppression(outputs, conf_thres=conf_thres, nms_thres=nms_thres)#对每张图片作抑制,只在测试或验证时采用

        #这里get_batch_statistics的输出是每个batch的推理统计结果,然后循环追加所有batch结果,完成整个验证集的统计结果
        sample_metrics += get_batch_statistics(outputs, targets, iou_threshold=iou_thres)

    # Concatenate sample statistics
    true_positives, pred_scores, pred_labels = [np.concatenate(x, 0) for x in list(zip(*sample_metrics))]
    #在axis = 0 方向拼接,得到了分离的true_positives, pred_scores, pred_labels
    precision, recall, AP, f1, ap_class = ap_per_class(true_positives, pred_scores, pred_labels, labels)#这里的ap_per_class是关键评估函数。
    #用模型对整个验证集有效预测的结果[np.concatenate(x, 0) for x in list(zip(*sample_metrics))]  和  labels 标签求指标

    return precision, recall, AP, f1, ap_class#得到一个验证集的每个类别的P,R,ap,f1,ap的类别。其实就是nums = num_class张PR曲线。每个变量的第一维度都等于类别数


"""
推理的核心函数,
输入:nms抑制之后的结果
输出:模型预测得到的正样本和负样本()
"""
#outputs:模型的原始预测输出仅经过nms抑制后的结果(nms抑制中做了置信度阈值下界的过滤,认为预测得分小于0.5的不算前景),还没有经过最终的判别置信度阈值过滤
#经过get_batch_statistics后就统计出最终的正确检测数目(正样本)
#iou_threshold这个阈值是预测框和gt_box的交并比。和nms一定要分开。
#两个IOU计算对象不同,
def get_batch_statistics(outputs, targets, iou_threshold):#iou_threshold参数:用nms之后得到的每个样本与gt_box做IOU,超过此iou_threshold就认为是正样本;但是对于某gt_box只有与其具有最大IOU的正样本(P)才是真正例(TP)。
    #这里是验证时结果与标签对比
    """ Compute true positives, predicted scores and predicted labels per sample """
    batch_metrics = []
    for sample_i in range(len(outputs)):
        #以下针对单张图片的操作,len(outputs)就是一次推理的样本(图片)数目
        if outputs[sample_i] is None:
            continue
        #这里output是什么样的,很关键,明白每个数据的shape后面就简单了,outputs第0维大小就是batchsize。
        output = outputs[sample_i]#这里output是单图片
        pred_boxes = output[:, :4]#pred_boxes也是单图片
        pred_scores = output[:, 4]
        pred_labels = output[:, -1]
        #true_positives指的正样本(目标)的数量
        true_positives = np.zeros(pred_boxes.shape[0])#生成一个形状的0填充的数组,最终记录正确预测的box的索引,正确即为1
           #targets是什么样的[],看这操作就是通过sample_i去对应targets的部分
        annotations = targets[targets[:, 0] == sample_i][:, 1:]#有点像反查!生成标注的数组,排除掉了第一维,是什么???
        target_labels = annotations[:, 0] if len(annotations) else []#从一张图片标注中提取 类别标签
        #取样本标注的第一维,即类别标签
        if len(annotations):
            #一条annotation就是一个gt_box的标签信息
            #如果这个样本是有标注的,即这样本有需要回归预测的object
            detected_boxes = []
            target_boxes = annotations[:, 1:]#从标注中提取 位置标签
            #下面是个常用操作enumerate(zip(pred_boxes, pred_labels)),是不是应该自己写看看作用效果???
            #分而治之
"""
对一张图片的pre_box遍历
"""
            for pred_i, (pred_box, pred_label) in enumerate(zip(pred_boxes, pred_labels)):

                # If targets are found break
                if len(detected_boxes) == len(annotations):
                    break
                    #这里指,如果下面的break

                # Ignore if label is not one of the target labels
                if pred_label not in target_labels:#如果预测标签不属于这张图片标注的任何一个标签
                    continue#这里是假正例
                    #IOU等没必要再做了。
"""
以下就是要从正样本里确定真正例:与每个gt_box具有最大IOU且这个值>iou_threshold的才是真正例。因此每个pred_box都会标记一个与gt_box有最大IOU的gt_box的box_index,但是如果已经被更大的IOU的pred_box标记过了,则就是假正例。
iou >= iou_threshold:正样本
box_index not in detected_boxes:如果有多个正样本pre_box预测为同一个gt_box,那么与gt_box的IOU最大的是真正例,其余都是假正例。
"""
                #这个tensor的max函数很重要,既能返回最大值,又能返回最大值的位置索引。这里都是同一个类别的。
                iou, box_index = bbox_iou(pred_box.unsqueeze(0), target_boxes).max(0)#目的:找出一张图片中某个pred_box与哪个gt_box具有最大IOU,索引box_index就是gt_box的编号
                #将此样本的预测pre_box与所有gt_box做IOU计算,得到bbox_iou(pred_box.unsqueeze(0), target_boxes),一个len==dets_nums的单图张量

                if iou >= iou_threshold and box_index not in detected_boxes:#只有与gt_box交并比大于阈值,且此之前别的pre_box没预测到这个gt_box才算。

#nms之后,正负样本的划分只看与gt_box的IOU阈值置信度;如果超过某个阈值,即推理结果为真正例。在此基础上作PR曲线,做PR曲线用到的是推理置信度即那个score。
#而正样本中的真正例,还要看是不是与此gt_box具有最大IOU

                    true_positives[pred_i] = 1#模型认为这个预测是正样本中的真阳例。
                    detected_boxes += [box_index]#认为一个gt_box被正确detected到

        batch_metrics.append([true_positives, pred_scores, pred_labels])#一个图片一个图片的追加,最终的shape:[3,batch_dets_nums]
        #true_positives所有为1的对应正样本,其余负样本。这样一个batch的统计就弄完了。
        #最终batch_metrics的里面第一维是Batch大小,即有Batch个[true_positives, pred_scores, pred_labels]元素,每一个元素代表一个样本:
        # true_positives:预测正确(类别正确且大于置信度阈值,这里用IOU阈值衡量了)的位置就是1,如[0,0,1,1,0]
        # pred_scores: 预测置信度
        # pred_labels:预测标签
    return batch_metrics#这里得到是有真正例的索引!!!

NMs之后正负样本(及真正例)的确定和map的计算

标签:end   回归   desc   tuples   指标   生成   根据   因此   正负样本   

原文地址:https://www.cnblogs.com/Henry-ZHAO/p/13586335.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!