基于SimCSE和Faiss的文本向量检索实践

这篇具有很好参考价值的文章主要介绍了基于SimCSE和Faiss的文本向量检索实践。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

文本的向量表示

1、SimCSE

2、支持无监督训

3、训练注意事项

向量检索

1、精准查找flat

2、HNSWx

3、IVFx

4、PQx

5、LSH

对博客标题进行向量检索

数据向量化

构建索引

文本检索

测试检索


传统的文本检索一般是建立倒排索引,对搜索词的召回结果进行打分排序返回最终结果,但是在海量的数据面前,召回结果页面临着一些挑战。于是就有了基于语义的搜索,即将文本向量化,默认向量包含了文本的语义信息,匹配最近的向量返回结果。

文本的向量表示

文本的向量表示有很多种方式,例如:one-hot,tf-idf,word2vec,或者基于深度学习的sentence-bert,simbert等等,这里尝试采用近年来小有名气的SimCSE,据说在各种任务上面都达到了SOTA的水平,而且支持无监督的训练,这一点就足够吸引我们来试验一下效果了。

1、SimCSE

SimCSE: Simple Contrastive Learning of Sentence Embeddings,可以用来做句向量的表征训练,对于模型本身网上已经有很多介绍了,这里不做太多阐述,只介绍算法几个核心的点以及训练模型的注意事项。

2、支持无监督训

基于SimCSE和Faiss的文本向量检索实践,NLP的应用落地,faiss,深度学习,大数据,自然语言处理

很多句向量模型都是有监督的,构建正样本和负样本的数据集,这种方式大家比较容易想到,也比较好理解,结果的好坏也和标注数据息息相关。而无监督的模型就比较少见,SimCSE无监督训练构思比较巧妙,也很简单,给人一种大道至简的感觉。

SimCSE的入手点是一个batch的数据,没条样本数据自己和自己构成正样本,自己和其他数据构成负样本,负样本这里是没有问题,但是正样本自己和自己就缺少泛化能力,为了使正样本之间有所差异并且保持相似性,可以使用数据增强的方法,例如增加噪音或者GAN生成等方式,当然这就变成了另外的话题了。作者利用不同的dropout来产生正样本,同一个batch里面每个数据的dropout不一致

在构建无监督batch的数据时,同一条数据重复一次,即一个batch内最后的数据形式为:[a1,a1,a2,a2.....an,an]。为了方便理解,我们把最终的混淆矩阵画出来(带有+号的是经过drop生成的正样本):

a1 a1+ a2 a2+ ... an an+
a1 0 1 0 0 ... 0 0
a1+ 1 0 0 0 ... 0 0
a2 0 0 0 1 ... 0 0
a2+ 0 0 1 0 ... 0 0
... ... ... ... ... ... ... ...
an 0 0 0 0 ... 0 1
an+ 0 0 0 0 ... 1 0

归一化之后,使用相乘即可计算出来向量之间的cosine距离,接着可以计算出loss。


def simcse_loss(y_true, y_pred):
    """用于SimCSE训练的loss
    """
    # 构造标签
    idxs = K.arange(0, K.shape(y_pred)[0])
    idxs_1 = idxs[None, :]
    idxs_2 = (idxs + 1 - idxs % 2 * 2)[:, None]
    y_true = K.equal(idxs_1, idxs_2)
    y_true = K.cast(y_true, K.floatx())
    # 计算相似度
    y_pred = K.l2_normalize(y_pred, axis=1)
    similarities = K.dot(y_pred, K.transpose(y_pred))
    similarities = similarities - tf.eye(K.shape(y_pred)[0]) * 1e12
    similarities = similarities * 20
    loss = K.categorical_crossentropy(y_true, similarities, from_logits=True)
    return K.mean(loss)

3、训练注意事项

源码可以参考苏神开源的代码,另外苏神的博客也值得一看。

学习率设置为1e-5,dropout设置为0.3。

随机选取了1W条博客标题,训练一个epoch,即可得到很好的效果。多增加训练数据,或者训练epoch效果反而会下降。无监督训练确实让人很迷惑啊。

个人感觉SimCSE其实也没有真正学习到句子的语义,一个句子增加一个不字,变成语义相反的句子,计算其相似度还是挺高的,跨越语义鸿沟任道而重远,不知道gpt3/gpt4是不是距离真正的语义越来越近了。

向量检索

