目标检测之AP、mAP计算

最近在做模型评测,在评测指标的计算过程上卡了很久,之前在课本上看的计算过程以及很多博客上看计算方法,介绍得比较简单,真正自己算的时候才发现细节真的实在太多了,花了一天时间理清了计算过程。
1.目标检测结果输出与指标计算流程
目标检测之AP、mAP计算_第1张图片
(1)以基于anchor的目标检测为例,模型输出大量检测框的类别分数和对应的offset,offset解码得到预测框的左上角和右下角坐标:(x1,y1,x2,y2);
(2)解码之后得到的检测框数量是远远大于真实数量的,存在多个预测框重叠的情况,于是使用NMS的方法对预测框进行过滤,注意:NMS只是过滤重叠的预测框,此时还没有跟真实框进行匹配,也就是下一步。
(3)预测框与真实框匹配,使用iou进行计算,大于一定阈值(一般设置为0.5或0.7),则认为是匹配上的。这里有两个问题:
**a.一个预测框可能与多个真实物体iou大于阈值:**选取iou最大的那个,实际操作是计算得到一个预测框与所有真实框的iou列表,进行降序排列,取最大的iou与阈值对比,大于阈值则将其匹配,作为TP;
**b.多个预测框匹配到一个真实物体:**取置信度最大的那个,作为TP,剩下的都是FP
(4)得到TP和FP的值了就可以计算precision、recall、AP、mAP了,这里也是有很多细节的,precision、recall比较好算:

r e c a l l = T P N _ g r o u d _ t r u t h recall=\frac{TP}{N\_groud\_truth} recall=N_groud_truthTP

p r e c i s i o n = T P T P + F P precision=\frac{TP}{TP+FP} precision=TP+FPTP

AP和mAP涉及到置信度阈值的,可以参考这篇博客,讲得很详细。

2.AP、mAP计算代码
numpy版本,网上大部分是这个版本,直接复制粘贴了:

def voc_ap(rec, prec, use_07_metric=False):
  """ ap = voc_ap(rec, prec, [use_07_metric])
  Compute VOC AP given precision and recall.
  If use_07_metric is true, uses the
  VOC 07 11 point method (default:False).
  """
  if use_07_metric:
    # 11 point metric
    ap = 0.
    for t in np.arange(0., 1.1, 0.1):
      if np.sum(rec >= t) == 0:
        p = 0
      else:
        p = np.max(prec[rec >= t])
      ap = ap + p / 11.
  else:
    # correct AP calculation
    # first append sentinel values at the end
    mrec = np.concatenate(([0.], rec, [1.]))
    mpre = np.concatenate(([0.], prec, [0.]))
    print(mpre)
    # compute the precision envelope
    for i in range(mpre.size - 1, 0, -1):
      mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])
 
    # to calculate area under PR curve, look for points
    # where X axis (recall) changes value
    i = np.where(mrec[1:] != mrec[:-1])[0]
 
    ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
    print(mpre)
  return ap

torch版本:

def voc_ap(recall,precision,use_07_metric=False):
    if use_07_metric:
        recall_thresholds = torch.arange(start=0, end=1.1, step=.1).tolist()  # (11)
        precisions = torch.zeros((len(recall_thresholds)), dtype=torch.float).to(device)  # (11)
        for i, t in enumerate(recall_thresholds):
            recalls_above_t = recall >= t
            if recalls_above_t.any():
                precisions[i] = precision[recalls_above_t].max()
            else:
                precisions[i] = 0.
        AP = precisions.mean()  # c is in [1, n_classes - 1]
    else:
        mrecall=torch.cat((torch.tensor([0.]).to(device),recall,torch.tensor([1.]).to(device)),0)
        mprecision=torch.cat((torch.tensor([0.]).to(device),precision,torch.tensor([0.]).to(device)),0)
        for i in range(mprecision.size(0)-1,0,-1):
            mprecision[i-1]=torch.max(mprecision[i-1],mprecision[i])
        i=torch.nonzero(mrecall[1:]!=mrecall[:-1][0]).squeeze()
        AP=torch.sum((mrecall[i+1]-mrecall[i])*mprecision[i+1])
    return AP

你可能感兴趣的:(pytorch,目标检测,深度学习,人工智能)