上一篇内容中,咱们理解了什么是 Faiss,以及如何将文本内容转换为向量数据。本篇文章中,咱们来应用 Faiss 实现向量检索性能。
应用 Faiss 实现最简略的向量检索性能
接下来,咱们将应用 Faiss 实现一个小性能,针对哈利波特小说全集内容,接触向量检索技术,实现类似内容搜寻的性能。与咱们应用“CTRL+F”或者把数据倒入 MySQL,应用“%LIKE%”去进行全文匹配不同,咱们的工具性能,将会远远高于个别的检索形式。
为了可能失去“快到飞起”的执行效率,在应用 Faiss 查问大量数据之前,咱们首先须要和其余谋求效率的数据库软件一样,为数据建设索引,咱们先来看看最简略的立体索引:IndexFlatL2
。
借助立体索引,实现根底的类似内容查问性能
Faiss 中最简略的索引,便是没有应用任何花哨技巧(压缩、分区等)的立体索引:IndexFlatL2
。当咱们应用这种索引的时候,咱们查问的数据会和索引中所有数据进行间隔计算,获取它们之间的 L2 间隔(欧几里得间隔)。因为它会尽职尽责的和所有数据进行比对,所以它是所有索引类型中最慢的一种,然而也是最简略和最精确的索引类型,同时,因为类型简略,也是内存占用量最低的类型。而它采取的遍历式查找,也会被从业者打趣称之为“暴力搜寻”。
在上文中,咱们曾经筹备好了 768 维度的高维向量数据,接下来,咱们就用这些数据来建设咱们的“第一堆向量数据”的索引:
import faiss
dimension = sentence_embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)
index.add(sentence_embeddings)
将咱们数据的维度信息传递给 faiss.IndexFlatL2
函数,建设一个空的索引容器,而后应用 index.add(sentence_embeddings)
将咱们在之前解决好的向量数据灌入这个索引容器中。
执行结束下面的代码之后,咱们执行 index.ntotal
来查看索引的数据是否正确:
# >>> index.ntotal
60028
确认所有数据都被索引之后,咱们来写一段最简略的程序,来进行查问,为了演示“相似性检索”,而不是“关键词匹配”,咱们来搜寻一个离谱的原文必定没有的内容“哈利波特猛然睡醒”:
topK = 5
search = model.encode(["哈利波特猛然睡醒"])
D, I = index.search(search, topK)
df['sentence'].iloc[I[0]]
执行程序之后,咱们将可能看到比拟合乎预期的神奇后果:
# >>> topK = 5
# >>> search = model.encode(["哈利波特猛然睡醒"])
# >>> D, I = index.search(search, topK)
# >>> df['sentence'].iloc[I[0]]
38216“我很好学生”哈利结巴的说擦着脸上的汗“我方才只是睡着了做了个恶梦。37890“我很好学生”哈利结巴的说擦着脸上的汗“我方才只是睡着了做了个恶梦。8009 那天早晨哈利失眠了。13996 最後哈利精疲力尽的爬上床猛拉他的四柱大床的蚊帐堵住射进来的一道月光翻身躺了进去而且简直立刻觉...
45306 罗恩立即就进入了梦乡然而哈利在上床之前从行李箱里翻出了他的那本《高级魔药制备》。Name: sentence, dtype: object
尽管没有齐全匹配关键词,然而咱们想要的内容还是被程序找到了。咱们每天都在应用的搜索引擎背地的泛滥技术之一,也包含相似的向量检索(将来有机会的话,咱们聊聊语义搜寻)。
进一步理解向量检索的细节
我晓得有一些同学,在惊叹下面这加起来不到 10 行的代码的成果之余,体验之后仍旧对于“向量”的感知是零。为了让大家清清楚楚的“入坑”,咱们先来开展聊聊下面的程序的含意。
topK = 5
search = model.encode(["哈利波特猛然睡醒"])
D, I = index.search(search, topK)
df['sentence'].iloc[I[0]]
第一行,topK
定义了咱们要查找多少条最类似的数据,比方这里我就只想查问 5 条数据,防止有人说我水文章字数 :D
第二行,咱们通过 model.encode
办法,来将要搜寻的内容“哈利波特猛然睡醒”编码为向量(行内人称这个过程的黑话为“embedding”)
第三行,则是应用咱们在前文中构建的 faiss 索引,来查找下面的“文本内容”,以及找到合乎预期数量的条数后就进行查找。
如果咱们将“D
和 I
”打印进去,能够看到相似上面的输入:
# >>> print (D)
[[206.22675 206.22675 212.70087 219.73259 221.30847]]
# >>> print (I)
[[38216 37890 8009 13996 45306]]
前者指的是“数据置信度 / 可信度”,而后者指的是咱们之前数据筹备时灌入的文本数据的具体行数。
最初一行,咱们应用 df['sentence'].iloc[I[0]]
来利用 pandas 的 DataFrame.iloc
接口,基于查问后果的行数,找到对应的文本的原文。如果咱们应用下面的“[38216 37890 8009 13996 45306]
”替换 iloc[I[0]]
中的数据,失去的后果也是一样的:
# >>> df['sentence'].iloc[[38216, 37890, 8009, 13996, 45306]]
38216“我很好学生”哈利结巴的说擦着脸上的汗“我方才只是睡着了做了个恶梦。37890“我很好学生”哈利结巴的说擦着脸上的汗“我方才只是睡着了做了个恶梦。8009 那天早晨哈利失眠了。13996 最後哈利精疲力尽的爬上床猛拉他的四柱大床的蚊帐堵住射进来的一道月光翻身躺了进去而且简直立刻觉...
45306 罗恩立即就进入了梦乡然而哈利在上床之前从行李箱里翻出了他的那本《高级魔药制备》。Name: sentence, dtype: object
聊完程序的执行过程,咱们来看看程序在“面对”的“向量”数据的真身是什么样的,以上文中后果中的第一条为例,咱们将 38216
这条在 faiss 索引中存储的数据进行向量重建:
>>> index.reconstruct(38216)
array([ 5.07521369e-02, -3.93364072e-01, -1.19723105e+00, -3.36433440e-01,
1.06395984e+00, 3.83257926e-01, 1.24985963e-01, 2.79548287e-01,
-7.02445269e-01, 7.59876966e-01, -5.09731807e-02, -5.78854322e-01,
-2.41243094e-01, -6.83130026e-01, 2.50904560e-01, -3.06654796e-02,
1.09606862e+00, 1.76596511e-02, 4.99801673e-02, -1.00713462e-01,
...
...
7.15905130e-01, 2.10034728e-01, 2.63317943e-01, 7.68652320e-01],
dtype=float32)
>>> len(index.reconstruct(38216))
768
“array”中的一堆应用迷信计数法示意的数据,就是咱们的向量数据,通过 len
办法来获取数据长度,咱们可能确认数据长度为 768,这个数据长度,就是被咱们称说为维度的神奇数字(能够施展设想,一个 768 维的平面世界)。
好啦,对于目前的咱们来说,理解到向量检索的过程和向量到这个水平就足够啦。如果你想对“FLAT”索引有更多理解,能够移步官网开源我的项目中的 [facebookresearch/faiss/blob/main/benchs/bench\_index\_flat.py]() 文件。
最初
和传统数据库相似,当咱们的数据量越来越大,用户规模越来越大之后,也会遇到性能问题,那么当类似度检索性能不够时,咱们该怎么办呢?
下一篇内容中,咱们将理解如何应用针对向量索引优化,来解决检索性能问题。
作者:苏洋
原文:《向量数据库入坑指南:聊聊来自元宇宙大厂 Meta 的类似度检索技术 Faiss》
链接:https://zhuanlan.zhihu.com/p/…
如果你感觉咱们分享的内容还不错,请不要悭吝给咱们一些激励:点赞、喜爱或者分享给你的小伙伴!
流动信息、技术分享和招聘速递请关注:https://zilliz.gitee.io/welcome/
如果你对咱们的我的项目感兴趣请关注:
用于存储向量并创立索引的数据库 Milvus
用于构建模型推理流水线的框架 Towhee