平时学习中遇到的一些传统的做法
1、BM25算法
给你一个句子,和一个文档库。如果想找到与这个句子相关的文档,需要怎么做?
-
直接想法:对句子embedding,对文档库embedding。遍历文档库,计算余弦相似度,再排序。
- 稍微优化,计算的时候就排序,有点插入排序的感觉。
- 问题:遍历是 O ( n ) O(n) O(n),插入排序bad case是 O ( n 2 ) O(n^2) O(n2)【每次都要过一遍,所以是1+2+…n】。此外,向量维度大计算余弦相似度也有时间消耗。
-
先召回一批可能相关的,再利用embedding计算相似度。然后把召回得分与相似度得分加权。此时,可以考虑用BM25算法对文档进行召回。
BM25算法
- 作用:计算查询与文档的相关度
- 计算过程:对query中的每个词,计算其与文档的相似度得分,然后加权。
- 只能考虑到重合词的问题,无法顾及语义的信息(传统模型的通病)
- 核心公式:
S c o r e ( q u e r y , d o c ) = ∑ i = 1 n W i R ( q i , d o c ) Score(query,doc)=\sum_{i=1}^{n}W_iR(q_i,doc) Score(query,doc)=∑i=1nWiR(qi,doc)
W i W_i Wi是IDF值, q i q_i qi是query中的词 - 具体原理见:自然语言处理-BM25相关度打分
关于搜索,可以看这篇
召回后的排序
利用BM25算法召回了一批文档,得到了其embedding的矩阵(每个文档是一个向量)。如何更快计算query与所有文档的相似度呢?
Faiss流程与原理分析
Faiss是Facebook AI团队开源的针对聚类和相似性搜索库,为稠密向量提供高效相似度搜索和聚类,支持十亿级别向量的搜索,是目前最为成熟的近似近邻搜索库。它包含多种搜索任意大小向量集(备注:向量集大小由RAM内存决定)的算法,以及用于算法评估和参数调整的支持代码。Faiss用C++编写,并提供与Numpy完美衔接的Python接口。除此以外,对一些核心算法提供了GPU实现。
还可以参照这篇:Faiss相似性搜索类库
2、AC自动机
对于NER任务,直接的想法就是序列标注问题,bilstm+CRF来解决。模型的优劣是一方面,要想模型有好的表现,大量的标注数据是不可少的。而且就算精度很高,也会存在一些bad case。实际业务中,还需要很多规则。在NER任务中,如果有业务中的关键词库以及时间这种用正则表达式可以解决的,就可以解决一部分问题。
所以说,基于业务词典,就是给你一个词库,如果句子中的词存在于词库中,就提取出来。
自己的想法:
- 先将关键词库加入分词字典,分词
- 遍历句子中的词,如果词在词库中,就抽出来。
- 时间复杂度 O ( n ∗ m ) O(n*m) O(n∗m),n 是句子长度,m是词库词数。
- 如果词库很大,时间复杂度就很高
优化的方法,这是一个多模式匹配问题,解决方案是AC自动机算法,将词库构建成树,只需遍历一遍句子(应该是无需分词?)就可以得到结果。