向量数据库FAISS之四:向量检索和 FAISS

来自 YouTube

1.相似度搜索的传统方法(Jaccard, w-shingling, Levenshtein)

1.Jaccard 距离

  1. 公式

    Jaccard ( A , B ) = 1 − ∣ A ∩ B ∣ ∣ A ∪ B ∣ \text{Jaccard}(A, B) = 1 - \frac{|A \cap B|}{|A \cup B|} Jaccard(A,B)=1ABAB

    其中, A 和 B 是两个集合。Jaccard 距离用于衡量两个集合的相似性,值在 0 到 1 之间,0 表示完全相同,1 表示完全不同。

  2. 使用场景

    • 文本比较:计算两个文档中词汇的相似度。
    • 聚类:用于计算文档、图像等对象的相似性。

2.w-shingling

  1. 定义

    w-shingling是一种将文本划分为重叠子字符串(或n-grams)的方法,w 代表子字符串的长度。

    例如,对于字符串 “abcde” 和 w = 3 ,可以得到 shingle 集合 {abc, bcd, cde}。

  2. 使用场景

    • 通常结合 Jaccard 相似度衡量不同的文本相似性
    • 文本相似度:通过生成w-shingles,然后计算Jaccard相似度来判断文本的相似度。
    • 近似重复文档检测。

3.Levenshtein 距离(编辑距离)

  1. 定义

    Levenshtein距离计算两个字符串之间通过插入、删除或替换操作变成相同字符串所需的最小操作次数。

  2. 使用场景

    • 拼写检查:判断两个字符串(单词)之间的编辑距离。
    • DNA序列比对:分析生物序列的相似性。

2.基于向量的相似度搜索(TF-IDF, BM25, SBERT)

在这里插入图片描述

1.TF-IDF

  1. 公式

    • TF(词频):某词 t 在文档 d 中出现的次数除以文档总词数:

      TF ( t , d ) = 词  t 在文档  d 中出现的次数 文档  d 的总词数 \text{TF}(t, d) = \frac{\text{词 } t \text{ 在文档 } d \text{ 中出现的次数}}{\text{文档 } d \text{ 的总词数}} TF(t,d)=文档 d 的总词数 t 在文档 d 中出现的次数

    • IDF(逆文档频率):词 t 在文档集合 D 中出现的频率的倒数:

      IDF ( t , D ) = log ⁡ ( ∣ D ∣ ∣ { d ∈ D : t ∈ d } ∣ ) \text{IDF}(t, D) = \log \left( \frac{|D|}{|\{d \in D : t \in d\}|} \right) IDF(t,D)=log({dD:td}D)

    • TF-IDF

      TF-IDF ( t , d , D ) = TF ( t , d ) × IDF ( t , D ) \text{TF-IDF}(t, d, D) = \text{TF}(t, d) \times \text{IDF}(t, D) TF-IDF(t,d,D)=TF(t,d)×IDF(t,D)

  2. 解决的问题

    • 衡量某个词在单个文档中的重要性,常用于文本检索和关键词提取
    • 通过IDF,减少在大多数文档中普遍出现的词(如“the”,“and”)的权重。
  3. 不足

    • 没有考虑词的位置、词序关系以及文档长度的影响
    • 对于长文档,TF-IDF会产生偏差,因为词频可能更高,但未必意味着其重要性更大。(比如有一篇文章专门讨论狗,狗出现的很多,但是未必重要)
    • 只能衡量词和文档的静态相关性,无法考虑用户查询的动态需求。

