向量数据库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.rhkb.cn/news/476737.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入探究蓝牙节能技术:SNIFF与HOLD模式

目录 一、概述 1.1. Sniff Mode(嗅探模式/呼吸模式) 1.1.1.定义与目的 1.1.2 工作原理 1.1.3 进入与退出 1.2. Hold Mode(保持模式) 1.2.1. 定义与目的 1.2.2. 工作原理 1.2.3. 进入 1.2.4. 通知机制 二、Sniff mode&a…

Linux驱动开发快速入门——字符设备驱动(直接操作寄存器设备树版)

Linux驱动开发快速入门——字符设备驱动 前言 笔者使用开发板型号:正点原子的IMX6ULL-alpha开发板。ubuntu版本为:20.04。写此文也是以备忘为目的。 字符设备驱动 本小结将以直接操作寄存器的方式控制一个LED灯,可以通过read系统调用可以…

ROS机器视觉入门:从基础到人脸识别与目标检测

前言 从本文开始,我们将开始学习ROS机器视觉处理,刚开始先学习一部分外围的知识,为后续的人脸识别、目标跟踪和YOLOV5目标检测做准备工作。我采用的笔记本是联想拯救者游戏本,系统采用Ubuntu20.04,ROS采用noetic。 颜…

电子电气架构 ---漫谈车载网关

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧,都是来源于自己的想象,只有你真的去做了,才会发现有多快乐。…

@Autowired与构造器注入区别,为什么spring推荐使用构造注入而不是Autowired?

目录 1.简介 2.了解两种注入方式的全过程 2.1 Autowired字段注入 2.2 构造函数注入 3.使用autowired注解注入有以下问题 3.1空指针异常 3.2测试不友好 4.使用Lombok去简化构造函数注入的臃肿代码 5.小结 5.1注解注入 5.2构造函数注入 1.简介 使用Spring开发时&#…

优化注意力层提升 Transformer 模型效率:通过改进注意力机制降低机器学习成本

Transformer 架构由 Vaswani 等人在 2017 年发表的里程碑式论文《Attention Is All You Need》中首次提出,如今已被广泛认为是过去十年间最具开创性的科学突破之一。注意力机制是 Transformer 的核心创新,它为人工智能模型提供了一种全新的方法&#xff…

在Excel中处理不规范的日期格式数据并判断格式是否正确

有一个Excel表,录入的日期格式很混乱,有些看着差不多,但实际多一个空格少一个字符很难发现,希望的理想格式是 1980-01-01,10位,即:“YYYY-mm-dd”,实际上数据表中这样的格式都有 19…

医工交叉入门书籍分享:Transformer模型在机器学习领域的应用|个人观点·24-11-22

小罗碎碎念 今天给大家推荐一本入门书籍。 这本书由Uday Kamath、Kenneth L. Graham和Wael Emara撰写,深入探讨了Transformer模型在机器学习领域的应用,特别是自然语言处理(NLP)。 原文pdf已经上传至知识星球的【入门书籍】专栏&…

SpringCloud Gateway转发请求到同一个服务的不同端口

SpringCloud Gateway默认不支持将请求路由到一个服务的多个端口 本文将结合Gateway的处理流程,提供一些解决思路 需求背景 公司有一个IM项目,对外暴露了两个端口8081和8082,8081是springboot启动使用的端口,对外提供一些http接口…

Parker派克防爆电机在实际应用中的安全性能如何保证?

Parker防爆电机确保在实际应用中的安全性能主要通过以下几个方面来保证: 1.防爆外壳设计:EX系列电机采用强大的防爆外壳,设计遵循严格的防爆标准,能够承受内部可能发生的爆炸而不破损,利用间隙切断原理,防…

虚拟形象+动作捕捉:解锁品牌N种营销玩法

近年来,随着Z世代年轻人对于二次元文化的热爱,各种二次元内容频频出圈。为了吸引年轻观众的注意,虚拟IP形象成为了品牌营销的“新宠”与“利器”为品牌踏入元宇宙蓝海提供了关键的切入点。在此背景下虚拟形象动作捕捉技术的组合应用方式正成为…

空间计算、物理计算、实时仿真与创造拥有「自主行为」的小狗 | 播客《编码人声》

「编码人声」是由「RTE开发者社区」策划的一档播客节目,关注行业发展变革、开发者职涯发展、技术突破以及创业创新,由开发者来分享开发者眼中的工作与生活。 虚拟世界与现实世界的界限逐渐模糊,已然成为不争的事实。但究竟哪些曾经的幻想已然…

影响电阻可靠性的因素

一、影响电阻可靠性的因素: 影响电阻可靠性的因素有温度系数、额定功率,最大工作电压、固有噪声和电压系数 (一)温度系数 电阻的温度系数表示当温度改变1摄氏度时,电阻阻值的相对变化,单位为ppm/C.电阻温度…

JAVA后端如何调用百度的身份证识别API

大家好,我是 程序员码递夫 。 今天给大家分享的是 JAVA后台如何调用百度的身份证识别API。 1、前言 我们做APP开发时常遇到 身份证认证或资质认证的 需求, 通过上传身份证照片是个常用的操作, 后台对上传的身份证照信息进行识别&#xff0…

Go语言进阶依赖管理

1. Go语言进阶 1.1 Goroutine package mainimport ("fmt""time" )func hello(i int) {println("hello goroutine : " fmt.Sprint(i)) }func main() {for i : 0; i < 5; i {go func(j int) { hello(j) }(i) // 启动一个新的 goroutine&…

基于Java Springboot高考志愿填报辅助系统

一、作品包含 源码数据库全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据库&#xff1a;…

autoware(2)运行自己的数据集

上一节完成了autoware.ai的安装和编译跑通了demo数据集&#xff0c;本将自己录制的数据包用于测试 1.修改点云地图 将加载点云地图的my_map.launch文件复制并命名为my_map_test.launch&#xff0c; &#xff08;1&#xff09;point cloud处替代原来的点云地图为自己的&#…

el-select 和el-tree二次封装

前言 本文章是本人在开发过程中&#xff0c;遇到使用树形数据&#xff0c;动态单选或多选的需求&#xff0c;element中没有这种组件&#xff0c;故自己封装一个&#xff0c;欢迎多多指教 开发环境&#xff1a;element-UI、vue2 组件效果 单选 多选 组件引用 <treeselec…

【LeetCode热题100】栈

这道题一共记录了关于栈的5道题目&#xff1a;删除字符串中所有相邻重复项、比较含退格的字符串、基本计算器II、字符串解码、验证栈序列。 class Solution { public:string removeDuplicates(string s) {string ret;for(auto c : s){if(ret.size() 0 || c ! ret.back()) ret …

《Python基础》之pip换国内镜像源

目录 推荐镜像源网址&#xff1a; 方法一&#xff1a;手动换源 方法二&#xff1a;命令提示符指令换源 临时换源 推荐镜像源网址&#xff1a; 阿里云&#xff1a;Simple Indexhttp://mirrors.aliyun.com/pypi/simple/ 华为云&#xff1a;Index of python-local https://m…