最近在做目标检测相关的工作,有时候想要统计mAP值却往往找不到对应的参考文献,所以就花了一些时间统一对资料进行了整理,希望可以帮到需要的朋友。
1、mAP(mean average precision),用来衡量多个类别的样本的平均AP值,在目标检测问题中,我们一般会检测多种类别的样本,然后计算各个类别的AP值,其中某个类的AP值用来评估网络对某种类别的样本的检测效果,∫p(r)dr(r∈[0,1]),p(r)表示的是我们讲precision表示成关于recall的函数,然后进行积分求解,实际上表示的某种类别的p-r曲线下的面积,一般有voc 2007(11 points法)和voc 2012的更加贴切的评价标准,具体可以在github上面查找到非常详细的资料,这里不再过过多解释;
2、相信比起mAP的概念相关的知识,大家关注更多的应该是mAP的求解步骤了,下面就做一个粗略的介绍:
1)求解每一类的AP值,这要求我们能够从预测的结果中挑选出对应每一类的预测结果,同时我们需要主要到,由于网络预测出来的候选框有的是非常非常多的,因为并不是每个候选框我们都参与了运算,需要注意的是我们从预测框中仅仅挑选置信度大于某一选定阈值的预测框进行求解,画出对应的p-r曲线,然后求解对应的precision和recall值,然后求解该类别的AP值(注意,在voc2007中,11points求解AP值的时候,recall值往往很难达到0.9以上,一般我们会将recall值没有的对应的precision设置0,然后求解其AP值);
2)针对多类求解mAP,即多个类别计算出来的AP值求平均。
下面贴一个修改版的各个类别的AP求解方法,若要求mAP的话,算出各个类别的AP值,然后取平均即可。
#coding=utf-8
"""
参照voc_detection的标准的mAP计算方法
"""
import numpy as np
import os
#计算某个类别的AP值。
def voc_ap(rec, prec, use_07_metric=False):
if use_07_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:
mrec = np.concatenate(([0.], rec, [1.]))
mpre = np.concatenate(([0.], prec, [0.]))
for i in range(mpre.size - 1, 0, -1):
mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])
i = np.where(mrec[1:] != mrec[:-1])[0]
ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
return ap
#如果是self_data数据,则需要对label进行转化,讲中心点加宽高转化为左上加右下
#如果是cocw数据,则可以直接比较,因为它的标签就是左上加上右下点的坐标
def read_file(file,classname):
with open(file,'r') as f:
lines=f.readlines()
if classname==-1:
lines=[line.strip().split(" ") for line in lines]
bboxes_to=[]
for item in lines:
bboxes_to.append(item[1:])
else:
lines_=[line.strip().split(" ") for line in lines]
lines=[]
bboxes_to=[]
for i,line in enumerate(lines_):
if int(line[0])==classname:
lines.append(line)
bboxes_to.append(line[1:])
# print(bboxes_to_[i])
# bboxes=[]
# for bbox in bboxes_to:
# item=[float(bbox[0]),float(bbox[1]),float(bbox[2]),float(bbox[3])]
# bboxes.append(item)
# return np.array(bboxes),lines
bboxes = []
for bbox in bboxes_to:
item = [float(bbox[0])-float(bbox[2])/2.0, float(bbox[1])-float(bbox[3])/2.0, float(bbox[0])+float(bbox[2])/2.0, float(bbox[1])+float(bbox[3])/2.0]
bboxes.append(item)
return np.array(bboxes),lines
#从ground truth中挑选某个类别的ground truth,
def convert(gt_dir,classname):
class_recs={}
npos=0
for root,dirs,files in os.walk(gt_dir):
for i,file in enumerate(files):
cur_path=os.path.join(root,file)
bbox,R=read_file(cur_path,classname)
det=[False]*len(R)
npos+=len(R)
#这样我们可以得到属于某个类别的ground truth
class_recs[file]={"bbox":bbox,'det':det}
print("正在转化中。。。"+str(len(files)-i))
return class_recs,npos
#更加详细的资料可以查看https://github.com/Tangzixia/Object-Detection-Metrics#average-precision
#pred_res代表的是我的预测结果,对应的格式为图片标号 置信度 预测类别 框
def gen_ap(gt_dir,pred_res,classname,iou=0.5):
class_recs,npos=convert(gt_dir,classname)
with open(pred_res,'r') as f:
lines=f.readlines()
#img_id,confidence,BB,
#得分
splitlines=[item.strip().split(" ") for item in lines]
img_ids=[x[0] for x in splitlines]
confidence=np.array([float(x[2]) for x in splitlines])
BB=np.array([[float(z) for z in x[3:]] for x in splitlines])
#找出每一类对应的候选框
inds=np.zeros(len(splitlines))
for i,item in enumerate(splitlines):
if int(item[1])==classname:
inds[i]=1
img_ids_=[]
confidence_=[]
BB_=[]
for i,item in enumerate(splitlines):
if inds[i]==1:
img_ids_.append(img_ids[i])
confidence_.append(confidence[i])
BB_.append(BB[i])
img_ids=img_ids_
confidence=np.array(confidence_)
BB=np.array(BB_)
# img_ids=list(np.array(img_ids[np.array(inds)]))
# confidence=list(np.array(confidence[np.array(inds)]))
# BB=list(np.array(BB[np.array(inds)]))
#confidence由大到小排序
sorted_ind=np.argsort(-confidence)
# 这里我们选择的置信度大于0.3的预测框求解其precision和recall,进而求解该类的AP值
# np.argsort(-confidence<=-.3)
sorted_ind1 = np.where(confidence[sorted_ind] >= .3)[0]
sorted_ind = sorted_ind[sorted_ind1]
print(len(sorted_ind))
BB=BB[sorted_ind,:]
img_ids=[img_ids[x] for x in sorted_ind]
# sorted_ind = np.argsort(-confidence)
# print(len(sorted_ind))
# BB = BB[sorted_ind, :]
# img_ids = [img_ids[x] for x in sorted_ind]
nd=len(img_ids)
print(nd)
tp=np.zeros(nd)
fp=np.zeros(nd)
for d in range(nd):
R=class_recs[img_ids[d]]
bb=BB[d,:].astype(float)
ovmax = -np.inf
BBGT=R['bbox'].astype(float)
if BBGT.size>0:
ixmin = np.maximum(BBGT[:, 0], bb[0])
iymin = np.maximum(BBGT[:, 1], bb[1])
ixmax = np.minimum(BBGT[:, 2], bb[2])
iymax = np.minimum(BBGT[:, 3], bb[3])
iw = np.maximum(ixmax - ixmin + 1., 0.)
ih = np.maximum(iymax - iymin + 1., 0.)
inters = iw * ih
uni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +
(BBGT[:, 2] - BBGT[:, 0] + 1.) *
(BBGT[:, 3] - BBGT[:, 1] + 1.) - inters)
overlaps=inters/uni
ovmax=np.max(overlaps)
# print(ovmax)
jmax=np.argmax(overlaps)
if ovmax>iou:
if not R['det'][jmax]:
tp[d]=1
R['det'][jmax]=1
else:
fp[d]=1
else:
fp[d]=1
fp=np.cumsum(fp)
tp=np.cumsum(tp)
rec=tp/float(npos)
prec=tp/np.maximum(tp+fp,np.finfo(np.float64).eps)
ap = voc_ap(rec, prec)
return rec,prec,ap
if __name__=="__main__":
# gt_dir="/media/hp/captcha/object detection/test/labels"
# pred_res="../all_res_car.txt"
# classname=4
# rec,prec,ap=gen_ap(gt_dir,pred_res,classname)
# print(rec,prec,ap)
gt_dir = "/home/hp/Data/house_data/train/Data_valid/labels_initial/"
pred_res = "../all_res_self_data.txt"
classname = 0
rec, prec, ap = gen_ap(gt_dir, pred_res, classname)
print(rec, prec, ap)
Measuring Object Detection models - mAP - What is Mean Average Precision?
darknet yolo 计算mAP,recall
深度学习系列之YOLOv2 mAP计算
YOLO V2 的mAP数据测试
关于代码的更多解释可以参看:https://www.zhihu.com/question/41540197
目标检测中的mAP是什么含义?
How to calculate mAP for detection task for the PASCAL VOC Challenge?
如何采样P-R曲线呢?
如下
有时间再来做更精细的整理!