在一个给定向量数据集中,按照某种度量方式,检索出与查询向量相近的K个向量(K-Nearest Neighbor,KNN),但由于KNN计算量过大,我们通常只关注近似近邻(Approximate Nearest Neighbor,ANN)问题。
NSW
NSW在构图时,每次随机选择点,加入图中。每次加入点都查找与其最近邻的m点以添加边。最终形成如下图所示的结构:
在搜索 NSW 图时,我们从预定义的入口点开始。这个入口点连接到附近的几个顶点。我们确定这些顶点中的哪一个最接近我们的查询向量并移动到那里。
如从A开始,A的临近点C离P的距离更近更新。然后C的临近点D距离P更近,然后D的临近点B和F没有更近,程序停止,即为D点。
HNSW
图的构建从顶层开始。进入图表后,算法贪婪地遍历边,找到与我们插入的向量q最接近的ef邻居——此时ef = 1。
找到局部最小值后,它会向下移动到下一层(就像在搜索期间所做的那样)。重复这个过程,直到到达我们选择的插入层。这里开始第二阶段的建设。
ef值增加到我们设置的efConstruction参数,这意味着将返回更多最近的邻居。在第二阶段,这些最近的邻居是新插入元素q的链接的候选者, 并作为下一层的入口点。
经过多次迭代后,添加链接时还要考虑两个参数。M_max,它定义了一个顶点可以拥有的最大链接数,同样的M_max0,它定义了针对第 0 层中的顶点的最大连接数。
HNSW 代表 Hierarchical Navigable Small World,一个多层图。数据库中的每个对象都在最低层(图片中的第 0 层)中捕获。这些数据对象连接得很好。在最低层之上的每一层上,表示的数据点较少。这些数据点与较低层匹配,但每个较高层中的点呈指数级减少。如果有搜索查询,将在最高层找到最近的数据点。在下面的示例中,这只是多了一个数据点。然后它更深一层,从最高层中第一个找到的数据点中找到最近的数据点,并从那里搜索最近的邻居。在最深层,将找到最接近搜索查询的实际数据对象。
HNSW 是一种非常快速且内存高效的相似性搜索方法,因为只有最高层(顶层)保存在缓存中,而不是最低层中的所有数据点。只有最接近搜索查询的数据点在被更高层请求后才会被加载,这意味着只需要保留少量内存。
距离度量
目前实现的 HNSW 假设角距离,也称为余弦距离。这在技术上实现为导入时的向量归一化步骤(使数据具有相同的量级),然后进行点积计算,这相当于余弦。
References:
Paper—Approximate nearest neighbor algorithm based on navigable
small world graphs
Paper—Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs
VID—HNSW for Vector Search Explained and Implemented with Faiss (Python)
https://www.pinecone.io/learn/hnsw/
一文看懂HNSW算法理论的来龙去脉
CODE—nsw.html
VID—王炜教授分享 Approximate Nearest Neighbor Queries for High Dimensional Data
Video Google: A Text Retrieval Approach to Object Matching in Videos
Scalable Recognition with a Vocabulary Tree(基于词汇树的可伸缩识别)