【问题标题】:MAP@k computationMAP@k 计算
【发布时间】:2019-07-24 18:24:00
【问题描述】:

根据wikiml metrics at kaggle,在 k 处计算的平均平均精度(对于答案中的前 k 个元素),而这个答案:Confusion about (Mean) Average Precision 应计算为k 处的平均精度,其中 k 处的平均精度计算为:

其中:P(i) 是列表中截止 i 处的精度; rel(i) 是一个指示函数,如果排名 i 的项目是相关文档,则等于 1,否则为零。

分隔符min(k, number of relevant documents) 的含义是答案中相关条目的最大可能数量。

这种理解正确吗?

MAP@k 是否总是小于为所有排名列表计算的 MAP?

我担心的是,这不是许多作品中计算 MAP@k 的方式。

很典型,分隔符不是min(k, number of relevant documents),而是top-k中相关文档的数量。这种方法将给出更高的 MAP@k 值。


HashNet: Deep Learning to Hash by Continuation" (ICCV 2017)

代码: https://github.com/thuml/HashNet/blob/master/pytorch/src/test.py#L42-L51

    for i in range(query_num):
        label = validation_labels[i, :]
        label[label == 0] = -1
        idx = ids[:, i]
        imatch = np.sum(database_labels[idx[0:R], :] == label, axis=1) > 0
        relevant_num = np.sum(imatch)
        Lx = np.cumsum(imatch)
        Px = Lx.astype(float) / np.arange(1, R+1, 1)
        if relevant_num != 0:
            APx.append(np.sum(Px * imatch) / relevant_num)

其中relevant_num不是min(k, number of relevant documents),而是结果中相关文档的数量,与相关文档的总数或k不同。

我是不是读错了代码?


Deep Visual-Semantic Quantization of Efficient Image Retrieval CVPR 2017

代码:https://github.com/caoyue10/cvpr17-dvsq/blob/master/util.py#L155-L178

def get_mAPs_by_feature(self, database, query):
    ips = np.dot(query.output, database.output.T)
    #norms = np.sqrt(np.dot(np.reshape(np.sum(query.output ** 2, 1), [query.n_samples, 1]), np.reshape(np.sum(database.output ** 2, 1), [1, database.n_samples])))
    #self.all_rel = ips / norms
    self.all_rel = ips
    ids = np.argsort(-self.all_rel, 1)
    APx = []
    query_labels = query.label
    database_labels = database.label
    print "#calc mAPs# calculating mAPs"
    bar = ProgressBar(total=self.all_rel.shape[0])
    for i in xrange(self.all_rel.shape[0]):
        label = query_labels[i, :]
        label[label == 0] = -1
        idx = ids[i, :]
        imatch = np.sum(database_labels[idx[0: self.R], :] == label, 1) > 0
        rel = np.sum(imatch)
        Lx = np.cumsum(imatch)
        Px = Lx.astype(float) / np.arange(1, self.R+1, 1)
        if rel != 0:
            APx.append(np.sum(Px * imatch) / rel)
        bar.move()
    print "mAPs: ", np.mean(np.array(APx))
    return np.mean(np.array(APx))

其中divider 为rel,计算为np.sum(imatch),其中imatch 是指示条目是否相关的二进制向量。问题是它只需要第一个R:imatch = np.sum(database_labels[idx[0: self.R], :] == label, 1) > 0。所以np.sum(imatch) 将在返回的大小为R 的列表中给出相关条目的数量,而不是min(R, number of relevant entries)。请注意,论文中使用的R 的值小于数据库中的条目数。


Deep Learning of Binary Hash Codes for Fast Image Retrieval (CVPR 2015)

