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

news2024/9/24 3:19:00

一、说明

        SImilarity 搜索是一个问题,给定一个查询的目标是在所有数据库文档中找到与其最相似的文档。相似度搜索(similarity search)是指在大规模数据集中寻找与某个查询对象最相似的对象的过程。该过程通常涉及计算两个对象之间的相似度得分(similarity score),然后按照得分排序,返回与查询对象最相似的前k个对象。相似度搜索在大规模数据集的相似性匹配问题中广泛应用,如图像检索、音频匹配、推荐系统、自然语言处理等领域。常见的相似度搜索算法包括基于余弦相似度的向量空间模型、基于海明距离的局部敏感哈希、基于编辑距离的最近邻搜索等。

二、介绍

        在数据科学中,相似性搜索经常出现在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) 搜索复杂性的图,它使用贪婪路由。路由是指从低度顶点开始搜索过程,以高度顶点结束的过程。由于低度顶点的连接很少,因此算法可以在它们之间快速移动,以有效地导航到最近邻居可能所在的区域。然后,算法逐渐放大并切换到高度顶点,以查找该区域顶点中的最近邻。

顶点有时也称为节点

4.1 搜索

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

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

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

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

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

4.2 建设

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

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

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

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

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

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

五、HNSW

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

5.1 搜索

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

在HNSW中搜索

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

5.2 复杂性

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

六、建设

6.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,是层之间的平均单个元素重叠。

6.2 插入

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

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

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

6.3 选择构造参数的值

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

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

6.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 和两个初始区域将相互连接。

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

6.5 复杂性

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

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

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

相似性搜索,第 3 部分:混合倒排文件索引和产品量化

在本系列的前两部分中,我们讨论了信息检索中的两种基本算法:倒置...

在此范式中,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 并将其与倒排文件索引和产品量化合并在一起。

8.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 设置值。

8.2 IndexHNSWFlat + IndexIVFPQ

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

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

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

IndexHNSWFlat + IndexIVFPQ 的 FAISS 实现

九、结论

        在本文中,我们研究了一种健壮的算法,该算法特别适用于大型数据集向量。通过使用多层图表示和候选选择启发式方法,其搜索速度可以有效地扩展,同时保持不错的预测准确性。还值得注意的是,HNSW可以与其他相似性搜索算法结合使用,使其非常灵活。维亚切斯拉夫·叶菲莫夫

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

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

相关文章

软件设计师学习笔记9-进程调度

目录 1. PV操作 1.1进程的同步与互斥 1.1.1互斥 1.1.2同步 1.2 PV操作 1.2.1信号量 1.2.2 PV操作的概念 2.信号量与PV操作 2.1 PV操作与互斥模型 2.2 PV操作与同步模型 2.3 互斥与同步模型结合 3.前趋图与PV操作 1. PV操作 1.1进程的同步与互斥 1.1.1互斥 互斥&…

Car Window Control Reset

大众汽车窗口自动升降失效&#xff0c;重置&#xff1a; 扣住5秒&#xff0c;重启汽车&#xff0c;试一下车钥匙&#xff0c;和再重试这个按钮&#xff0c;扣一下试一试

使用openWRT 配置SFTP 实现远程文件安全传输

文章目录 前言 1. openssh-sftp-server 安装2. 安装cpolar工具3.配置SFTP远程访问4.固定远程连接地址 前言 本次教程我们将在OpenWRT上安装SFTP服务&#xff0c;并结合cpolar内网穿透&#xff0c;创建安全隧道映射22端口&#xff0c;实现在公网环境下远程OpenWRT SFTP&#xf…

nginx空字节漏洞复现

将nginx复制到C盘根目录 cmd运行startup.bat 安装完成后访问 输入info.php 输入info.png 抓包使用00截断 可以看到phpinfo成功执行 在PHP的底层C语言里&#xff0c;%00代表着字符串结束&#xff0c;00截断可以用来绕过后端验证&#xff0c;后端验证的时候因为00截断认为文件是…

【已更新代码图表】2023数学建模国赛E题python代码--黄河水沙监测数据分析

E 题 黄河水沙监测数据分析 黄河是中华民族的母亲河。研究黄河水沙通量的变化规律对沿黄流域的环境治理、气候变 化和人民生活的影响&#xff0c;以及对优化黄河流域水资源分配、协调人地关系、调水调沙、防洪减灾 等方面都具有重要的理论指导意义。 附件 1 给出了位于小浪底水…

postgresql-使用plpgsql批量插入用户测试数据

目的 使用plpgsql批量插入用户测试数据 ❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤我是分割线❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤ 我的环境 客户端&#xff1a;windows 版pgadmin4 服务端&#xff1a;linux版PostgreSQL 15.4 ❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤…

Spring整合tomcat的WebSocket详细逻辑(图解)

主要解决存在的疑问 为什么存在2种spring整合websocket的方式&#xff0c;一种是使用ServerEndpoint注解的方式&#xff0c;一种是使用EnableWebSocket注解的方式&#xff0c;这2种有什么区别和联系&#xff1f;可以共存吗&#xff1f;它们实现的原理是什么&#xff1f;它们的各…

