Closed Wenze7 closed 1 year ago
这个问题我之前也思考过。 我看T2 rank对4个level的定义如下:
只有0是不相关的,1应该也算相关吧。T2rank提到他们follow了TREC的标准,来定义了这4个level。
值得注意的是,你提到的代码里的evaluator, MTEB实际跑的时候是没有调用到的 实际用到的evaluator应该下面是这行: https://github.com/embeddings-benchmark/mteb/blob/main/mteb/abstasks/AbsTaskRetrieval.py#L54 MTEB在retrieval的任务上采用了BEIR的evaluator,BEIR用的包则是pytrec_eval,看上去和T2Rank的标准是一致的。
我在翻越pytrec_eval的时候看到了这个issue,看上去1-5的rel系数也是支持的。 https://github.com/cvangysel/pytrec_eval/issues/4
在计算dcg 的时候,如果我理解的没错的话,计算增益的方式应该是 (2**rel - 1) / (log2(i+2)) 如果rel系数为0的话,增益也为0。 所以我得到的结论就是T2rank计算dcg也不需要额外的处理,计算应该没有问题。
感谢!感谢!感谢!
这个问题我之前也思考过。 我看T2 rank对4个level的定义如下:
只有0是不相关的,1应该也算相关吧。T2rank提到他们follow了TREC的标准,来定义了这4个level。
值得注意的是,你提到的代码里的evaluator, MTEB实际跑的时候是没有调用到的 实际用到的evaluator应该下面是这行: https://github.com/embeddings-benchmark/mteb/blob/main/mteb/abstasks/AbsTaskRetrieval.py#L54 MTEB在retrieval的任务上采用了BEIR的evaluator,BEIR用的包则是pytrec_eval,看上去和T2Rank的标准是一致的。
我在翻越pytrec_eval的时候看到了这个issue,看上去1-5的rel系数也是支持的。 cvangysel/pytrec_eval#4
在计算dcg 的时候,如果我理解的没错的话,计算增益的方式应该是 (2**rel - 1) / (log2(i+2)) 如果rel系数为0的话,增益也为0。 所以我得到的结论就是T2rank计算dcg也不需要额外的处理,计算应该没有问题。
还想继续问下,在算MAP和MRR的时候还考虑这个相关性的档位吗?
实际的计算方式在pytrec_eval中应该有写,不过我c++实在不太好,没找到相关的代码。 不过根据我的理解,map@k是这样计算的:
所以看上去计算map@k是不会在意top k内部是如何排位的,个人理解这种指标应该是给retrieval这种粗排任务用的。 而对于精排的话,看ndcg应该更合理一些。
MAP 的计算是通过 pytrec_eval ,把大于等于 1(relevance_level) 的当作相关,没有挡位的概念了,只有 0 和 大于等于 1。
class RelevanceEvaluator(_RelevanceEvaluator):
def __init__(self, query_relevance, measures, relevance_level=1):
measures = self._expand_nicknames(measures)
measures = self._combine_measures(measures)
super().__init__(query_relevance=query_relevance, measures=measures, relevance_level=relevance_level)
MRR 的计算在 beir 的代码中,也没有挡位的概念,只把分数大于 0 或者说大于等于 1 的看成是相关。和 MAP 的默认实现一致。
def mrr(qrels: Dict[str, Dict[str, int]],
results: Dict[str, Dict[str, float]],
k_values: List[int]) -> Tuple[Dict[str, float]]:
MRR = {}
for k in k_values:
MRR[f"MRR@{k}"] = 0.0
k_max, top_hits = max(k_values), {}
logging.info("\n")
for query_id, doc_scores in results.items():
top_hits[query_id] = sorted(doc_scores.items(), key=lambda item: item[1], reverse=True)[0:k_max]
for query_id in top_hits:
query_relevant_docs = set([doc_id for doc_id in qrels[query_id] if qrels[query_id][doc_id] > 0]) # 注意这里
for k in k_values:
for rank, hit in enumerate(top_hits[query_id][0:k]):
if hit[0] in query_relevant_docs:
MRR[f"MRR@{k}"] += 1.0 / (rank + 1)
break
https://github.com/wangyuxinwhy/uniem/blob/9acd3ebf76bc0181fcbc4cad094acb0c4cad964b/mteb-zh/mteb_zh/tasks.py#L266 代码里好像写的是所有的档次的doc都放进了valid_qrels里。 而在MTEB的代码里,在算NDCG的IDCG的时候,只要出现在valid_qrels都算作1,其他都是0。这样那些低档的也算为正确了。 https://github.com/embeddings-benchmark/mteb/blob/582553693de507f338a720a0bc572147b8c6ef33/mteb/evaluation/evaluators/RetrievalEvaluator.py#L212 不知道是不是我的理解有问题,还是代码没考虑到?