近似最近邻检索ANNS学习记录
向量介绍
向量就是一个数组,数组元素称为向量的每一个维度值;通常情况下每一个维度的值是数字形式。
问题阐述
检索问题,就是在向量数据集中,检索出相似向量簇;本质做法包括下面两种:
- KNN:K-Nearest Neighbor
- ANN:Approximate Nearest Neighbor
算法思想:牺牲精度换取时间和空间;
近似检索就是通过特定的索引结构,将整个高维向量空间构建向量索引,映射到低维或者小范围向量空间,在映射后的空间中检索;
典型场景
- 高性能
- 海量数据
常见距离度量
名称 | 简介 | 备注 |
欧式距离 | ||
余弦距离 | ||
汉明距离 | ||
内积 |
评估指标:召回率(精度)定义:给定的向量Q,在数据集上的K近邻为N;通过检索召回的K个近邻为M,则召回率为:
索引结构设计
方法 | 名称 | 简介 | 备注 |
暴力计算 | 一般作为Base算法 | ||
倒排方法 | 通过聚类或者其他方法,将整个向量空间划分为K个区域,每个区域用一个中心点C代替,每个向量和所有中心点对比,将自身划归到距离自己最近的中心点对应的倒排 | ||
哈希方法 |
局部敏感哈希Locality Sensitive Hashing,LSH,是hash方法的代表算法。它是用hash的方法把数据从原空间哈希到一个新的空间中,使得在原始空间的相似的数据,在新的空间中也相似的概率很大,而在原始空间的不相似的数据,在新的空间中相似的概率很小。 |
基本思想:基于哈希的搜索方法采用一组局部敏感哈希函数对向量集合进行划分。 构建索引:通过采用局部敏感哈希函数对每一个向量计算出一个与之相对应的哈希值。对于距离较接近的向量,其哈希值也较为接近。该方法将各局部敏感哈希函数的值域划分为若干个区间,从而每个向量相应于特定的局部敏感哈希函数,均有一个区间与之对应。该方法通过哈希值的区间对向量进行划分,若两向量对于任一哈希函数其哈希值所在的区间均相同,则这两个向量属于同一分类。 向量检索:通过相同的局部敏感哈希函数和区间划分方法可以计算得到目标向量所属分类。然后依次计算该分类以及该分类的邻近分类中所有向量与目标向量的距离获取距离最小的向量。 优点:基于哈希的方法,通过计算目标向量所在分类以及邻近的分类可以有效的排除掉大量与目标向量相似度较低的向量,减少了向量相似度的计算次数。对于小数据集和中规模的数据集(几个million-几十个million),基于LSH的方法的效果和性能较好。 缺点:该方法通常只能对向量空间进行均匀划分,而实际应用中向量在空间中的分布通常是不均匀的,从而导致各个分类中向量的数量相差巨大,并进一步影响搜索的效率和准确度。 |
|
聚类方法 | K-means |
1. 从数据集中随机选取K个样本做为初始聚类中心; 2. 计算每个样本到K个聚类中心最小距离并归类; 3. 重新计算聚类中心并更新; |
|
K-means++ | 1. 随机选取1个聚类中心记为C1;
2. 计算每个样本到C1的距离,计算概率,确定第二个聚类中心;依次选出K个 3. 重新计算聚类中心并更新; |
||
ISODATA (Iterative Selforganizing Data Analysis Techniques Algorithm) 迭代自组织数据分析算法 |
1. 随机选取K0个样本作为聚类中心; 2. 计算每个样本到K0个中心最小距离并归类; 3. 判断各聚类个数是否小于N,如果小于N则丢弃该类; 4. 重新计算质心; 5. 如果K<K0/2则进行分裂操作;如果K>2K0则进行合并操作; |
ISODATA算法是在k-均值算法的基础上,增加对聚类结果的“合并”和“分裂”两个操作,并设定算法运行控制参数的一种聚类算法。迭代次数会影响最终结果,迭代参数选择很重要 | |
基于树结构的方法 | 树检索总览 |
基本思想:基于树的搜索方法通常根据向量的分布特征采用一系列的超平面将高维向量空间划分为多个子空间,并采用树型结构维护空间划分的层次关系。 构建索引:树中的每一个非叶子节点对应于一个子空间和一组超平面。超平面将该节点的子空间进一步划分为更小的子空间,每一个子空间与该节点的一个孩子节点相对应。树中的根节点对应的是完整的向量空间,除根节点之外的每一个节点均对应于其父节点空间被划分后得到的一个子空间。而每个叶子节点对应于一个不可再分的子空间。依据上述规则,对于向量集合中的各个向量都可以找到树中的一个叶子节点与之对应。 向量检索:在向量搜索的过程中,可通过树型结构快速的搜索到若干个距离目标向量较近的叶子节点。通过依次计算目标向量与上述叶子节点所对应各向量的距离即可近似得到与目标向量最相似的向量。 优点:采用基于树的搜索方法可以快速的定位到与目标向量最为相似的若干个叶子节点,从而有效地避免了很多无效比对,提高了搜索效率。 缺点:随着向量维度的提高,计算用于划分空间的超平面的开销将显著增大,从而影响树型结构的构建效率。此外,如果目标向量与某一超平面距离较近,该方法的搜索结果可能会丢失大量的与目标相似的向量,从而影响查询的准确度。 |
|
KDTree (K-Dimensional Tree) |
KD树采用求每一个维度的方差,选择方差最大的那个维度开始划分。 方差的大小可以反映数据的波动性。方差大表示数据波动性越大,选择方差最大作为划分空间标准的好处在于,可以使得所需的划分面数目最小,反映到树数据结构上,可以使得我们构建的KD树的树深度尽可能的小。 |
||
BallTree |
以球面划分空间 |
||
VPTree |
选取一个制高点,计算每个点和制高点的距离,取距离中值作为判断标准 |
||
基于图方法 | 图检索总览 |
基本思想:基于图的搜索方法通常不对向量空间进行划分。 构建索引:该方法预先计算向量集合中各向量间的相似度,并以图的形式维护向量之间的相似关系。具体而言,在图中每个向量是一个节点,距离较近的节点之间通过边相互连接。 向量检索:在搜索时,从一个或者多个起始节点出发进行探索。每次探索一个节点时,计算该节点的所有邻居节点与目标向量的相似度,并基于当前探索的结果,选择与目标向量最为相似且未被探索的节点作为下一次需要探索的节点并开始下一次探索。以上过程在无法找到新的探索节点时结束,并将探索过程中所有被访问的节点中与目标向量最为相似的节点作为搜索结果。 优点:基于图的方法通常有较高的搜索效率和准确度 缺点:构建搜索图的过程中需要进行大量的向量距离计算,从而导致极大的计算开销。除此之外,在需要向向量集合中增加新的向量时,通常需要对搜索图进行重新构建,从而严重影响了向量的插入效率 |
|
NSW (Navigable Small World Graph) |
构图的过程中,插图一个全新点时,查找到与这个全新点最近的m个点(m由用户设置),连接全新点到m个点的连线。那么越先被插入的点,越有可能有高速公路,因为插入某一个点时,链接与它相近的点。但是在后面的构图过程中可能会有更近的点插入,那么这些原先的连线就成了高速公路了。 | ||
HNSW (Hierarchal Navigable Small World Graph) |
HNSW每层都是一个NSW(Navigable Small World Graph),通过图数据结构组织,上层节点通过投币决定在哪一层,节点在下层图中都有记录,上层图是下层图的一个缩影,检索时,从上到下,不断指引检索过程,逐步靠近想要探索的向量空间。 构图过程中通过边的裁剪保证图的连通性。 |
||
量化方法 | 向量量化 |
基本思想:基于向量量化的方法通常采用聚类的方式对向量集合中的向量进行划分。 构建索引:该方法通过 k-means 等聚类方法将向量集合划分为多个聚类,并记录各个聚类的中心点的坐标。 向量检索:首先依次比对目标向量与各个聚类中心的距离,选择出与目标向量最为接近的若干个聚类中心。接下来获取这些聚类中心所对应聚类中的所有向量,依次计算各向量与目标向量的距离,选择出距离最为接近的若干个向量。 优点:采用聚类的方法将数据集合划分,在搜索过程中排除掉与目标向量相似度较低的向量。 缺点:在高维向量的搜索中容易遗漏部分潜在的与目标向量距离较近的向量,从而难以达到较高的准确度 |
|
SQ | SQ是将每一个维度量化成指定位数的一个数,比如将32位的int量化成8位的int,通过损失一定的精度,缩减存储成本。 | ||
PQ | PQ是将整个向量划分为M段,每一段量化成一个指定位数的数,比如下图将128维(每个维度32位)的向量分成4段,每段量化成一个8位的数,则相当于每段含有256个聚类中心,那么一个128维的向量可以用4维(每个维度8位)的向量表示。 | ||
IVF-PQ | 通过先粗量化,获取里查询向量较近的几个聚类,再在这几个聚类中做PQ计算 | ||
量化+图 | 图遍历过程中使用量化计算来加速 | 在高维数据上优化明显 | |
倒排+图 | 用海量中心点去分割向量空间,图方法来组织海量中心点 |
参考链接
- https://blog.csdn.net/lijinwen920523/article/details/116358099
典型最佳实践
算法库名称 | 简介 | 地址 | 备注 |
NMS | C++库,提供Python绑定,提供了SWGraph、HNSW、BallTree、MPLSH实现 | https://github.com/nmslib/nmslib | 基于图 |
HNMS | 相比当前NMSLIB版本,hnswlib内存占用更少 | https://github.com/nmslib/hnswlib | 基于图 |
KGraph | C++库,提供Python绑定 | https://github.com/aaalgo/kgraph | 基于图 |
Annoy | C++库(提供Python绑定)。Annoy最突出的特性是支持使用静态索引文件,不同进程可以共享索引 | https://github.com/spotify/annoy | |
Scikit-learn | 提供LSHForest 、KDTree 、BallTree |
https://scikit-learn.org/stable/modules/neighbors.html |