代码:https://github.com/kevinlin311tw/caffe-cvprw15/blob/master/analysis/precision.m#L30-L55

    buffer_yes = zeros(K,1);
    buffer_total = zeros(K,1);
    total_relevant = 0;
    
    for j = 1:K
        retrieval_label = trn_label(y2(j));
        
        if (query_label==retrieval_label)
            buffer_yes(j,1) = 1;
            total_relevant = total_relevant + 1;
        end
        buffer_total(j,1) = 1;
    end
    
    % compute precision
    P = cumsum(buffer_yes) ./ Ns';
    
    if (sum(buffer_yes) == 0)
        AP(i) = 0;
    else
        AP(i) = sum(P.*buffer_yes) / sum(buffer_yes);
    end

这里的分隔符是sum(buffer_yes),它是返回的k列表中相关文档的数量,而不是min(k, number of relevant documents)


"Supervised Learning of Semantics-Preserving Deep Hashing" (TPAMI 2017)

代码:https://github.com/kevinlin311tw/Caffe-DeepBinaryCode/blob/master/analysis/precision.m

代码与上一篇论文中的相同。


Learning Compact Binary Descriptors with Unsupervised Deep Neural Networks (CVPR 2016)

相同的代码:https://github.com/kevinlin311tw/cvpr16-deepbit/blob/master/analysis/precision.m#L32-L55



我错过了什么吗?上述论文中的代码是否正确?为什么和https://github.com/benhamner/Metrics/blob/master/Python/ml_metrics/average_precision.py#L25-L39不一致?


更新

我发现了这个已关闭的问题,指的是同样的问题:https://github.com/thuml/HashNet/issues/2

以下声明是否正确?

AP 是一个排名指标。如果排名列表中的前 2 个检索是相关的(并且只有前 2 个),则 AP 为 100%。你说的是召回率,在这种情况下确实是 0.2%。

据我了解,如果我们将 AP 视为 PR 曲线下的面积,则上述说法是不正确的。


附:我怀疑这是否应该去 Cross Validated 或 StackOverflow。如果您认为最好将其放置在交叉验证中,我不介意。我的理由是,这不是一个理论问题,而是参考实际代码的实现问题。

【问题讨论】:

    标签: python matlab information-retrieval precision-recall average-precision


    【解决方案1】:

    您找到这个是完全正确的,做得很好。鉴于代码的相似性,我的猜测是有一个源错误,然后论文接二连三地复制了错误的实现而没有仔细检查。

    “akturtle”问题提出者也完全正确,我打算举同样的例子。我不确定“kunhe”是否理解这个论点,当然在计算平均精度时召回很重要。

    是的,错误应该夸大数字。我只是希望排名列表足够长,方法足够合理,使得他们在排名列表中达到 100% 的召回率,在这种情况下,bug 不会影响结果。

    不幸的是,审稿人很难发现这一点,因为通常不会审阅论文代码。值得联系作者尝试让他们更新代码,用正确的数字更新他们的论文,或者至少不要继续在他们未来的作品中犯错误。如果您打算写一篇比较不同方法的论文,您可以指出问题并报告正确的数字(以及可能存在错误的数字,只是为了比较苹果)。

    回答你的附带问题:

    MAP@k 是否总是小于为所有排名列表计算的 MAP?

    不一定,MAP@k 本质上是计算 MAP,同时对仅给定 k 次检索就无法做得更好的潜在情况进行规范化。例如。考虑返回的具有相关性的排名列表: 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 并假设总共有 6 个相关文件。此处的 MAP 应略高于 50%,而 MAP@3 = 100%,因为您无法比检索 1 1 1 做得更好。 但这与您发现的错误无关,因为他们的错误保证 MAP@k 至少与真正的 MAP@k 一样大。

    【讨论】:

    • 当然,我指的是最后一个例子中的 AP@k,但 MAP@k 紧随其后(例如,如果查询数为 1,或者这种事情在您的查询中经常发生..
    • 感谢您的回答。我会尝试联系论文的作者。
    猜你喜欢
    • 2010-11-04
    • 1970-01-01
    • 1970-01-01
    • 2012-12-08
    • 2014-05-20
    • 2019-10-10
    • 1970-01-01
    • 2013-11-26
    • 2019-07-01
    相关资源
    最近更新 更多