[图像检索]准确率、查准率/精确度、查全率/召回率、AP/mAP

整理图像检索任务中常用的评估标准(准确率、查准率/精确度、查全率/召回率、AP/mAP)以及相应的实现

术语

  • 准确率(accuracy):查询图像对应标签是否位于检索标签列表的前topK位;
  • 查准率/精确度(precision):查询图像对应标签在检索标签列表的前topK位中占据的比例;
  • 查全率/召回率(recall):查询图像对应标签在检索标签列表的前topK位中出现的次数与真值标签列表个数的比例;
  • AP(average precision/平均精度):单次查询中,计算检索标签列表中真值标签出现时的精度,累加并平均真值标签出现次数;
  • mAP(mean average precision/均值平均精度):执行多次查询,每次查询均计算AP,累加并平均。

AP/mAP的作用:衡量真值标签在检索标签列表中排序的质量AP/mAP值越大,表明越多的真值标签排序在检索列表前面,AP/mAP=1.0表明所有的真值标签均出现在检索列表的最前面。

Update: 图像检索-Recall@K

实现

mAP

具体实现原理参考图像检索:信息检索评价指标mAP就是每次查询计算的AP的平均值,相关实现可以参考:SimpleIR/simpleir/utils/metric/

mAP for Oxford

Oxford5k是图像检索任务中的基准数据集之一。它提供了55张查询图像以及5066张检索图像(包含了查询图像),另外,它还提供了一个C++源文件 - compute_ap.cpp,能够执行单次AP计算。

关键代码计算如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
...
...

float
compute_ap(const set<string>& pos, const set<string>& amb, const vector<string>& ranked_list)
{
// pos 正样本集合
// amb 负样本集合
// ranked_list 排序列表
float old_recall = 0.0;
float old_precision = 1.0;
float ap = 0.0;

// 已检索到正样本个数
size_t intersect_size = 0;
size_t i = 0;
size_t j = 0;
// 依次遍历所有检索结果
for ( ; i<ranked_list.size(); ++i) {
// 如果该查询结果是负样本标签,那么跳过本次计算
if (amb.count(ranked_list[i])) continue;
// 如果该查询结果是正样本标签,那么已检索到的正样本个数加1
if (pos.count(ranked_list[i])) intersect_size++;

// 对于干扰项,召回率保持不变,计算精度不断变小
// 计算召回率 = 已检索到正样本个数 / 正样本集个数。其值不断变大
float recall = intersect_size / (float)pos.size();
// 计算精度 = 已检索到正样本个数 / 预测已遍历样本集个数。其值不断变小
float precision = intersect_size / (j + 1.0);

// 计算AP(曲线下面积),横坐标是召回率,纵坐标是精度
// 之前坐标点:(old_recall, old_precision)
// 当前坐标点:(recall, precision)
// 累加前后坐标点的矩形面积来模拟曲线下面积
// 对于干扰项,前后召回率一样,所以ap += 0
ap += (recall - old_recall)*((old_precision + precision)/2.0);

old_recall = recall;
old_precision = precision;
j++;
}
return ap;
}


int
main(int argc, char** argv)
{
// 计算单次查询的AP
// 输入真值目录中的查询前缀、查询图像与特征集一一比对的检索文件(每一行表示一个检索图像名)
if (argc != 3) {
cout << "Usage: ./compute_ap [GROUNDTRUTH QUERY] [RANKED LIST]\n";
return -1;
}

string gtq = argv[1];

// 读取检索结果,排序结果按行保存,每行表示一个检索图像名
vector<string> ranked_list = load_list(argv[2]);
// 读取该查询图像对应的真值标签,包括正样本(good/ok)和负样本(junk)
// 保存为结构体set
set<string> good_set = vector_to_set( load_list(gtq + "_good.txt") );
set<string> ok_set = vector_to_set( load_list(gtq + "_ok.txt") );
set<string> junk_set = vector_to_set( load_list(gtq + "_junk.txt") );

// 创建正样本set,组合good和ok标签
set<string> pos_set;
pos_set.insert(good_set.begin(), good_set.end());
pos_set.insert(ok_set.begin(), ok_set.end());

// 计算AP
float ap = compute_ap(pos_set, junk_set, ranked_list);

cout << ap << "\n";

return 0;
}

Oxford5k计算的mAP更类似于目标检测任务的计算,求取的是PR曲线的曲线下面积,而上面mAP的计算就是单纯考虑精度的影响。

相关阅读