2.BM25

  1. 公式

    BM25 是 TF-IDF 的改进

    BM25 ( t , d ) = IDF ( t ) × TF ( t , d ) ⋅ ( k 1 + 1 ) TF ( t , d ) + k 1 ⋅ ( 1 − b + b ⋅ ∣ d ∣ avgdl ) \text{BM25}(t, d) = \text{IDF}(t) \times \frac{\text{TF}(t, d) \cdot (k_1 + 1)}{\text{TF}(t, d) + k_1 \cdot \left(1 - b + b \cdot \frac{|d|}{\text{avgdl}}\right)} BM25(t,d)=IDF(t)×TF(t,d)+k1(1b+bavgdld)TF(t,d)(k1+1)

    • TF ( t , d ) \text{TF}(t, d) TF(t,d) 是词 t t t 在文档 d d d 中的词频。
    • IDF ( t ) = log ⁡ ( N − n ( t ) + 0.5 n ( t ) + 0.5 ) \text{IDF}(t) = \log \left( \frac{N - n(t) + 0.5}{n(t) + 0.5} \right) IDF(t)=log(n(t)+0.5Nn(t)+0.5) 是词 t t t 的逆文档频率,其中 N N N 是总文档数, n ( t ) n(t) n(t) 是包含词 t t t 的文档数。
    • ∣ d ∣ |d| d 是文档 d d d 的长度, avgdl \text{avgdl} avgdl 是所有文档的平均长度。
    • k 1 k_1 k1 b b b 是调节参数,通常 k 1 ∈ [ 1.2 , 2.0 ] k_1 \in [1.2, 2.0] k1[1.2,2.0] b ≈ 0.75 b \approx 0.75 b0.75
  2. 解决的问题

    • 在TF-IDF 的基础上,BM25 加入了文档长度归一化的机制,避免了长文档在词频上的不公平优势。
    • BM25 是一种平衡频率和文档长度的动态模型,适用于实际的文档检索。
  3. 不足

    尽管在信息检索中表现优越,但对于词序、词义关系等更复杂的语义问题处理能力有限。

3.SBERT

  1. SBERT(Sentence-BERT) 是基于 BERT 模型的一种变体,专门用于生成句子的向量表示,以便更好地进行句子间的相似度计算和语义搜索

  2. 原理

    SBERT的主要目标是通过预训练的 BERT 模型,结合句子对比学习策略,生成高质量的句子嵌入(sentence embeddings),并在向量空间中表示这些句子的语义。

    原始 BERT 只能处理单个句子的方式不同SBERT 能高效计算句子相似度

  3. 步骤

    1. 句子嵌入生成:通过双塔结构(Siamese Network),输入的句子对分别通过共享权重的BERT编码器生成句子的嵌入向量
    2. 相似度计算:SBERT 使用余弦相似度、欧几里得距离等来衡量句子嵌入之间的相似性。
    3. 训练方式:SBERT 使用对比损失(Contrastive Loss)、**三元组损失(Triplet Loss)**或者基于自然语言推理(NLI)的数据集训练,以优化嵌入质量。

    双塔结构
    是一种神经网络结构,通常用于计算两个输入之间的相似性。它的核心思想是通过共享权重的两个子网络分别对两个输入进行编码,然后比较它们的输出向量来评估相似性

    工作原理

    1. 输入 → 两个文本或图像等

    2. 共享权重编码器

      两个子网络(塔)是共享参数的,即 他们使用完全相同的网络权重。

      对于输入 A 和 B,得到向量表示 E A E_A EA E B E_B EB

    3. 相似度计算

      E A E_A EA E B E_B EB 计算相似性,可以用余弦相似度欧几里得距离曼哈顿距离等度量方式来衡量两个输入在向量空间中的接近程度。

    4. 损失函数

      训练时,使用 对比损失(Contrastive Loss)或 三元组损失(Triplet Loss)来让相似输入的嵌入向量更接近,不相似输入的嵌入向量远离。

    5. 共享权重的优势

      通过共享参数,双塔结构保证了两个输入被同样处理,这避免了输入之间的不对称处理问题。

  4. 解决的问题

    • 句子相似度计算:BERT 只能处理句子对的相似度,而 SBERT 可以通过向量计算高效地处理大量句子的相似度问题,极大加速了计算过程。
    • 语义搜索:SBERT 可以将文本数据转化为语义向量,通过快速的余弦相似度计算,实现语义层面的搜索
    • 嵌入聚类:通过生成高质量的句子向量,SBERT 可以用于句子的聚类分析
  5. 不足

    • 计算开销:SBERT 在生成句子嵌入时仍然依赖于BERT模型,计算成本相对较高,尤其在处理长文本时。
    • 上下文依赖性不足:SBERT 生成的句子嵌入是固定的,缺乏对上下文动态变化的建模能力
    • 无法处理词序关系:SBERT 主要关注句子级别的语义嵌入,对于词序或细粒度的信息捕捉能力有限
  6. 代码

    在这里插入图片描述

3.faiss-相似度搜索介绍与如何选择索引