数据接口工程对接BI可视化大屏(二)创建BI空间

第2章 创建BI空间 2.1 SugarBI介绍 网站地址:https://cloud.baidu.com/product/sugar.html SugarBI是百度推出的自助BI报表分析和制作可视化数据大屏的强大工具。 基于百度Echarts提供丰富的图表组件&#xff0c;开箱即用、零代码操作、无需SQL&#xff0c;5分钟即可完成数…

C#__线程的优先级和状态控制

线程的优先级&#xff1a; 一个CPU同一时刻只能做一件事情&#xff0c;哪个线程优先级高哪个先运行&#xff0c;优先级相同看调度算法。 在Thread类中的Priority属性&#xff08;Highest,Above,Normal,BelowNormal,Lowest&#xff09;可以影响线程的优先级 关于…

PHP反序列化漏洞

一、序列化&#xff0c;反序列化 序列化&#xff1a;将php对象压缩并按照一定格式转换成字符串过程反序列化&#xff1a;从字符串转换回php对象的过程目的&#xff1a;为了方便php对象的传输和存储 seriallize() 传入参数为php对象&#xff0c;序列化成字符串 unseriali…

HTTP代理如何设置

HTTP代理是一种非常重要的网络工具&#xff0c;它可以帮助我们在访问互联网时提高访问速度&#xff0c;保护用户隐私等等。在使用HTTP代理时&#xff0c;需要先进行设置。下面就来介绍一下HTTP代理如何设置。 一、了解HTTP代理 在开始设置HTTP代理之前&#xff0c;我们需要先了…

系统架构技能之设计模式-组合模式

一、上篇回顾 我们上篇主要讲述了结构型模式中的外观模式&#xff0c;外观模式作为结构型模式中的一个简单又实用的模式&#xff0c;外观模式通过封装细节来提供大粒度的调用&#xff0c; 直接的好处就是&#xff0c;封装细节&#xff0c;提供了应用写程序的可维护性和易用性。…

Es6中的拓展运算符参数解构在实际项目当中应用

扩展操作符 … 是ES6中引入的&#xff0c;将可迭代对象展开到其单独的元素中,常见的应用场景有:拷贝数组对象,合并数组,参数传递,数组去重,字符串转字符数组,解构变量等 单纯的学习某个技术知识点,很容易的,但是能在实际项目中运用进去,那就不简单了的 单纯的学习某个语言的语法…

国家矿山安全监察局关于露天矿山边坡监测系统建设及预警响应要求

矿山是人类社会发展的物资基础&#xff0c;也是国民经济的重要组成部分。随着我国经济的快速增长&#xff0c;矿山开发步伐加快&#xff0c;使得边坡问题日益严重&#xff0c;影响了矿山的安全生产。为有效防范遏制矿山重特大事故发生&#xff0c;国家矿山安全监察局在8月30日发…

Laravel系列开源Dcat admin礼盒商城后台管理项目

前言: 在最近能在与某位前段大佬,合作开发一款项目,这宽项目是由laravel框架搭建使用的Dcat admin框架所制作的一个后台的管理系统,前段制作的是一款小程序,虽说后台管理系统无论是前段还是后端都是千篇一律,但内容也是非常丰富。但本项目仅作为开源学习和技术交流&#xff0c…

爬虫数据清洗可视化实战-就业形势分析

基于采集和分析招聘网站的数据的芜湖就业形势的调查研究 一、引言 本报告旨在分析基于大数据的当地就业形势&#xff0c;并提供有关薪资、工作地点、经验要求、学历要求、公司行业、公司福利以及公司类型及规模的详细信息。该分析是通过网络爬虫技术对招聘网站的数据进行采集…

校园二手物品交易系统微信小程序设计

系统简介 本网最大的特点就功能全面&#xff0c;结构简单&#xff0c;角色功能明确。其不同角色实现以下基本功能。 服务端 后台首页&#xff1a;可以直接跳转到后台首页。 用户信息管理&#xff1a;管理所有申请通过的用户。 商品信息管理&#xff1a;管理校园二手物品中…

蓝牙服务功能

前言 这阵子用到蓝牙比较多&#xff0c;想写一个专栏专门讲解蓝牙协议及其应用&#xff0c;本篇是第二篇文章&#xff0c;讲解蓝牙服务。 参考网上各大神文章&#xff0c;及瑞萨的文章&#xff0c;参考GPT&#xff0c;并且加入了一些本人的理解。 图片部分源自网络&#xff…

树形控件加自定义图标样式及指引线

记录一下留用&#xff0c;有错误请指正。 效果图如下&#xff1a; 自定义图标及指引线 代码&#xff1a; <div class"head-container" style"margin-left: -15px;"><el-tree icon-class"none"style"height:100%; overflow-y: h…

ffmpeg-android studio创建jni项目

一、创建native项目 1.1、选择Native C 1.2、命名项目名称 1.3、选择C标准 1.4、项目结构 1.5、app的build.gradle plugins {id com.android.application }android {compileSdk 32defaultConfig {applicationId "com.anniljing.ffmpegnative"minSdk 25targetSdk 32…