相似性搜索:第 4 部分--分层可导航小世界 (HNSW)

news2024/11/28 14:38:06

SImilarity 搜索是一个问题,给定一个查询的目标是在所有数据库文档中找到与其最相似的文档。

一、介绍

        在数据科学中,相似性搜索经常出现在NLP领域,搜索引擎或推荐系统中,其中需要检索最相关的文档或项目以进行查询。在大量数据中,有各种不同的方法可以提高搜索性能。

        分层可导航小世界 (HNSW) 是一种最先进的算法,用于近似搜索最近的邻居。在后台,HNSW 构造了优化的图形结构,使其与本系列文章前面部分中讨论的其他方法非常不同。

HNSW的主要思想是构建这样一个图,其中任何一对顶点之间的路径都可以在少量步骤中遍历。

        关于著名的六次握手规则的一个众所周知的类比与这种方法有关:

所有人之间的社交关系都相距六或更少。

        在继续讨论 HNSW 的内部工作原理之前,让我们首先讨论跳过列表和可导航的小词——HNSW 实现中使用的关键数据结构。

二、跳过列表

        跳过列表是一种概率数据结构,允许在排序列表中平均插入和搜索 O(logn) 的元素。跳过列表由几层链表构成。最低层具有原始链表,其中包含所有元素。当移动到更高级别时,跳过的元素数会增加,从而减少连接数。

在跳过列表中查找元素 20

        特定值的搜索过程从最高级别开始,并将其下一个元素与该值进行比较。如果该值小于或等于该元素,则算法将继续执行其下一个元素。否则,搜索过程将下降到具有更多连接的较低层,并重复相同的过程。最后,算法下降到最低层并找到所需的节点。

        根据来自维基百科的信息,跳过列表具有主参数p,它定义了元素出现在多个列表中的概率。如果一个元素出现在层 i 中,那么它出现在层 i + 1 中的概率等于 p(p 通常设置为 0.5 或 0.25)。平均而言,每个元素都显示在1 / (1 - p)列表中。

        正如我们所看到的,这个过程比链表中的正常线性搜索要快得多。事实上,HNSW继承了同样的想法,但它不是链表,而是使用图表。

三、可导航的小世界

        可导航小世界是一个具有多对数 T = O(logkn) 搜索复杂性的图,它使用贪婪路由。路由是指从低度顶点开始搜索过程,以高度顶点结束的过程。由于低度顶点的连接很少,因此算法可以在它们之间快速移动,以有效地导航到最近邻居可能所在的区域。然后,算法逐渐放大并切换到高度顶点,以查找该区域顶点中的最近邻。

顶点有时也称为节点

3.1 搜索

        首先,通过选择入口点进行搜索。为了确定算法移动到的下一个顶点(或多个顶点),它会计算从查询向量到当前顶点的相邻顶点的距离,并移动到最近的顶点。在某些时候,当算法找不到比当前节点本身更靠近查询的邻居节点时,它会终止搜索过程。此节点作为对查询的响应返回。

        在可导航的小世界中贪婪的搜索过程。节点 A 用作入口点。它有两个邻居 B 和 D.节点 D 比 B 更接近查询。节点 D 有三个邻居 C、E 和 F.E 是离查询最近的邻居,所以我们移动到 E。最后,搜索过程将指向节点 L。由于 L 的所有邻居都比 L 本身离查询更远,因此我们停止算法并返回 L 作为查询的答案。

        这种贪婪的策略并不能保证它会找到确切的最近邻,因为该方法在当前步骤中仅使用本地信息来做出决定。提前停止是算法的问题之一。特别是在搜索过程开始时,当没有比当前节点更好的相邻节点时,它就会发生。在大多数情况下,当起始区域具有太多低度顶点时,可能会发生这种情况。

        提早停止。当前节点的两个邻居都离查询更远。因此,该算法返回当前节点作为响应,尽管存在更接近查询的节点。

        通过使用多个入口点可以提高搜索准确性。