在这里插入图片描述

不同的索引在不同向量数量的查询时间对比。注意,纵轴是对数时间

  • 数据集

    import shutil
    import urllib.request as request
    from contextlib import closing# first we download the Sift1M dataset
    with closing(request.urlopen('ftp://ftp.irisa.fr/local/texmex/corpus/sift.tar.gz')) as r:with open('sift.tar.gz', 'wb') as f:shutil.copyfileobj(r, f)import tarfile# the download leaves us with a tar.gz file, we unzip it
    tar = tarfile.open('sift.tar.gz', "r:gz")
    tar.extractall()import numpy as np# now define a function to read the fvecs file format of Sift1M dataset
    def read_fvecs(fp):a = np.fromfile(fp, dtype='int32')d = a[0]return a.reshape(-1, d + 1)[:, 1:].copy().view('float32')# data we will search through
    xb = read_fvecs('./sift/sift_base.fvecs')  # 1M samples
    # also get some query vectors to search with
    xq = read_fvecs('./sift/sift_query.fvecs')
    # take just one query (there are many in sift_learn.fvecs)
    xq = xq[0].reshape(1, xq.shape[1])
    

    在这里插入图片描述

1.Flat Indexes

在这里插入图片描述

除此之外,也有 IndexFlatIP(**IP, Inner Product,**内积)

在这里插入图片描述

质量很高,但是速度很慢

d = 128
k = 10import faissindex = faiss.IndexFlatIP(d)
index.add(xb)%%time
D, I = index.search(xq, k)'''
CPU times: user 16.2 ms, sys: 2.14 ms, total: 18.4 ms
Wall time: 21.8 ms
'''
baseline = I[0].tolist()

2.LSH(局部敏感哈希)

在这里插入图片描述

与字典(尽量最小化碰撞)不同,LSH 尝试最大化碰撞。然后将搜索范围限制在一个桶内

nbits = d*4index = faiss.IndexLSH(d, nbits)
index.add(xb)%%time
D, I = index.search(xq, k)
'''
CPU times: user 3.3 ms, sys: 2.47 ms, total: 5.76 ms
Wall time: 5.37 ms
'''
np.in1d(baseline, I)
'''
array([ True,  True,  True,  True, False, False,  True, False, False,True])
'''

可以用 nbits 在速度与准确率直接找平衡

在这里插入图片描述

nibts 越高,召回率越高

在这里插入图片描述

但是,nbits 越高,速度越慢

3.HNSW

在这里插入图片描述

这是一个NSW图,图中两个顶点的距离为 4 跳。

以此类推,下面是 HNSW

在这里插入图片描述

同样需要四跳

