使用Sentence Transformers和Faiss构建语义搜索引擎

本文涉及的产品
Elasticsearch Serverless通用抵扣包,测试体验金 200元
简介: 使用Sentence Transformers和Faiss构建语义搜索引擎

640.png


介绍

您是否曾经想过如何使用Sentence Transformers创建嵌入向量,并在诸如语义文本相似这样的下游任务中使用它们?

在本教程中,您将学习如何使用Sentence Transformers和Faiss构建一个基于向量的搜索引擎。代码地址会在本文的最后提供

为什么要构建基于向量的搜索引擎?

基于关键字的搜索引擎很容易使用,在大多数情况下工作得很好。你要求机器学习论文,他们会返回一堆包含精确匹配或接近变化的查询结果,就像机器学习一样。其中一些甚至可能返回包含查询的同义词或出现在类似上下文中的单词的结果。其他的,如Elasticsearch,可以快速、可伸缩地完成所有这些功能,甚至更多。然而,基于关键词的搜索引擎通常会遇到以下问题:

  • 复杂查询或具有双重含义的单词。
  • 长查询,如论文摘要或博客中的一段。
  • 不熟悉某个领域术语的用户或想要进行探索性搜索的用户。

基于向量(也称为语义)的搜索引擎通过使用最先进的语言模型找到文本查询的数字表示,在高维向量空间中对它们进行索引,并度量查询向量与索引文档的相似程度,从而解决了这些缺陷。

索引、矢量化和排序方法