3.2 建设

        NSW 图是通过随机排列数据集点并将其逐个插入到当前图中来构建的。插入新节点时,该节点将通过边链接到离该节点最近的 M 个顶点。

        顺序插入节点(从左到右),M = 2。在每次迭代中,都会向图形中添加一个新顶点,并链接到其 M = 2 个最近邻。蓝线表示连接到新插入节点的边。

        在大多数情况下,可能会在图形构建的开始阶段创建远程边缘。它们在图形导航中起着重要作用。

与在构造开始时插入的元素的最近邻居的链接稍后成为网络集线器之间的桥梁,这些网络集线器保持整体图形连接,并允许在贪婪路由期间对跃点数进行对数缩放。——俞.A.马尔科夫,D.A.亚舒宁

        从上图中的例子中,我们可以看到一开始添加的远程边缘AB的重要性。假设一个查询需要从相对遥远的节点 A 和 I 遍历路径。拥有边缘 AB 可以通过直接从图形的一侧导航到另一侧来快速完成此操作。

随着图中顶点数量的增加,新连接到新节点的边的长度将减小的可能性也会增加。

四、高净值

HNSW基于与跳过列表和可导航小世界相同的原则。它的结构表示一个多层图,顶层的连接较少,底层区域更密集。

4.1 搜索

        搜索从最高层开始,每次在层节点中贪婪地找到本地最近邻时,搜索都会进行到下面的一个级别。最终,在最低层找到的最近邻是查询的答案。

在HNSW中搜索

与新南威尔士州类似,HNSW的搜索质量可以通过使用多个入口点来提高。不是在每个层上只找到一个最近邻,而是找到与查询向量最近的 efSearch(超参数),并且这些邻域中的每一个都用作下一层的入口点。

4.2 复杂性

原始论文的作者声称,在任何层上找到最近邻所需的操作次数由一个常数限制。考虑到图中所有层的数量都是对数的,我们得到的总搜索复杂度为 O(logn)。

五、 HNSW建设

5.1 选择最大图层

        HNSW 中的节点按顺序逐个插入。每个节点都被随机分配一个整数 l,指示该节点可以在图形中呈现的最大层。例如,如果 l = 1,则节点只能在第 0 层和第 1 层上找到。作者为每个节点随机选择l,其指数衰减概率分布由非零乘数mL归一化(mL = 0导致HNSW中的单层和非优化的搜索复杂性)。通常,大多数 l 值应等于 0,因此大多数节点仅存在于最低级别。mL 值越大,节点出现在较高层上的概率就越大。

每个节点的层数l是随机选择的,概率分布呈指数衰减。

基于归一化因子mL的层数分布。水平轴表示均匀 (0, 1) 分布的值。

为了实现可控层次结构的最佳性能优势,不同层上的相邻元素之间的重叠(即也属于其他层的元素相邻元素的百分比)必须很小。——俞.A.马尔科夫,D.A.亚舒宁。

减少重叠的方法之一是减少毫升。但重要的是要记住,在对每层进行贪婪搜索期间,减少mL也会导致平均更多的遍历。这就是为什么必须选择这样一个 mL 值来平衡重叠和遍历次数的原因。

该论文的作者建议选择等于1 / ln(M)mL的最佳值。该值对应于跳过列表的参数p = 1 / M,是层之间的平均单个元素重叠。

5.2 插入

为节点分配值 l 后,其插入有两个阶段:

  1. 算法从上层开始,贪婪地找到最近的节点。然后,找到的节点用作下一层的入口点,搜索过程继续。到达l层后插入进入第二步。
  2. 从第 l 层开始,算法将新节点插入当前层。然后它的行为与之前在步骤 1 中相同,但它不是只找到一个最近的邻居,而是贪婪地搜索 efConstruction(超参数)最近的邻居。然后从 efConstruction 中选择 M 个相邻节点,并构建从插入节点到它们的边。之后,算法下降到下一层,每个找到的 efConstruction 节点充当入口点。算法在新节点及其边插入到最低层 0 后终止。