向量检索可以用ES,8.0版本听说优化了检索的算法,由于公司的ES还没有升级,也没能验证下大数据集检索的速度怎么样,若是能得到大幅度优化,ES还是首先的,毕竟其全文检索能力还是很强;也可以用Faiss,海量数据表现出色,但是其只是一个包,需要进行二次开发;更可以用milvus,是一个向量数据库,集成了Faiss,支持属性的索引联合搜索,但是也还存在一些坑,待后续版本完善。这里决定采用Faiss,单一字段的检索,Faiss还是能胜任的。

使用Faiss比较简单,但是要选择一个适合自己业务场景的索引类型很重要,现实场景中我们还要考虑数据量,召回率,内存大小,响应时间等因素,可以参考官方文档。

1、精准查找flat

基于穷举,召回率最高,但是速度慢,适合数据量比较小的场景。

2、HNSWx

基于图检索的方法,召回率高,检索速度快,但是构建索引慢,占用内存极大。

3、IVFx

基于倒排索引,IVFx中的x是k-means聚类中心的个数,使用倒排索引的思想减少检索时间。

4、PQx

基于乘积量化,分段检索,然后取交集,检索速度快,内存占用较小,但是召回率有所下降。

5、LSH

基于局部敏感哈希,占用内存小,检索速度快,但是召回率低。

考虑到生产环境的内存占用,检索的数据量在5000W+,这里使用网上比较推荐的IVFxPQy的索引方式,比较中规中矩的一种方法。

对博客标题进行向量检索

数据向量化

利用上面训练好的SimCSE模型,使用批推理的方式,将所有数据向量化,主要是为了利用批推理加快处理速度。

def data_to_vec(self):
    """数据向量化"""
    data_list = []
    batch_data = []
    count = 0
    with open(self.blog_data_path) as file:
        for line in file:
            terms = line.strip().split("\t")
            article_id, title = terms[0], terms[1]

            count += 1
            if count % 1000 == 0:
                print(f"processed: {count}")
            if len(batch_data) >= self.model_predict.model_config.batch_size:
                vecs = self.model_predict.predict_batch(batch_data)
                batch_data.clear()
                data_list.extend(vecs)
            batch_data.append(title)
    if len(batch_data):
        vecs = self.model_predict.predict_batch(batch_data)
        data_list.extend(vecs)
        batch_data.clear()

    xb = np.array(data_list, dtype=np.float32)
    np.save(self.data_vec_path, xb)
    print("save vector.")

构建索引

IVFx中x取100,PQy中y取16。

def create_index(self):
    """创建索引"""
    param = 'IVF100,PQ16'
    measure = faiss.METRIC_L2
    index = faiss.index_factory(self.model_predict.model_config.output_units, param, measure)

    xb = np.load(self.data_vec_path + ".npy")
    start_time = time.time()
    print("create index...")
    index.train(xb)
    index.add(xb)
    faiss.write_index(index, self.index_path)
    end_time = time.time()
    print(f"index created.cost:{end_time-start_time}")

文本检索

首先将句子转换成向量,再进行检索,取topk,然后计算余弦相似度,进行重新排序,输出结果。

def search(self, query, topk=5):
    """"搜索"""
    vec = self.model_predict.predict(query.lower())
    d, idx_list = self.index.search(np.array([vec]), topk)
    result_list = []
    for idx in range(len(idx_list[0])):
        data = self.data_list[idx_list[0][idx]]
        new_distance = self._cos_distinct(data, query)
        result_list.append((data, new_distance))
    sorted_result = sorted(result_list, key=lambda term: term[1], reverse=True)
    return sorted_result

测试检索

输入检索句子(就拿本文的标题来检索一下吧):

基于SimCSE和Faiss的文本向量检索实践

输出:

基于Lucene的全文检索实践
基于mongodb的地理检索实现
基于mongodb的地理检索实现
PostgreSQL的FTI与中文全文索引的实践
docker + laravel项目使用elasticsearch进行全文检索功能

再看一下CSDN官网的检索结果:

基于SimCSE和Faiss的文本向量检索实践,NLP的应用落地,faiss,深度学习,大数据,自然语言处理

 官网的结果基于词的全文检索,本文给的结果有那么一点儿语义的味道,但是距离真语义还是有一定差距,现在这个阶段的话倒是可以作为一个召回源对全文检索进行补充。

下课咯。文章来源地址https://www.toymoban.com/news/detail-589844.html

