图像检索评价指标:mAP@k、mAP的计算

mAP ,mean Average Precision,平均检索精度.是图像检索领域最最常用的评价指标。

一、mAP@k、mAP

1.1 mAP@k

很多地方喜欢用这张图来解释,确实画的很好了,不过略有瑕疵,我稍微修改了一下。这张图是求mAP@10的结果。

原图主要存在的问题就是,在前10张图片中,把所有的相似的结果都返回了。这样会给读者造成这样的困扰:没检索出来的但是又相似的图片怎么办??

改了之后,就清晰多了。我们就会发现我们这里求mAP的时候是不考虑召回率的,也就是并没有考虑那些相似的但是不在topk中的那些漏掉的图片。只考虑了topk中,相似的图片。

注:当然还有一种计算mAP的方法,就是考虑召回率的计算方法,我们这里不展开。

mAP@k,理解的话应该是m(AP@k),而不是(mAP)@k。也就是先求AP@k,再求平均。

AP@k,理解的话应该是A(P@k),而不是(AP)@k。也就是先求P@k,再求平均。

P@k = 前k个中有多少个正样本 / k,比如对于查询1的结果:P@1 = 1, P@2 = 1/2,  P@3 = 2/3...

求AP@k的时候,是求哪些P@k,然后再求平均呢?是求检索到的k张图片中,正样本位置上的P@k。比如,查询1中,返回了10张图片,但是只有5个正样本,分别在第1、3、6、9、10位。所以要求P@1,P@3,P@6, P@9,P@10这5个值,再求平均得到AP@10.

在求mAP@k的时候,k是指每次查询的时候返回k张图片。这个写@k是与后面要讲的mAP做区分用的。写论文的时候有的时候都不写@k,到底是用的mAP@k,还是mAP,自己把握去吧

【举例】

假设有3张图片,这三张图片的哈希码为:query1=[1,-1,1,1], query2=[-1,1,-1,-1],query3=[1,-1,-1,-1]。

数据库中有7张图片,对应的哈希码为:gallery=[[ 1,-1,-1,-1], [-1, 1, 1,-1], [ 1, 1, 1,-1], [-1,-1, 1, 1], [ 1, 1,-1,-1], [ 1, 1, 1,-1], [-1, 1,-1,-1]]

三张query图片的标签为:[1,0,0], [1,1,0], [0,0,1]。

7张gallery图片的标签为:[0,1,0], [1,1,0], [1,0,1], [0,0,1], [0,1,0], [0,0,1], [1,1,0]

求mAP@5.

(1)对于query1([1,-1,1,1]):

首先query1与gallery图片求距离,然后按照距离进行排序,得到最近的topk(这里设为5)张图片。

gallery汉明距离(有几位不同)排序
[ 1,-1,-1,-1]22
[-1, 1, 1,-1]35
[ 1, 1, 1,-1]23
[-1,-1, 1, 1]11
[ 1, 1,-1,-1]3
[ 1, 1, 1,-1]24
[-1, 1,-1,-1]4

然后,看看返回的topk张图片中,哪些是正样本,哪些是负样本。query1的标签为[1,0,0],所以包含第1类的都是正样本。

返回的topk图片4图片1图片3图片6图片2
标签[0,0,1][0,1,0][1,0,1][0,0,1][1,1,0]
是否正样本

最后,计算AP@5值:

(1/3 + 2/5)/2 = 0.3667

(2)对于query2([-1,1,-1,-1]):

首先query2与gallery图片求距离,然后按照距离进行排序,得到最近的topk(这里设为5)张图片。

gallery汉明距离(有几位不同)排序
[ 1,-1,-1,-1]24
[-1, 1, 1,-1]12
[ 1, 1, 1,-1]25
[-1,-1, 1, 1]3
[ 1, 1,-1,-1]13
[ 1, 1, 1,-1]2
[-1, 1,-1,-1]01

然后,看看返回的topk张图片中,哪些是正样本,哪些是负样本。query2的标签为 [1,1,0],所以包含第1类或第2类的都是正样本。

返回的topk图片7图片2图片5图片1图片3
标签[1,1,0][1,1,0][0,1,0][0,1,0][1,0,1]
是否正样本

最后,计算AP@5值:

(1/1 + 2/2 + 3/3 + 4/4 + 5/5)/5 = 1.0

(3)对于query3([1,-1,-1,-1]):

首先query3与gallery图片求距离,然后按照距离进行排序,得到最近的topk(这里设为5)张图片。

gallery汉明距离(有几位不同)排序
[ 1,-1,-1,-1]01
[-1, 1, 1,-1]3
[ 1, 1, 1,-1]23
[-1,-1, 1, 1]3
[ 1, 1,-1,-1]12
[ 1, 1, 1,-1]24
[-1, 1,-1,-1]25