在 HNSW 中插入节点(蓝色)。新节点的最大层被随机选择为 l = 2。因此,节点将插入第 2、1 和 0 层。在这些层中的每一层上,节点将连接到其 M = 2 个最近的邻居。

5.3 选择构造参数的值

        原始论文提供了有关如何选择超参数的几个有用的见解:

  • 根据模拟,M 的良好值介于 5 和 48 之间。较小的 M 值往往更适合低召回率或低维数据,而较高的 M 值更适合高召回率或高维数据。
  • 更高的 efConstruction 值意味着随着更多候选者的探索,搜索更深入。但是,它需要更多的计算。作者建议选择这样的 efConstruction 值,在训练期间导致召回率接近 0.95-1
  • 此外,还有另一个重要参数 Mmₐₓ — 顶点可以具有的最大边数。除此之外,存在相同的参数 Mmₐₓ₀,但分别用于最低层。建议为 Mmₐₓ 选择一个接近 2 * M 的值。大于 2 * M 的值可能会导致性能下降和内存使用过多。同时,Mmₐₓ = M 会导致高召回率下性能不佳。

5.4 候选人选择启发式

        上面已经指出,在节点插入过程中,从 efConstruction 中选择 个候选者来构建它们的边。让我们讨论选择这些 M 节点的可能方法。

        天真的方法将M视为接近的候选人。然而,它并不总是最佳选择。下面是一个演示它的示例。

        想象一个如下图所示结构的图表。如您所见,有三个区域,其中两个区域未相互连接(左侧和顶部)。因此,例如,从A点到B点需要通过另一个区域的长路径。以某种方式连接这两个区域以获得更好的导航是合乎逻辑的。

        节点 X 将插入到图形中。目标是以最佳方式将其连接到其他 M = 2 点。

        然后将节点 X 插入到图中,并需要链接到 M = 2 个其他顶点。

        在这种情况下,朴素方法直接采用 M = 2 个最近的邻居(B 和 C)并将 X 连接到它们。虽然X连接到它真正的最近邻居,但它并不能解决问题。让我们看看作者发明的启发式方法。

启发式不仅考虑节点之间的最近距离,还考虑图上不同区域的连通性。

        启发式选择第一个最近的邻居(在我们的例子中为 B)并将插入的节点 (X) 连接到它。然后,该算法按排序顺序 (C) 顺序获取另一个最近的最近邻,并且仅当从该相邻节点到新节点 (X) 的距离小于从该相邻节点到所有已连接的顶点 (B) 到新节点 (X) 的任何距离时,算法才会构建一条边。之后,算法继续到下一个最近的邻居,直到构建 M 条边。

        回到示例,启发式过程如下图所示。启发式选择 B 作为 X 的最近邻,并构建边 BX。然后,该算法选择 C 作为下一个最近的最近邻。但是,这次BC<CX。这表明将边 CX 添加到图形中不是最佳选择,因为已经存在边 BX,并且节点 B 和 C 彼此非常接近。同样的类比在节点 D 和 E 上进行。之后,算法检查节点 A。这一次,它满足了自 BA > AX 以来的条件。因此,新的边 AX 和两个初始区域将相互连接。

左边的例子使用了朴素的方法。右边的示例使用选择启发式,它导致两个初始不相交区域相互连接。

5.5 复杂性

        与搜索过程相比,插入过程的工作方式非常相似,没有任何显着差异,可能需要非恒定数量的操作。因此,插入单个顶点会施加 O(logn) 的时间。要估计总复杂度,应考虑给定数据集中所有插入节点 n 的数量。最终,HNSW建设需要O(n * logn)时间。