到了这里,关于基于SimCSE和Faiss的文本向量检索实践的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • AI实践与学习1_NLP文本特征提取以及Milvus向量数据库实践

    随着NLP预训练模型(大模型)以及多模态研究领域的发展,向量数据库被使用的越来越多。 在XOP亿级题库业务背景下,对于试题召回搜索单单靠着ES分片集群普通搜索已经出现性能瓶颈,因此需要预研其他技术方案提高试题搜索召回率。 现一个方案就是使用Bert等模型提取试

    2024年01月24日
    浏览(48)
  • 【向量数据库】相似向量检索Faiss数据库的安装及余弦相似度计算(C++)

    Faiss 是一个强大的向量相似度搜索库,具有以下优点: 高效的搜索性能:Faiss 在处理大规模向量数据时表现出色。它利用了高度优化的索引结构和近似搜索算法,可以快速地执行最近邻搜索和相似度匹配,具有很低的查询延迟。 高度可扩展:Faiss 提供了多种索引结构和算法

    2024年02月07日
    浏览(55)
  • 使用Spark ALS模型 + Faiss向量检索实现用户扩量实例

    1、通过ALS模型实现用户/商品Embedding的效果,获得其向量表示 准备训练数据, M = (U , I, R) 即 用户集U、商品集I、及评分数据R。 (1)商品集I的选择:可以根据业务目标确定商品候选集,比如TopK热度召回、或者流行度不高但在业务用户中区分度比较高的商品集等。个人建议量

    2024年02月13日
    浏览(40)
  • 基于Langchain的txt文本向量库搭建与检索

    这里的源码主要来自于Langchain-ChatGLM中的向量库部分,做了一些代码上的修改和封装,以适用于基于 问题 和 包含数据库表描述的txt文件 (文件名为库表名,文件内容为库表中的字段及描述)对数据库表进行快速检索。 splitter.py myfaiss.py embedder.py Config是用来传参的类,这里略

    2024年02月04日
    浏览(35)
  • 对句子分词,找到对应词的腾讯词向量模型并使用Python进行faiss检索

    目录 一、下载腾讯的词向量 二、停用词 三、代码部分         3.1、代码思想 四、输出结果         本文主要是将句子分词转向量,再加总词向量求平均变为句子向量。接着再存储到faiss中。等待新句子到来,同样按照上述方法处理。达到在faiss能检索出相似的向量。  

    2023年04月08日
    浏览(37)
  • 【深度学习】以图搜索- 2021sota repVgg来抽取向量 + facebook的faiss的做特征检索, 从环境搭建到运行案例从0到1

    Faiss的全称是Facebook AI Similarity Search。 这是一个开源库,针对高维空间中的海量数据,提供了高效且可靠的检索方法。 暴力检索耗时巨大,对于一个要求实时人脸识别的应用来说是不可取的。 而Faiss则为这种场景提供了一套解决方案。 Faiss从两个方面改善了暴力搜索算法存在

    2024年02月15日
    浏览(45)
  • LangChain 4用向量数据库Faiss存储,读取YouTube的视频文本搜索Indexes for information retrieve

    接着前面的Langchain,继续实现读取YouTube的视频脚本来问答Indexes for information retrieve LangChain 实现给动物取名字, LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字 LangChain 3使用Agent访问Wikipedia和llm-math计算狗的平均年龄 引用向量数据库Faiss 查看OpenAI model main.p

    2024年02月05日
    浏览(59)
  • 自然语言处理 Paddle NLP - 检索式文本问答-理论

    基础 自然语言处理(NLP) 自然语言处理PaddleNLP-词向量应用展示 自然语言处理(NLP)-前预训练时代的自监督学习 自然语言处理PaddleNLP-预训练语言模型及应用 自然语言处理PaddleNLP-文本语义相似度计算(ERNIE-Gram) 自然语言处理PaddleNLP-词法分析技术及其应用 自然语言处理Pa

    2024年02月11日
    浏览(56)
  • Elasticsearch:如何部署 NLP:文本嵌入和向量搜索

    作为我们自然语言处理 (NLP) 博客系列的一部分,我们将介绍一个使用文本嵌入模型生成文本内容的向量表示并演示对生成的向量进行向量相似性搜索的示例。我们将在 Elasticsearch 上部署一个公开可用的模型,并在摄取管道中使用它来从文本文档生成嵌入。然后,我们将展示如

    2024年02月05日
    浏览(54)
  • spark基于HNSW向量检索

    参考文档:https://talks.anghami.com/blazing-fast-approximate-nearest-neighbour-search-on-apache-spark-using-hnsw/ HNSW参数调优文档:https://github.com/nmslib/hnswlib/blob/master/ALGO_PARAMS.md spark 运行HNSW向量检索分为以下三步 1 创建HNSW索引,并存储到磁盘 2 将存储的索引分发到每个executor 3 进行向量检索 使用

    2024年02月11日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包