如何使用bm25算法检索出最相关的序列

CSU迦叶 CSU迦叶     2023-03-10     709

关键词:

背景

起因

博主正在进行的科研应用到了in-context learning这个范式,与传统的学习范式不同,情境中学习并不是真的学习,即不改变模型的参数,称为in-context inference 或许更为贴切。Icl不要求存在传统的训练集,但是依然需要少数几个有标签的样例(demostration)来告诉模型要做什么任务。那么模型推理结果的好坏很大程度上就取决于这几个样例给的好不好。

那么如何得到样例,一种思路是这样的,假定已经得到了一个demo pool(也许是传统学习范式中的训练集变化来的),对于任意一个query(和demo的区别是它没有标签),什么样的demos是好的呢?我们可以直观地联想到,和query越像,这个demo也就越适合作为icl中的样例。

BM25

BM25算法于2009年在论文The Probabilistic Relevance Framework: BM25 and Beyond中提出,可能是提出早的缘故,已经有python第三方库对它做了很好的实现,2023年我们只需会调用。

from rank_bm25 import BM25Okapi

使用过程

总体思路

两个步骤:1)将准备好的demo pool传给BM25okapi,这个过程会得到一个将哈希映射到序列的缓存字典 2)使用实例化后的BM25okapi,传入query,得到最相似的n个demo的哈希,再使用上一步得到的字典映射回序列。

代码

对于步骤一,我参照仓库(https://github.com/prompt-learning/cedar),单独定义了一个工具类Util,在当中定义了静态方法load_bm_25(),如下

class Util:
    @staticmethod
    def load_bm_25(bm_25_cache_dict, test_methods, demoPool:List[Oracle_datapoint_with_demo_length]):
        start_time = time.time()
        how_many_md5hash_conflicts = 0

        for dp in demoPool:
            tokenized_test_method = dp.datapoint.test_method.split(" ") # 匹配datapoint哪些元素之间的相似度是这里决定的
            md5hash = hashlib.md5(" ".join(tokenized_test_method).encode('utf-8')).hexdigest()

            if md5hash in bm_25_cache_dict:
                how_many_md5hash_conflicts += 1
            else:
                bm_25_cache_dict[md5hash] = dp
            test_methods.append(dp.datapoint.test_method)

        print("how_many_md5hash_conflicts: ", how_many_md5hash_conflicts)
        bm25 = BM25Okapi(test_methods)

        end_time = time.time()
        print("load_bm_25: ", end_time - start_time)
        print("The size of the bm25 cache is  bytes".format(sys.getsizeof(bm_25_cache_dict)))
        print(f"total entries: len(bm_25_cache_dict.keys())")
        return bm25

load_bm_25()有三个参数,分别是bm_25_cache_dict,test_methods,demoPool.下面分别说一下他们的作用:

首先前两个参数,传进去的分别是空字典和空列表,但是从函数出来以后,它们都被装载了内容,主要为了后期使用时候的校验。至于第三个参数demoPool,顾名思义,就是要把所有的候选demo给放在这个列表当中,类型是可以自定义的。但是注意看这一句

 bm25 = BM25Okapi(test_methods)

真正用来初始化BM25Okapi即构成池子的,其实是demoPool的一部分,test_methods。当然也可以不这么写,直接传入有内容的test_methods,这样第三个参数也就省去了。但是这样写还是有原因的,虽然对于每一个demo,我们只用它的一部分来比较和query的相关性,但毕竟这里的demo可以直接等价于行文时所说的例子。

步骤二的代码如下:

def bm25_retrived_demos(query:Oracle_datapoint,demoPool:List[Oracle_datapoint_with_demo_length])->List[Oracle_datapoint]:
    bm_25_cache_dict = 
    test_methods = []
    bm25 = Util.load_bm_25(bm_25_cache_dict, test_methods, demoPool)
    
    tokenized_query = query.test_method.split(" ")
    results_top_n = bm25.get_top_n(tokenized_query, test_methods, n=2)

    candidate_demonstrations:List[Oracle_datapoint] = []
    length_so_far = 0

    for r in results_top_n:
        md5hash_of_query = hashlib.md5(r.encode('utf-8')).hexdigest()

        if md5hash_of_query in bm_25_cache_dict:
            dp = bm_25_cache_dict[md5hash_of_query]

            candidate_demo_token_count = dp.token_count
            if (length_so_far + candidate_demo_token_count) <= 7000: # 7000暂时取代本应计算的max_demo_length
                candidate_demonstrations.append(dp.datapoint)
                length_so_far += candidate_demo_token_count
            else:
                break
        else:
            raise Exception("why key missing in the dict?")
        
    print("number of candidate demonstrations: ", len(candidate_demonstrations))
    return candidate_demonstrations

在第四行,调用了步骤一中定义的方法。此外最关键的一行代码是第七行

results_top_n = bm25.get_top_n(tokenized_query, test_methods, n=2)

前两个参数前面已经介绍过,最后一个参数用来决定返回前多少个最相似的序列。

来看一下最终的调用!

DATA_PATH = "sample/"
    dds = Dataset(
        DATA_PATH,
        "1_demo_pool_focal_method.txt" ,
        "2_demo_pool_test_method.txt" ,
        "3_demo_pool_focal_name.txt" ,
        "4_demo_pool_test_name.txt" ,
        "5_demo_pool_oracle.txt" ,
    )

demoPool : List[Oracle_datapoint] = []
demoPool = get_demo_pool(dds.parse())

candidate_demos = bm25_retrived_demos(query,demoPool)

bm25算法

参考技术Abm25是一种用来评价搜索词和文档之间相关性的算法,它是一种基于概率检索模型提出的算法,再用简单的话来描述下bm25算法:我们有一个query和一批文档Ds,现在要计算query和每篇文档D之间的相关性分数,我们的做法... 查看详情

elasticsearch实战-tf/idf/bm25分值计算(文本搜索排序分值计算,全文检索算法,文本相似度算法)

一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。TF-IDF加权的各种形式常被搜... 查看详情

elasticsearch实战-tf/idf/bm25分值计算(文本搜索排序分值计算,全文检索算法,文本相似度算法)

一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。TF-IDF加权的各种形式常被搜... 查看详情

bm25算法语义相似度计算(代码片段)

原理BM25算法,通常用来作搜索相关性平分。一句话概况其主要思想:对Query进行语素解析,生成语素qi;然后,对于每个搜索结果D,计算每个语素qi与D的相关性得分,最后,将qi相对于D的相关性得分进行加权求和,从而得到Query... 查看详情

bm25算法解析

...会计算出相应的得分,分数越高,代表相关度越高。BM25算法是ElstaticSearch默认的打分算法。BM25算法通常用来作为搜索相关性评分:对查询经进行语素解析,生成语素气;然后,对于每个搜索结果d,计算每个语素气与d的相关性得... 查看详情

bm25

BM25算法,通常用来作搜索相关性平分。一句话概况其主要思想:对Query进行语素解析,生成语素qi;然后,对于每个搜索结果D,计算每个语素qi与D的相关性得分,最后,将qi相对于D的相关性得分进行加权求和,从而得到Query与D的... 查看详情

文本相似度-bm25算法原理及实现

...;R(qi,d)表示语素qi与文档d的相关性得分。下面我们来看如何定义。判断一个词的权重,方法有多种,较常用的是IDF。这里以IDF为例,公式如下:其中,N为索引中的全部文档数,n(qi)为包含了qi的文档数。根据IDF的定义可以看出... 查看详情

文本抽取式摘要

...容,这个实现相对简单(常用算法TextRank、TF-IDF等,本文使用的是BM25算法)。另一种是生成式,生成式的构成比较复杂,实现难度也很大,效果在实际落地过程中也并不理想。所以下文主要是针对抽取式自动摘要来讨论的。问题... 查看详情

搜索之bm25和bm25f模型

...元如果模型)    近期在优化文本相关性。使用到BM25和BM25F模型。可是发现网络上关于BM25和BM25F模型的介绍比較少,在此总结一下,方便记忆,还有一方面搜了一下相关的资料,发现比較少。写下来欢迎大家查阅。... 查看详情