六、将HNSW与其他方法相结合

        HNSW 可以与其他相似性搜索方法一起使用,以提供更好的性能。最流行的方法之一是将其与倒排文件索引和产品量化 (IndexIVFPQ) 结合使用,本文系列的其他部分对此进行了介绍。

        在此范式中,HNSW扮演IndexIVFPQ粗量化器的角色,这意味着它将负责查找最近的Voronoi分区,因此可以缩小搜索范围。要做到这一点,必须在所有Voronoi质心上建立一个HNSW指数。当给定查询时,HNSW 用于查找最近的 Voronoi 质心(而不是像以前那样通过比较与每个质心的距离进行暴力搜索)。之后,在相应的Voronoi分区中量化查询向量,并使用PQ代码计算距离。

        通过在 HNSW 中找到建在 Voronoi 质心之上的最近邻居来选择最近的 Voronoi 质心。

        当仅使用倒排文件索引时,最好将 Voronoi 分区的数量设置为不要太大(例如 256 或 1024),因为执行暴力搜索以查找最近的质心。通过选择少量的Voronoi分区,每个分区内的候选者数量变得相对较大。因此,该算法可以快速识别查询的最近质心,并且其大部分运行时都集中在查找 Voronoi 分区内的最近邻。

        但是,将 HNSW 引入工作流程需要进行调整。考虑仅在少量质心(256 或 1024)上运行 HNSW:HNSW 不会带来任何显著的好处,因为对于少量的向量,HNSW 在执行时间方面的性能与朴素暴力搜索相对相同。此外,HNSW需要更多的内存来存储图形结构。

这就是为什么在合并 HNSW 和倒排文件索引时,建议将 Voronoi 质心的数量设置为比平时大得多。通过这样做,每个Voronoi分区内的候选人数量就会少得多。

        范式的这种转变导致以下设置:

  • HNSW在对数时间内快速识别最近的Voronoi质心。
  • 之后,在各自的Voronoi分区内进行详尽的搜索。这应该不是麻烦,因为潜在候选人的数量很少。

七、费斯实施

Faiss(Facebook AI Search Similarity)是一个用C++编写的Python库,用于优化的相似性搜索。该库提供了不同类型的索引,这些索引是用于有效存储数据和执行查询的数据结构。

        根据 Faiss 文档中的信息,我们将了解如何利用 HNSW 并将其与倒排文件索引和产品量化合并在一起。

7.1 IndexHNSWFlat

        FAISS有一个实现HNSW结构的类IndexHNSWFlat。像往常一样,后缀“Flat”表示数据集向量完全存储在索引中。构造函数接受 2 个参数:

  • D:数据维度。
  • M:插入过程中需要添加到每个新节点的边数。

        此外,通过hnsw字段,IndexHNSWFlat提供了几个有用的属性(可以修改)和方法:

  • hnsw.efConstruction:施工期间要探索的最近邻居数量。
  • hnsw.efSearch:搜索期间要探索的最近邻居的数量。
  • hnsw.max_level:返回最大层数。
  • hnsw.entry_point:返回入口点。
  • faiss.vector_to_array(index.hnsw.levels):返回每个矢量的最大层数列表
  • hnsw.set_default_probas(M:整数,level_mult:浮点):允许分别设置 M 和 mL 值。默认情况下,level_mult设置为 1 / ln(M)。

Faiss 实现 IndexHNSWFlat

IndexHNSWFlat 为 Mmₐₓ = M 和 Mmₐₓ ₀ = 2 * M 设置值。

7.2 IndexHNSWFlat + IndexIVFPQ

I        ndexHNSWFlat 也可以与其他索引结合使用。其中一个例子是上一部分描述的IndexIVFPQ。此综合索引的创建分两个步骤进行:

  1. IndexHNSWFlat 初始化为粗量化器。
  2. 量化器作为参数传递给 IndexIVFPQ 的构造函数。

        可以使用不同或相同的数据来完成训练和添加。

IndexHNSWFlat + IndexIVFPQ 的 FAISS 实现

八、结论

        在本文中,我们研究了一种鲁棒算法,该算法特别适用于大型数据集向量。通过使用多层图表示和候选选择启发式,其搜索速度可以有效扩展,同时保持良好的预测精度。还值得注意的是,HNSW 可以与其他相似性搜索算法结合使用,使其非常灵活。