M = 16 # 每个顶点的连接数
ef_search = 8 # 搜索的深度
ef_construction = 64 # 构建时的扩展因子,决定了在构建图时为每个点找到最近邻的搜索深度index = faiss.IndexHNSWFlat(d, M)index.hnsw.efSearch = ef_search
index.hnsw.efConstruction = ef_constructionindex.add(xb)%%time
D, I = index.search(xq, k)
'''
CPU times: user 366 μs, sys: 261 μs, total: 627 μs
Wall time: 1.27 ms
'''
np.in1d(baseline, I)
'''
array([ True,  True, False, False, False,  True, False, False,  True,True])
'''
# 以上不太准,调整 M 和 ef_search
M = 32 # 每个顶点的连接数
ef_search = 32 # 搜索的深度
ef_construction = 64 # 构建时的扩展因子,决定了在构建图时为每个点找到最近邻的搜索深度......
%%time
D, I = index.search(xq, k)
'''
CPU times: user 345 μs, sys: 133 μs, total: 478 μs
Wall time: 375 μs
'''
np.in1d(baseline, I)
'''
array([ True,  True, False,  True,  True,  True,  True, False,  True,True])
''

在这里插入图片描述

对比不同的 M、efConstruction 和 efSearch 组合的召回率

可以发现,

  • M 的大小对效果提升最明显
  • 其次是 efSearch
  • 最后是 efConstruction
  • 总结,efConstruction 最后大一些,M在 32-64 以上就可以了,efSearch = 32 是中位数,最好和 M 一起调节

在这里插入图片描述

不同的 M、efSearch 对查找时间的对比

  • 可以发现,efSearch = 32, M=32 就不错

4.IVF

在这里插入图片描述

其实这个算法就像聚类,通过调整 探针 nprobe 来权衡准确率是查找时间

nlist = 128 # 质心数量quantizer = faiss.IndexFlatIP(d)
index = faiss.IndexIVFFlat(quantizer, d, nlist)index.train(xb) # 需要训练!index.add(xb)index.nprobe = 1%%time
D, I = index.search(xq, k)
'''
CPU times: user 928 μs, sys: 305 μs, total: 1.23 ms
Wall time: 576 μs
'''
np.in1d(baseline, I)
'''
array([ True, False, False,  True,  True, False, False,  True, False,True])
'''
# 把探针改成 2
index.nprobe = 2
%%time
D, I = index.search(xq, k)
'''
CPU times: user 2.78 ms, sys: 2.16 ms, total: 4.93 ms
Wall time: 5.13 ms
'''
np.in1d(baseline, I)
'''
array([ True,  True,  True,  True,  True, False,  True,  True,  True,True])     
'''

在这里插入图片描述

不同探针和质心下的召回率和搜索时间

在这里插入图片描述

不同质心下的索引大小

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/20464.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Stata17最新保姆级安装教程【附安装包】

文章目录 Stata介绍 Stata下载 Stata安装步骤 Stata介绍 Stata 是一套提供其使用者数据分析、数据管理以及绘制专业图表的完整及整合性统计软件。它提供许许多多功能,包含线性混合模型、均衡重复反复及多项式普罗比模式等。 Stata下载 Stata 64位下载链接&…

jenkins离线安装插件

Jenkins 在线安装插件失败 报错: Caused: java.io.IOException: Failed to load https://updates.jenkins.io/download/plugins/login-theme/244.vd67c77f0c4c8/login-theme.hpi to /var/jenkins_home/plugins/login-theme.jpi.tmpat hudson.model.UpdateCenter$Up…

人工智能学习——前言

一、概论理解 首先何为人工智能?简单一句人话就是:人工操纵搭建出来的智能学习模型 那我们要用它干什么?简单一句话就是:我们给出指令 ——> 得到想要的结果 最简单的生活例子来看:就好比小狗,我们让它…

C++11——异常

1.异常概念 异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就会抛出异常,让函数的调用者处理这个错误 throw:当出现问题时,程序会抛出一个异常,通过 throw 来完成catch:catch 关键字捕获异…

腾讯:将LLM排序能力迁移至BERT

📖标题:Best Practices for Distilling Large Language Models into BERT for Web Search Ranking 🌐来源:arXiv, 2411.04539 🌟摘要 🔸最近的研究强调了大型语言模型(LLM)作为零样…

unity 打包WebGL打开后Input无法输入中文,在手机端无法调用输入法(使用WebGLInput)

成果展示 1、只是在电脑上运行时 使用TexMeshPro-InputField组件就可以输入中文了 2.不仅在电脑上运行,还需要在移动端运行 这个时候就需要使用WebGLInput插件,连接里有测试demo 1、下载后把WebGLSupport.unitypackage 导入到工程里 2、给input添加两…

服务器上部署并启动 Go 语言框架 **GoZero** 的项目

要在服务器上部署并启动 Go 语言框架 **GoZero** 的项目,下面是一步步的操作指南: ### 1. 安装 Go 语言环境 首先,确保你的服务器上已安装 Go 语言。如果还没有安装,可以通过以下步骤进行安装: #### 1.1 安装 Go 语…

如何通过统一权限管理打破异构系统的安全屏障

企业在运营过程中面临着众多异构系统的整合挑战,这些异构系统由于其不同的技术架构、数据格式和安全机制等,给信息管理带来了诸多挑战。其中,“信息孤岛”问题尤为突出,而异构环境下的统一授权管理系统则成为解决这一问题的关键。…

【IDEA】插件篇(JClassLib)

一、JClassLib 1、概述 jclasslib 字节码编辑器是一个可视化已编译Java类文件和包含的字节码的工具。 项目地址:https://github.com/ingokegel/jclasslib 其他反编译工具:javap、arthas 2、安装 IntelliJ IDEA -> Preferences -> Plugins&am…

机器学习阶段学习Day31

KNN分类算法 KNN算法原理 根据K个邻居样本来判断当前样本属于哪个类别:K个最相似邻居中大多数所属类别即为当前样本的类别。但是对于数据量巨大或者高纬度的数据样本不太合适,数据量大的数据样本需要进行大量计算,而高纬度数据计算距离不具…

深入理解前端路由

目录 前言1. 什么是路由2. Vue Router 的基础2.1 安装 Vue Router2.2 创建路由器2.3 在应用中使用 Vue Router 3. 路由切换与编程式导航3.1 声明式导航3.2 编程式导航 4. 子路由:结构化的路由管理4.1 子路由的定义4.2 子路由的渲染 5. 高级用法:路由守卫…

【UGUI】Unity 游戏开发:背包系统初始化克隆道具

在游戏开发中,背包系统是一个非常常见的功能模块。它允许玩家收集、管理和使用各种道具。今天,我们将通过一个简单的示例来学习如何在 Unity 中初始化一个背包系统。我们将使用 Unity 2021.3.7 版本,并结合 C# 脚本来实现这一功能。 1. 场景…

grafana+prometheus+windows_exporter实现windows进程资源占用的监控

grafanaprometheuswindows_exporter实现windows进程资源占用的监控TOC 一、 管理端搭建,采用windows版本的grafanaprometheus 管理端安装部署不做本文终端,简单讲解一下,此处采用msi的grafana安装包,和免安装版本的prometheus 1…

ElementUI之给el-table实现搜索功能

1&#xff0c;有一个表格 <el-table:data"tableData"borderstyle"width: 100%"><el-table-columnprop"date"label"日期"width"180"></el-table-column><el-table-columnprop"name"label&quo…

Chrome 浏览器 131 版本开发者工具(DevTools)更新内容

Chrome 浏览器 131 版本开发者工具&#xff08;DevTools&#xff09;更新内容 一、使用 Gemini 调试 CSS Chrome DevTools 现在推出了一个新的实验性 AI 辅助面板&#xff0c;可以与 Gemini 聊天并获得帮助来调试 CSS。 在 Elements 面板中&#xff0c;右键点击一个元素并选…

Ubuntu20.04 Rk3588 交叉编译ffmpeg7.0

firefly 公司出的rk3588的设备&#xff0c;其中已经安装了gcc 交叉编译工具&#xff0c;系统版本是Ubuntu20.04。 使用Ubuntu20.04 交叉编译ffmpeg_ubuntu下配置ffmpeg交叉编译器为arm-linux-gnueabihf-gcc-CSDN博客文章浏览阅读541次。ubuntu20.04 交叉编译ffmpeg_ubuntu下配…

蓝桥杯第22场小白入门赛2~5题

这场比赛开打第二题就理解错意思了&#xff0c;还以为只能用3个消除和5个消除其中一种呢&#xff0c;结果就是死活a不过去&#xff0c;第三题根本读不懂题意&#xff0c;这蓝桥杯的题面我只能说出的是一言难尽啊。。第四题写出来一点但是后来知道是错了&#xff0c;不会正解&am…

sagemaker中使用pytorch框架的DLC训练和部署cifar图像分类任务

参考资料 https://github.com/aws/amazon-sagemaker-examples/blob/main/sagemaker-python-sdk/pytorch_cnn_cifar10/pytorch_local_mode_cifar10.ipynbhttps://sagemaker.readthedocs.io/en/stable/frameworks/pytorch/using_pytorch.html 获取训练数据 # s3://zhaojiew-sa…

golang笔记8-函数

1. 基本函数 package mainimport "fmt"/*什么是函数&#xff1a;完成某一功能的程序指令的集合语法&#xff1a;func 函数名称(形参列表)(返回值类型列表){执行语句。。。返回值列表}注意事项&#xff1a;函数名&#xff1a;函数名首字母大写&#xff1a;可以被本包…

vite+vue3+ts编译vue组件后,编译产物中d.ts文件为空

一、前言 使用vue3vitets实现一个UI组件库&#xff0c;为了生成类型文件便于其他项目引用该组件库。根据推荐使用了vite-plugin-dts插件进行ts文件的生成 二、版本 组件版本vue ^3.5.12 vite ^5.4.10 vite-plugin-dts ^4.3.0 typescript ~5.6.2 三、问题描述 使用vitevi…