【推荐系统】HNSW

一、NSW

1.1【插入/创建索引】建图

向图中插入新点时,通过“随机”存在的一个点出发查找到距离新点最近的m个点(m由用户设置),
连接新点到这最近的m个点,over。

1.2【查询】

有三个点集合:candidates、visitedset、results。
其中candidates为当前要考察的点集合,visitedset为已经访问过的点集合,
results为当前距离查询点最近的点集合;前两者为变长,最后为定长。

1、随机选择一个点作为查询起始点entry_point,把该点加入candidates中,同时加入visitedset;
2、【结束条件】遍历candidates,从candidates中选择距离查询点query最近的点c,和results中距离查询点query最远的点d进行比较,
如果c和查询点q的距离大于d和查询点q的距离(results中已经存了最小的),说明当前图中所有距离查询点最近的点已经都找到了,
或者candidates为空;则结束查询。
3、从candidates中删除点c
4、遍历点c的所有邻居e(c比results中的d更小),如果e已经在visitedset中存在则跳过,不存在则加入visitedset
(把c的邻居e且dis(e,q)<dis(d,q)且未访问过,加入candidates、results)
5、把比d和q距离更近的e加入candidates、results中,
如果results未满,则把所有的e都加入candidates、results。
如果results已满,则弹出和q距离最远的点;
6、循环2-5

二、HNSW

借鉴了redis中跳表(“跳表”,Skip list是一个分层结构多级链表,最下层是原始的链表,每个层级都是下一个层级的“高速跑道”,
增加查询的速度,该方法与平衡树的方法是类似的(或者说是增加了索引),但是它更简单,更快,使用更少的空间。),加快检索速度;

layer=2
layer=1
layer=0 (第0层存储所有节点信息)

跳表的特点:
1、有序:每一层链表中的数据都是有序的;
2、分层:一个跳跃表应该有若干个层(Level)链表组成;跳跃表中最底层的链表包含所有数据;层数是从下往上越来越高,层数越低元素越多,如果一个元素X出现在第i层,那么编号比 i 小的层都包含元素X;
3、层与层之间相同元素用指针连接。第 i 层的元素通过一个指针指向下一层拥有相同值的元素;
4、首尾:在每一层中,-∞ 和 +∞两个元素都出现(分别表示INT_MIN 和 INT_MAX);
5、头指针(head)指向最高一层的第一个元素;

HNSW性质:
- 第0层中包含图中所有节点;
- 向上节点数依次减少,遵循指数衰减概率分布;
- 建图时新加入的节点由指数衰减概率函数得出该点最高投影到第几层;
- 从最高的投影层向下的层中该点均存在;
- 搜索时从上向下依次查询;

2.1【插入】

1、确认插入到第几层 L(由概率函数确定),依据是“指数衰减概率函数”;
2、自顶层向q的层数L逼近搜索,一直到 L+1,每层寻找当前层中,与query最近邻的1个点;
3、自L层向0层逼近搜索,每层寻找当前层中,q最近邻的efConstruction个点赋值到集合W;
4、在W中选择q最近邻的M个点作为neighbors双向连接起来;
5、检查每个neighbors的连接数,如果大于Mmax(最大的连接数),则需要缩减连接到最近邻的Mmax个(为了保证搜索效率,需要对每个node的出度做裁剪。)
原则:p1出度有p2,p3。d(p1, p2) < d(p1, p3) and d(p2, p3) < d(p1, p3),删除p1-p3)
删除更长的,且与已有的点也比较近。

2.2【查找】

顶层倒数第2层逼近搜索,每层寻找当前层q而最近的ef=1个点,加入W中;
取W中最接近q的点作为最底层的入口点,更快查找到q
从上一层得到的ep点开始搜索底层获得ef个q的最近邻。

在某一层中查询最近邻和NSW中的查询算法一致。

 参考:HNSW:https://zhuanlan.zhihu.com/p/397628955 

三、补充

1、KD-tree
2、LSH
树和 LSH 都属于空间切分类算法,所以空间切分类算法在最坏的情况下需要扫描几乎整个数据集。
3、IVFPQ 分桶+倒排索引
4、基于图的向量搜索算法

HNSW 和 NSG 的比较

HNSW 从结构入手,利用分层图提高图的导航性减少无效计算从而降低搜索时间,达到优化的目的。
而 NSG 选择将图的整体度数控制在尽可能小的情况下,提高导航性,缩短搜索路径来提高搜索效率。      
下面我们从内存占用,搜索速度,精度等方面来比较 HNSW 和 NSG。

HNSW 由于多层图的结构以及连边策略,导致搜索时内存占用量会大于 NSG,在内存受限场景下选择 NSG 会更好。
但是 NSG 在建图过程中无论内存占用还是耗时都大于 HNSW。
此外 HNSW 还拥有目前 NSG 不支持的特性,即增量索引,虽然耗时巨大。
对比其他的索引类型,无论 NSG 还是 HNSW 在搜索时间和精度两个方面,都有巨大优势。

【HNSW插入,建立连接】

新节点在插入到图中任意位置后,会建立 candidate pool,它用来保存所有搜索过的节点。
首先将插入位置附近的节点加入到 pool 中,从 pool 中挑选出距离最近的节点,再从它出发寻找更近的节点,找到后将其加入到 pool 中(下图 2-A 到 2-B ),
如果此节点都已搜索完毕,则挑选 pool 中的下一个节点进行搜索,不断循环N次,直至搜索到了 pool 的尾部,此时算法结束。
在此过程中,如果pool满了但却发现了更近的节点,那么将它插入到 pool 中,剔除最远的节点,
并且从新插入的位置处重新开始搜索(下图2-B到2-C)。这样减少了边的数量,改善了局部图的导航性。

 【搜索】

HNSW思想:按照一定的规则把一张的图分成多张,越接近上层的图,平均度数越低,节点之间的距离越远;
越接近下层的图平均度数越高,节点之间的距离也就越近。

搜索从最上层开始,找到本层距离最近的节点之后进入下一层。下一层搜索的起始节点即是上一层的最近节点,往复循环,


直至找到结果(见下图)。由于越是上层的图,节点越是稀少,平均度数也低,距离也远,所以可以通过非常小的代价提供了良好的搜索方向,通过这种方式减少大量没有价值的计算,减少了搜索算法复杂度。更进一步,如果把 HNSW 中节点的最大度数设为常数,这样可以获得一张搜索复杂度仅为 log(n) 的图。

Milvus 揭秘| 向量索引算法HNSW和NSG的比较 - 知乎

NSW建图

NSW的建图方式非常简单,就是向图中插入新点时,通过随机存在的一个点出发查找到距离新点最近的m个点(m由用户设置),
连接新点到这最近的m个点。减少出度。。。

->增加查询的速度

HNSW建图

  1. 新元素 q 插入(随便找一个点e,计算e的m个近邻与p的距离,不停传递直到找到最近的target,过程中连线,建立图);
  2. 在 hnsw 索引中查询距离 q 最近邻的 K 个元素。
  3. 自顶层向倒数第二层搜索,每层找到当前层q最近邻的rd=1个点,加入集合W中。取W中最近q的点作为入口点,计算近邻。

参考:

【论文笔记】HNSW ( Hierarchical Navigable Small World graphs) - 知乎

 按照论文的整体思路,按照NSW--> skip list --> HNSW的顺序进行学习。

分为“建立索引”、“查找”两个部分。

Milvus 揭秘| 向量索引算法HNSW和NSG的比较 - 顾钧的文章 - 知乎

HNSW学习笔记 - 知乎

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值