资源

  • 六度分离 |维基百科
  • 跳过列表 |维基百科
  • 使用分层可导航小世界图进行高效而强大的近似最近邻搜索。禹。A.马尔科夫,D.A.亚舒宁
  • 费斯文档
  • 费斯存储库
  • 费斯指数摘要

除非另有说明,否则所有图片均由作者提供。

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

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

相关文章

从0开始学go第八天

gin获取URL路径参数 package main//获取path&#xff08;URL&#xff09;参数 import ("net/http""github.com/gin-gonic/gin" )func main() {r : gin.Default()r.GET("/:name/:age", func(c *gin.Context) {//获取路径参数name : c.Param(&quo…

15 | JPA 对 Web MVC 开发者做了哪些支持

我们使用 Spring Data JPA 的时候&#xff0c;一般都会用到 Spring MVC&#xff0c;Spring Data 对 Spring MVC 做了很好的支持&#xff0c;体现在以下几个方面&#xff1a; 支持在 Controller 层直接返回实体&#xff0c;而不使用其显式的调用方法&#xff1b;对 MVC 层支持标…

如何通过Photoshop将视频转换成GIF图片

一、应用场景 1、将视频转有趣动图发朋友圈 2、写CSDN无法上传视频&#xff0c;而可以用GID动图替代 3、其他 二、实现步骤 1、打开Photoshop APP 2、点击文件——导入——视频帧到图层 3、选择视频文件 4、配置视频信息&#xff0c;按照图片提示配置完毕之后&#xff0c;…

gma 2.0.2 (2023.10.15) 更新日志

安装 gma 2.0.2 pip install gma2.0.2新增 0.1、矢量提取&#xff08;重要更新&#xff09; &#xff08;见简单示例&#xff09;   现在&#xff0c;你可以像 numpy 或 pandas 一样直接对 Layer 进行切片提取。 0.2、修改属性表&#xff08;重要更新&#xff09; &#xff…

数电第一次实验

四选一&#xff0c;信号选择器 三位4选1多路选择器 要求输入信号有4个&#xff0c;且每个信号宽3位 如果是直接根据选择信号选 选择的是信号&#xff0c;选择的是编号&#xff0c;与信号具体是什么内容无关&#xff0c;信号的内容与其是否被选择无关&#xff0c;信号的编号…

E034-服务漏洞利用及加固-利用CVE-2016-5195漏洞实现Linux系统本地提权

实验等级: 中级 任务场景: 【任务场景】 小王接到磐石公司的邀请&#xff0c;对该公司内部网络进行渗透测试&#xff0c;经过对局域网被操作系统进行全面的维护中&#xff0c;发现了一台内核版本为4.2.0-27的Linux服务器&#xff0c;低权限用户利用该漏洞技术可以在全版本L…

【笔记整理】软考-软件设计师

一、计算机系统 计算机基本单位 单位名称简称换算位bitb字节byteB1B8b千字节KB1KB1024B兆字节MB1MB1024KB吉字节GB1GB1024MB太字节TB1TB1024GB 带宽单位Mbps的b是指Bit&#xff08;位&#xff09; 速度单位MB/s的B是指Byte&#xff08;字节&#xff09; 1MB/s&#xff1d;8M…

Android 10.0 禁止弹出系统simlock的锁卡弹窗功能实现

1.前言 在10.0的系统开发中,在一款产品中,需要实现simlock锁卡功能,在系统实现锁卡功能以后,在开机的过程中,或者是在插入sim卡 后,当系统检测到是禁用的sim卡后,就会弹出simlock锁卡弹窗,要求输入puk 解锁密码,功能需求禁用这个弹窗,所以就需要看是 哪里弹的,禁用…

04-React脚手架

04-React脚手架 1. react脚手架入门 1).脚手架的介绍 xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目 包含了所有需要的配置&#xff08;语法检查、jsx编译、devServer…&#xff09;下载好了所有相关的依赖可以直接运行一个简单效果 react提供了一个用于创建rea…