elasticsearch——评分机制详解

...过倒排索引可以获取与查询语句相匹配的文档列表,那么如何将最符合用户查询需求的文档放到前列呢?本质是一个排序问题,排序的依据是相关性算分。Elasticsearch使用的是termf 查看详情

常见统计模型(代码片段)

...性对搜索结果进行排序。?特点:与BM25效果相当,但需要使用大量文档语料库来训练,语料库最好与使用场景比较相似。布尔模型苹果AND公司:表示既包含“苹果”,有包含“公司”,这两个词的文档。苹果OR公司:表示搜索包... 查看详情

问答机器人召回优化(代码片段)

...学习,我们能够返回相似的召回结果,但是,如何让这些结果更加 查看详情

densepassageretrievalforopen-domainquestionanswering

...nQuestionAnswering段落检索是opendomianQA的重要问题传统方法是使用稀疏向量空间模型,如TF-IDF或BM25本文重点研究室是密集向量空间模型,密集表示采用简单的双层编码器框架,同时采用了非常少的问题和段落对传统检索... 查看详情

densepassageretrievalforopen-domainquestionanswering

...nQuestionAnswering段落检索是opendomianQA的重要问题传统方法是使用稀疏向量空间模型,如TF-IDF或BM25本文重点研究室是密集向量空间模型,密集表示采用简单的双层编码器框架,同时采用了非常少的问题和段落对传统检索... 查看详情

字符串查找与匹配之bm算法

...Codeblocks等编辑器中都有字符串查找功能。2、字符串查找算法是一种搜索算法,目的是在一个长的字符串中找出是否包含某个子字符串。二、字符串匹配:1、一个字符串是一个定义在有限字母表上的字符序列。例如,ATCTAGAGA是字... 查看详情

关于如何存储和检索时间序列数据的建议

】关于如何存储和检索时间序列数据的建议【英文标题】:Suggestionsonhowtostoreandretrievetime-seriesdata【发布时间】:2018-02-1522:25:11【问题描述】:我目前正在开展一个项目,该项目需要我们存储大量时间序列数据,但更重要的是,... 查看详情

推荐系统[八]算法实践总结v2:排序学习框架(特征提取标签获取方式)以及京东推荐算法精排技术实战

...。自从机器学习的思想逐步渗透到信息检索等领域之后,如何利用机器学习来提升信息检索的性能水平变成了近些年来非常热门的研究话题,因此产生了各类基于机器学习的排序算法,也带来了搜索引擎技术的成熟和发展,如今... 查看详情

推荐系统[八]算法实践总结v2:排序学习框架(特征提取标签获取方式)以及京东推荐算法精排技术实战

...问题。自从机器学习的思想逐步到信息检索等领域之后,如何利用机器学习来提升信息检索的性能水平变成了近些年来非常热门的研究话题,因此产生了各类基于机器学习的排序算法,也带来了搜索引擎技术的成熟和发展,如今... 查看详情