在深入学习本教程之前,我将简要解释基于关键字和基于向量的搜索引擎如何进行以下工作的

  • 索引文档(即以一种容易检索的形式存储它们
  • 向量化文本数据
  • 衡量文档与查询的相关性

这将帮助我们突出两种系统之间的差异,并理解为什么基于矢量的搜索引擎可以为长文本查询提供更有意义的结果。

1、基于关键字搜索引擎

让我们以一个过于简化的Elasticsearch为例。Elasticsearch使用标记器将文档分割成标记(即有意义的文本单位),这些标记映射到数字序列,并用于构建反向索引。

640.png

反向索引:与检查每个文档是否包含查询词不同,反向索引使我们能够查找一个词并检索包含该词的所有文档列表。源

同时,Elasticsearch用一个高维加权向量表示每个索引文档,其中每个不同的索引项是一个维度,它们的值(或权重)是用TF-IDF计算的。

为了找到相关文档并对其进行排序,Elasticsearch将布尔模型(BM)与向量空间模型(VSM)结合在一起。BM标记包含用户查询的文档,VSM评分它们的相关性。在搜索过程中,使用相同的TF-IDF管道将查询转换为向量,文档d对查询q的VSM得分为加权查询向量V(q)和V(d)的余弦相似度。

这种度量相似度的方法非常简单,而且不可扩展。Elasticsearch背后的工作机器是Lucene,它使用了各种技巧,从增强领域到改变矢量的标准化方式,以加快搜索速度和提高其质量。

Elasticsearch在大多数情况下工作得很好,然而,我们希望创建一个系统,也关注单词的上下文。这把我们带到了基于矢量的搜索引擎。

2、基于矢量的搜索引擎

我们还需要创建考虑单词上下文的文档表示。我们还需要一种高效可靠的方法来检索存储在索引中的相关文档。

创建密集的文档向量

近年来,NLP社区在这方面取得了长足的进步,许多深度学习模型都是开源的,并通过像Huggingface 's transformer这样的软件包进行分发,这些软件包提供了最先进的、经过预先训练的模型。使用预先训练好的模型有很多优点:

  • 它们通常生成高质量的嵌入,因为它们是在大量文本数据上训练的。
  • 它们不需要您创建自定义标记器,因为转换器有自己的方法。
  • 根据您的任务对模型进行微调很简单

这些模型为文档中的每个标记生成一个固定大小的向量。我们如何获得文档级向量呢?这通常通过平均或汇集单词向量来实现。然而,这些方法产生低于平均的句子和文档嵌入,通常比平均GloVe向量差。

为了构建我们的语义搜索引擎,我们将微调基于BERT的模型,以生成语义上有意义的长文本序列嵌入。

建立一个指数并衡量相关性

检索相关文档最简单的方法是测量查询向量和数据库中每个文档向量之间的余弦相似度,然后返回得分最高的那些。不幸的是,这在实践中非常缓慢。

首选的方法是使用Faiss,一个有效的相似度搜索和聚类密集向量库。Faiss提供了大量的索引和复合索引。此外,给定一个GPU, Faiss可扩展到数十亿个向量!

用Transformers 和Faiss构建一个基于向量的搜索引擎

在这个实际的例子中,我们将使用真实的数据。通过使用Orion查询微软的学术图表,我创建了一个包含8,430篇发表于2010年至2020年的关于错误信息、虚假信息和假新闻的学术文章的数据集。

我检索了论文的摘要、标题、引用、发表年份和ID。我做了最少的数据清理,比如删除没有摘要的论文。数据是这样的:

640.png

导入Python包并从S3读取数据

让我们导入所需的包并读取数据。该文件是公开的,所以您可以在谷歌Colab上运行代码,或者通过访问GitHub repo在本地运行代码!

#UsedtoimportdatafromS3.
importpandasaspdimports3fs#Usedtocreatethedensedocumentvectors.
importtorchfromsentence_transformersimportSentenceTransformer#UsedtocreateandstoretheFaissindex.
importfaissimportnumpyasnpimportpickle#Usedtodovectorsearchesanddisplaytheresults.
fromvector_engine.utilsimportvector_search, id2details#UsepandastoreadfilesfromS3buckets!df=pd.read_csv('s3://vector-search-blog/misinformation_papers.csv')

使用Sentence Transformers对文档进行矢量化

接下来,我们对论文摘要进行编码。Sentence Transformers提供了许多预先训练过的模型,其中一些可以在这个电子表格中找到。在这里,我们将使用base-nli- stbs -mean-tokens模型,该模型在语义文本相似度任务中表现出色,而且比BERT要快得多,因为它要小得多。

我们将做如下的工作:

  • 通过将模型名作为字符串传递来实例化transformer。
  • 切换到GPU,如果它是可用的。
  • 使用' .encode() '方法对所有论文摘要进行向量化。
#Instantiatethesentence-levelDistilBERTmodel=SentenceTransformer('distilbert-base-nli-stsb-mean-tokens')
#CheckifCUDAisavailableansswitchtoGPUiftorch.cuda.is_available():
model=model.to(torch.device("cuda"))
print(model.device)
#Convertabstractstovectorsembeddings=model.encode(df.abstract.to_list(), show_progress_bar=True)

建议使用GPU对文档进行矢量转换。

用Faiss索引文档

Faiss包含的算法可以在任意大小的向量集合中搜索,甚至是那些无法放入RAM的向量。要了解更多关于Faiss的信息,你可以在arXiv阅读他们的论文。

Faiss是围绕索引对象构建的,索引对象包含可搜索向量,有时还对其进行预处理。它处理一个固定维数d的向量集合,通常是几个10到100。

Faiss只使用32位浮点矩阵。这意味着在构建索引之前,我们必须更改输入的数据类型。

在这里,我们将使用IndexFlatL2索引来执行暴力的L2距离搜索。它在我们的数据集上工作得很好,但是,对于大型数据集,它会非常慢,因为它会随着索引向量的数量线性扩展。Faiss也提供快速索引!

要用抽象向量创建索引,我们将:

将抽象向量的数据类型更改为float32。

建立一个索引,并传递它将要操作的向量的维数。

将索引传递给IndexIDMap,该对象使我们能够为索引的向量提供id的自定义列表。

将抽象向量及其ID映射添加到索引。在我们的例子中,我们将从Microsoft Academic Graph将向量映射到它们的论文id。

为了测试索引是否按预期工作,我们可以使用索引向量查询它,并检索其最相似的文档以及它们的距离。第一个结果应该是我们的查询!

#Step1: Changedatatypeembeddings=np.array([embeddingforembeddinginembeddings]).astype("float32")
#Step2: Instantiatetheindexindex=faiss.IndexFlatL2(embeddings.shape[1])
#Step3: PasstheindextoIndexIDMapindex=faiss.IndexIDMap(index)
#Step4: AddvectorsandtheirIDsindex.add_with_ids(embeddings, df.id.values)
#Retrievethe10nearestneighboursD, I=index.search(np.array([embeddings[5415]]), k=10)

640.png

由于我们使用索引向量查询Faiss,因此第一个结果必须是查询,并且距离必须等于零!

搜索用户输入的查询

让我们尝试为新搜索查询找到相关的学术文章。在此示例中,我将使用WhatsApp的第一段查询索引,这可以从揭穿事实核查的故事中受益,以减少错误信息?

640.png

要检索学术文章以进行新的查询,我们必须:

  • 使用与抽象向量相同的句子DistilBERT模型对查询进行编码。
  • 将其数据类型更改为float32
  • 使用编码的查询搜索索引

为了方便起见,我将这些步骤包装在vector_search()函数中。

importnumpyasnpdefvector_search(query, model, index, num_results=10):
"""Tranforms query to vector using a pretrained, sentence-levelDistilBERT model and finds similar vectors using FAISS.Args:query (str): User query that should be more than a sentence long.model (sentence_transformers.SentenceTransformer.SentenceTransformer)index (`numpy.ndarray`): FAISS index that needs to be deserialized.num_results (int): Number of results to return.Returns:D (:obj:`numpy.array` of `float`): Distance between results and query.I (:obj:`numpy.array` of `int`): Paper ID of the results."""vector=model.encode(list(query))
D, I=index.search(np.array(vector).astype("float32"), k=num_results)
returnD, Idefid2details(df, I, column):
"""Returns the paper titles based on the paper index."""return [list(df[df.id==idx][column]) foridxinI[0]]
#QueryingtheindexD, I=vector_search([user_query], model, index, num_results=10)

我们输入的文字讨论了错误信息,事实检查,WhatsApp和巴西和印度的选举。我们希望基于矢量的搜索引擎返回有关这些主题的结果。通过检查论文标题,大多数结果看起来与我们的查询非常相关。我们的搜索引擎可以正常工作!

640.png

结论

在本教程中,我们使用Sentence Transformers和Faiss构建了一个基于矢量的搜索引擎。我们的索引效果很好,并且相当简单。我们可以使用像SciBERT这样的领域特定的转换器来提高嵌入的质量,该转换器已在语义库的语料库上的论文中进行了预训练。我们还可以在返回结果之前删除重复项并尝试其他索引。

对于使用Elasticsearch的人员,Open Distro引入了近似的k-NN相似性搜索功能,该功能也是AWS Elasticsearch服务的一部分。

最后,您可以在GitHub上找到代码(https://github.com/kstathou/vector_engine),并通过Google Colab进行尝试(https://colab.research.google.com/github/kstathou/vector_engine/blob/master/notebooks/001_vector_search.ipynb)。

相关实践学习
在云上部署ChatGLM2-6B大模型(GPU版)
ChatGLM2-6B是由智谱AI及清华KEG实验室于2023年6月发布的中英双语对话开源大模型。通过本实验,可以学习如何配置AIGC开发环境,如何部署ChatGLM2-6B大模型。
目录
相关文章
|
机器学习/深度学习 自然语言处理 算法
文本分析-使用jieba库进行中文分词和去除停用词(附案例实战)
文本分析-使用jieba库进行中文分词和去除停用词(附案例实战)
8698 0
|
存储 人工智能 OLAP
LangChain+通义千问+AnalyticDB向量引擎保姆级教程
本文以构建AIGC落地应用ChatBot和构建AI Agent为例,从代码级别详细分享AI框架LangChain、阿里云通义大模型和AnalyticDB向量引擎的开发经验和最佳实践,给大家快速落地AIGC应用提供参考。
131887 94
|
存储 自然语言处理 API
LlamaIndex使用指南
LlamaIndex是一个方便的工具,它充当自定义数据和大型语言模型(llm)(如GPT-4)之间的桥梁,大型语言模型模型功能强大,能够理解类似人类的文本。LlamaIndex都可以轻松地将数据与这些智能机器进行对话。这种桥梁建设使你的数据更易于访问,为更智能的应用程序和工作流铺平了道路。
5032 0
|
4月前
|
SQL 人工智能 数据可视化
开源AI BI可视化工具-WrenAI
Wren AI 是一款开源的 SQL AI 代理,支持数据、产品及业务团队通过聊天、直观界面和与 Excel、Google Sheets 的集成获取洞察。它结合大型语言模型(LLM)与检索增强生成(RAG)技术,助力用户高效处理复杂数据分析任务。
|
XML 存储 API
RAG效果优化:高质量文档解析详解
本文介绍了如何通过高质量的文档解析提升RAG系统整体的效果。
16530 15
|
JSON 数据可视化 API
GraphRAG+Ollama,构建本地精准全局问答系统!
RAG 是目前大语言模型相关最知名的工具之一,从外部知识库中检索事实,以便为大型语言模型 (LLM) 提供最准确、最新的信息。
|
10月前
|
文字识别
统一多模态Embedding, 通义实验室开源GME系列模型
随着多媒体应用的迅猛发展,用户产生的数据类型日益多样化,不再局限于文本,还包含大量图像、音频和视频等多模态信息。这为信息检索带来了前所未有的挑战与机遇。传统的信息检索模型多关注单一模态,如仅对文本或图像进行分析和搜索。
2074 6
|
11月前
|
SQL 存储 人工智能
Vanna:开源 AI 检索生成框架,自动生成精确的 SQL 查询
Vanna 是一个开源的 Python RAG(Retrieval-Augmented Generation)框架,能够基于大型语言模型(LLMs)为数据库生成精确的 SQL 查询。Vanna 支持多种 LLMs、向量数据库和 SQL 数据库,提供高准确性查询,同时确保数据库内容安全私密,不外泄。
1637 7
Vanna:开源 AI 检索生成框架,自动生成精确的 SQL 查询
|
11月前
|
机器学习/深度学习 人工智能
Qwen2VL-Flux:开源的多模态图像生成模型,支持多种生成模式
Qwen2VL-Flux 是一个开源的多模态图像生成模型,结合了 Qwen2VL 的视觉语言理解和 FLUX 框架,能够基于文本提示和图像参考生成高质量的图像。该模型支持多种生成模式,包括变体生成、图像到图像转换、智能修复及 ControlNet 引导生成,具备深度估计和线条检测功能,提供灵活的注意力机制和高分辨率输出,是一站式的图像生成解决方案。
1206 4
Qwen2VL-Flux:开源的多模态图像生成模型,支持多种生成模式
|
人工智能 并行计算 监控
深入剖析 Qwen2.5 - 32B 模型在 VLLM 上的单机三卡部署与运行
本文深入探讨了Qwen2.5 - 32B模型在VLLM框架上的部署过程,从模型下载、启动命令、资源占用分析到GPU资源分配及CUDA图应用,详述了大模型运行的挑战与优化策略,强调了硬件资源规划与技术调优的重要性。
7216 2