R/d2及S/C4估计总体标准差,比较其CPK及规格限概率的差异

R/d2 和 S/C4 是用于估计总体标准差的无偏估计方法&#xff0c;通常用于控制图中。这些估计方法的主要目的是通过样本数据来估计总体标准差&#xff0c;以便监测过程的稳定性和变异性&#xff0c;而不需要收集整个总体的数据。 具体来说&#xff1a; R图中的 R/d2 和 S图中的…

【JAVA】有关包的概念

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️初识JAVA】 前言 Java包是用于组织和管理Java类的方式。它们提供了一种命名空间&#xff0c;以避免名称冲突&#xff0c;并使程序的组织更加有效和可维护。今天我们接着来学习有关包的概念。 包 …

faster lio 回环 加入GTSAM优化的记录

首先感谢这位博主的文章&#xff1a;https://blog.csdn.net/weixin_41281151/article/details/125371285&#xff0c;其中部分代码参考于改博主中的github&#xff1a; https://github.com/kahowang/FAST_LIO_SAM 不同的是&#xff0c;我使用的是faster lio进行更改&#xff0c…

vscode键盘输入不进去

二话不说&#xff0c;直接把输入切换到终端输出即可&#xff01; 打开设置&#xff0c;搜索terminal&#xff0c;切换到run in terminal 即可&#xff01;

C语言-指针相关使用

指针是 C语言的重要组成部分&#xff0c;是 C语言的核心、精髓。 在 C语言中&#xff0c;指针使用得当&#xff0c;能显著提高某些程序的效率&#xff0c;使用不当&#xff0c;则很容易造成系统错误、 一、指针使用 编译系统为每个变量都分配了一个能满足其类型大小的内存单…

vqvae简单实战,利用vqvae来提升模型向量表达

最近CV领域各种大模型在图像生成领域大发异彩&#xff0c;比如这两年大火的dalle系列模型。在这些模型中用到一个基础模型vqvae&#xff0c;今天我们写个简单实现来了解一下vqvae的工作原理。vqvae原始论文连接https://arxiv.org/pdf/1711.00937.pdf 1&#xff0c;代码 首先我们…

机器学习——奇异值分解二(特征分解+SVD纯理解)

矩阵的特征分解 特征值和特征向量的定义 抄来的&#xff1a;奇异值分解 困惑1&#xff1a;特征值和特征向量&#xff0c;和原矩阵是怎样的关系&#xff0c;需要一个栗子进行更具象的认识 困惑2&#xff1a;为什么多个特征向量组合成的矩阵&#xff0c;可以构成矩阵A的特征分解…

项目管理之实施关键步骤

项目管理已成为当代企业运营和发展过程中不可或缺的重要环节。如何实现高效、有序和可控的项目管理&#xff0c;一直是企业领导和项目团队追求的目标。本文将结合项目管理七招制胜内容&#xff0c;详细阐述项目管理实战中的具体做法。 如何分析项目 了解项目的背景和目的&…

网工记背配置命令(3)----POE配置示例

POE 供电就是通过以太网供电&#xff0c;这种方式仅凭借那根连接通信终端的网线就可完成为它们供电。POE提供的是-53V~0v 的直流电&#xff0c;供电距离最长可达 100m。PoE 款型的交换机的软件大包天然支持 POE&#xff0c;无需 license&#xff0c;通过执行 poe-enable 命令使…

【力扣1844】将所有数字用字符替换

&#x1f451;专栏内容&#xff1a;力扣刷题⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、题目描述二、题目分析 一、题目描述 给你一个下标从 0 开始的字符串 s &#xff0c;它的偶数下标处为小写英文字母&am…

系列七、Redis持久化

一、是什么 将内存中的数据写入到硬盘的过程。 二、持久化方式 RDB、AOF 2.1、RDB&#xff08;Redis Database&#xff09; 2.1.1、概述 在指定的时间间隔&#xff0c;执行数据集的时间点快照。实现类似照片记录效果的方式&#xff0c;就是把某一时刻的数据和状态以文件的形…