然后,看看返回的topk张图片中,哪些是正样本,哪些是负样本。query3的标签为 [0,0,1],所以包含第3类的都是正样本。

返回的topk图片1图片5图片3图片6图片7
标签[0,1,0][0,1,0][1,0,1][0,0,1][1,1,0]
是否正样本

最后,计算AP@5值:

(1/3 + 2/4)/2 = 0.4165

(4)对所有的query的AP值,求平均

mAP@5 = (0.3667 + 1 + 0.4165) /3 = 0.5944

1.2 mAP与mAP@k的区别

mAP呢,就是每次查询的时候不是返回k张图片了,而是把所有的图片都按相似度进行返回。也就是k的值等于gallery数据库的大小。

【举例】

还是用上面的例子。求mAP。

(1)对于query1([1,-1,1,1]):

首先query1与gallery图片求距离,然后按照距离进行排序

gallery汉明距离(有几位不同)排序
[ 1,-1,-1,-1]22
[-1, 1, 1,-1]35
[ 1, 1, 1,-1]23
[-1,-1, 1, 1]11
[ 1, 1,-1,-1]36
[ 1, 1, 1,-1]24
[-1, 1,-1,-1]47

然后,看看返回的topk张图片中,哪些是正样本,哪些是负样本。query1的标签为[1,0,0],所以包含第1类的都是正样本。

返回的topk图片4图片1图片3图片6图片2图片5图片7
标签[0,0,1][0,1,0][1,0,1][0,0,1][1,1,0][0,1,0][1,1,0]
是否正样本

最后,计算AP值:

(1/3 + 2/5 + 3/7)/3 = 0.3873

(2)对于query2([-1,1,-1,-1]):

首先query2与gallery图片求距离,然后按照距离进行排序,得到最近的topk(这里设为5)张图片。

gallery汉明距离(有几位不同)排序
[ 1,-1,-1,-1]24
[-1, 1, 1,-1]12
[ 1, 1, 1,-1]25
[-1,-1, 1, 1]37
[ 1, 1,-1,-1]13
[ 1, 1, 1,-1]26
[-1, 1,-1,-1]01

然后,看看返回的topk张图片中,哪些是正样本,哪些是负样本。query2的标签为 [1,1,0],所以包含第1类或第2类的都是正样本。

返回的topk图片7图片2图片5图片1图片3图片6图片4
标签[1,1,0][1,1,0][0,1,0][0,1,0][1,0,1][0,0,1][0,0,1]
是否正样本

最后,计算AP值:

(1/1 + 2/2 + 3/3 + 4/4 + 5/5)/5 = 1.0

(3)对于query3([1,-1,-1,-1]):

首先query3与gallery图片求距离,然后按照距离进行排序,得到最近的topk(这里设为5)张图片。

gallery汉明距离(有几位不同)排序
[ 1,-1,-1,-1]01
[-1, 1, 1,-1]36
[ 1, 1, 1,-1]23
[-1,-1, 1, 1]37
[ 1, 1,-1,-1]12
[ 1, 1, 1,-1]24
[-1, 1,-1,-1]25

然后,看看返回的topk张图片中,哪些是正样本,哪些是负样本。query3的标签为 [0,0,1],所以包含第3类的都是正样本。

返回的topk图片1图片5图片3图片6图片7图片2图片4
标签[0,1,0][0,1,0][1,0,1][0,0,1][1,1,0][1,1,0][0,0,1]
是否正样本

最后,计算AP值:

(1/3 + 2/4 + 3/7)/3 = 0.4206

(4)对所有的query的AP值,求平均

mAP = (0.3873 + 1 + 0.4206) /3 = 0.6026

二、代码实现

# @file name  : test2.py
# @brief      : 
# @author     : liupc
# @date       : 2021/8/2

import numpy as np

#计算汉明距离。有几位不同,距离就为几。
def CalcHammingDist(B1, B2):
    q = B2.shape[1]
    distH = 0.5 * (q - np.dot(B1, B2.transpose()))
    return distH


#计算mAP@k的值
def CalcTopMap(qB, rB, queryL, retrievalL, topk):
    #qB queryBinary, query数据集,都转成了哈希码
    #rB retrievalBinary,gallery数据集,都转成了哈希码
    #queryL queryLabel,query数据集的标签
    #retrievalL retrievalLabel,gallery数据集的标签

    num_query = queryL.shape[0]         #共有多少个查询
    topkmap = 0
    for iter in range(num_query): #对每一个查询,求其AP@k的值
        #gnd:一个长度等于gallery数据集的0/1向量,1表示为正样本(即至少包含query的一个标签),0表示负样本(即,不包含query的标签)。
        gnd = (np.dot(queryL[iter, :], retrievalL.transpose()) > 0).astype(np.float32)
        hamm = CalcHammingDist(qB[iter, :], rB)  #计算第iter张query图片与gallery数据集的汉明距离
        ind = np.argsort(hamm)                   #对汉明距离进行排序,返回下标,表示最相似的图片列表
        gnd = gnd[ind]                           #最相似的图片是否为正样本的列表

        tgnd = gnd[0:topk]                       #只看前topk个结果
        tsum = np.sum(tgnd).astype(int)          #前topk个中有多少个预测对了
        if tsum == 0:
            continue
        count = np.linspace(1, tsum, tsum)

        tindex = np.asarray(np.where(tgnd == 1)) + 1.0
        topkmap_ = np.mean(count / (tindex))
        topkmap += topkmap_
    topkmap = topkmap / num_query
    return topkmap

#计算mAP的值
def CalcMap(qB, rB, queryL, retrievalL):
    #qB queryBinary, query数据集,都转成了哈希码
    #rB retrievalBinary,gallery数据集,都转成了哈希码
    #queryL queryLabel,query数据集的标签
    #retrievalL retrievalLabel,gallery数据集的标签

    num_query = queryL.shape[0]
    map = 0
    # print('++++++++++++++++++++++++++++++++++++++++++++++++++++++++++')

    for iter in range(num_query):
        gnd = (np.dot(queryL[iter, :], retrievalL.transpose()) > 0).astype(np.float32)
        tsum = np.sum(gnd).astype(int)
        if tsum == 0:
            continue
        hamm = CalcHammingDist(qB[iter, :], rB)
        ind = np.argsort(hamm)
        gnd = gnd[ind]
        count = np.linspace(1, tsum, tsum)

        tindex = np.asarray(np.where(gnd == 1)) + 1.0
        map_ = np.mean(count / (tindex))
        # print(map_)
        map = map + map_
    map = map / num_query

    return map


#计算topk准确率
def CalcTopAcc(qB, rB, queryL, retrievalL, topk):
    # qB: {-1,+1}^{mxq}
    # rB: {-1,+1}^{nxq}
    # queryL: {0,1}^{mxl}
    # retrievalL: {0,1}^{nxl}
    num_query = queryL.shape[0]
    topkacc = 0
    # print('++++++++++++++++++++++++++++++++++++++++++++++++++++++++++')
    for iter in range(num_query):
        # gnd:一个长度等于gallery数据集的0/1向量,1表示为正样本(即至少包含query的一个标签),0表示负样本(即,不包含query的标签)。
        gnd = (np.dot(queryL[iter, :], retrievalL.transpose()) > 0).astype(np.float32)
        hamm = CalcHammingDist(qB[iter, :], rB)  #计算第iter张query图片与gallery数据集的汉明距离
        ind = np.argsort(hamm)                   #对汉明距离进行排序,返回下标,表示最相似的图片列表
        gnd = gnd[ind]                           #最相似的图片是否为正样本的列表
        tgnd = gnd[0:topk]                       #只看前topk个结果
        tsum = np.sum(tgnd)                      #前topk个中有多少个预测对了
        if tsum == 0:
            continue
        topkacc += tsum / topk
    topkacc = topkacc / num_query
    return topkacc



if __name__=='__main__':
    queryBinary = np.array([[1,-1,1,1],[-1,1,-1,-1],[1,-1,-1,-1]])
    galleryBinary = np.array([[ 1,-1,-1,-1],
                              [-1, 1, 1,-1],
                              [ 1, 1, 1,-1],
                              [-1,-1, 1, 1],
                              [ 1, 1,-1,-1],
                              [ 1, 1, 1,-1],
                              [-1, 1,-1,-1]])
    queryLabel = np.array([[1,0,0],
                           [1,1,0],
                           [0,0,1]], dtype=np.int64)
    galleryLabel = np.array([[0,1,0],
                             [1,1,0],
                             [1,0,1],
                             [0,0,1],
                             [0,1,0],
                             [0,0,1],
                             [1,1,0]], dtype=np.int64)

    topk = 5

    topkmap = CalcTopMap(queryBinary, galleryBinary, queryLabel, galleryLabel, topk)
    print("map@{}为:{}".format(topk, topkmap))

    map = CalcMap(queryBinary, galleryBinary, queryLabel, galleryLabel)
    print("map为:{}".format(map))

    topkacc = CalcTopAcc(queryBinary, galleryBinary, queryLabel, galleryLabel, topk)
    print("acc@{}为:{}".format(topk, topkacc))

运行结果:

三、代码详解

参考:https://yongyuan.name/blog/evaluation-of-information-retrieval.html

           https://zhuanlan.zhihu.com/p/51955362

  • 27
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值