NN-Descent构建K近邻图——论文超详细注解

个人博客:www.mzwang.top

论文题目

Efficient K-Nearest Neighbor Graph Construction for Generic Similarity Measures

相关信息

作者与单位

Wei Dong([email protected]);

Moses Charikar([email protected]);

Kai Li([email protected]).

Department of Computer Science, Princeton University

出处与时间

In Proceedings of the 20th international conference on World wide web; 2011

作者拟解决的主要问题

K近邻图的构建在很多基于Web的应用上是一个重要的操作,比如协同过滤(基于用户的邻居作推荐)、相似性搜索等。一个有效地构建方法将使K近邻图的应用更加广泛。

暴力构建K近邻图的时间复杂度为O(n2)O(n^2),为了能更高效的构建K近邻图,现存的工作扩展性都不太好,而且一般都特定于具体的相似性度量。

有效的K近邻图构建仍然是一个开放的问题,解决该问题的已知方案中没有一个是通用、有效和可扩展的。因此,本文提出了NN-Descent方法,该方法具有以下优点:

  1. 通用。适用于任意的相似性度量准则。

  2. 可扩展。随着数据集尺寸的增加,Recall仅有很小的下降。由于对每一个数据点的局部信息进行操作,因此适用于分布式计算环境(MapReduce).

  3. 节省空间。整个构建过程仅涉及到一种数据结构——近邻图。

  4. 快速、精确。百分之几的相似性比较便可实现90%以上的召回率。

  5. 容易实施。主要代码不超过200行(C++)。

论文主要研究内容

如何有效地构建一个K近邻图,具体如下:

  1. 适用任意相似性度量的K近邻图构建方法。
  2. 在较短的时间内快速构建K近邻图的方法。
  3. 构建一个在其上能快速、精确执行搜索的K近邻图。
  4. 适用于MapReduce框架的K近邻图构建方案。

论文使用的方法

抽象描述注解

VV表示数据集,数据集尺寸为N=VN=|V|,相似性度量σ\sigmaV×VRV \times V \rightarrow RvV\forall v \in VBK(v)B_K(v)表示vvKK个最近邻,RK(v)={uVvBK(u)}R_K(v)= \lbrace u \in V | v \in B_K(u) \rbrace表示vv的反向K个最近邻。B[v]B[v]R[v]R[v]分别表示BK(v)B_K(v)RK(v)R_K(v)的近似。B[v]=B[v]R[v]\overline{B}[v]=B[v] \cup R[v]表示vv的一般邻居。

当在VV上的度量方式为距离度量时,即ddV×V[0, +]V \times V \rightarrow [0,\ +\infty]r[0, +]\forall r \in [0,\ +\infty],以vv为球心的r-球定义为:Br(v)={uVd(u, v)r}B_r(v)=\lbrace u \in V | d(u, \ v) \leq r\rbrace

如果c\exists c满足:
B2r(v)cBr(v), vV(1) |B_{2r}(v)| \leq c|B_{r}(v)|, \ \forall v \in V \tag{1}
则称度量空间V增长受限cc是增长常量。

基础算法注解

基本思想:邻居的邻居更可能是邻居

理论推导

我们可以从VV中每一个点的现有的近似K近邻出发,通过探索该点邻居的邻居(在当前近似K近邻中)而不断完善该点的K近邻。换句话说,可从粗略的K近邻图出发通过改进而不断完善它。对这一观点的量化表达如下:

K=c3K=c^3(后面公式推导要用到,KK取此值是方便推导),假定已有的近似K近邻图(可以随机给每个点选邻居构建,也可通过其它数据结构辅助构建,如哈希,树等)为BBvV\forall v \in VB[v]=vB[v]B[v]B^\prime[v]=\bigcup _{v^\prime \in B[v]} B[v^\prime]表示vv所有邻居的邻居集合,它也是在完善vv的K近邻时的候选点集。当B的精度比较高时(迭代完善了一定次数或通过某种更好的方式初始化B),高到什么程度呢?就是给定一个固定的半径rr,对vV\forall v \in VB[v]B[v]包含的K个邻居均匀地分布在Br(v)B_r(v)中。这样的话,当各事件相互独立且K<<Br/2(v)K<< |B_{r/2}(v)|时,B[v]B^\prime [v]很可能包含在Br/2(v)B_{r/2}(v)中的K个邻居。换句话说,对vV\forall v \in V,通过探索B[v]B^\prime [v]来使vv到它的近似K近邻的距离减半。

Br/2(v)B_{r/2}(v)中的一点uu,要从B[v]B^\prime[v]里面找到,则至少存在一点vv^\prime,使得vB[v]v^\prime \in B[v],且uB[v]u \in B[v^\prime]。接下来,我们只需要找满足上述条件的vv^\prime即可。而若vBr/2(v)v^\prime \in B_{r/2}(v),则有以下几个不等式成立:

  1. vBr(v)v^\prime \in B_r(v),因此,P{vB[v]}K/Br(v)P\lbrace v^\prime \in B[v]\rbrace \geq K/|B_r(v)|P{vB[v]}P\lbrace v^\prime \in B[v]\rbrace表示概率。注解: vBr/2(v)v^\prime \in B_{r/2}(v),则vBr(v)v^\prime \in B_r(v)必然成立。若vvKK个邻居都在Br(v)B_r(v)中取的话,则一共有CBr(v)KC_{|B_r(v)|}^K种情况,而Br(v)B_r(v)中的一点不是vv的邻居的情况有CBr(v)1KC_{|B_r(v)|-1}^K种,Br(v)B_r(v)中的一点不是vv的邻居的概率为CBr(v)1K/CBr(v)KC_{|B_r(v)|-1}^K/C_{|B_r(v)|}^K,即为(Br(v)K)/Br(v)(|B_r(v)|-K)/|B_r(v)|,因此Br(v)B_r(v)中的一点是vv的邻居的概率为1CBr(v)1K/CBr(v)K1-C_{|B_r(v)|-1}^K/C_{|B_r(v)|}^K,即为K/Br(v)K/|B_r(v)|Br/2(v)B_{r/2}(v)中的一点更可能是vv的邻居,故vv^\primevv的邻居的概率大于等于K/Br(v)K/|B_r(v)|
  2. d(u, v)d(u, v)+d(v, v)rd(u,\ v^\prime) \leq d(u, \ v) + d(v, \ v^\prime) \leq r,因此,P{uB[v]}K/Br(v)P\lbrace u \in B[v^\prime]\rbrace \geq K/|B_r(v^\prime)|注解: 由第一条推论可知,因此Br(v)B_r(v^\prime)中的一点是vv^\prime的邻居的概率为K/Br(v)K/|B_r(v^\prime)|,而uuvv^\prime的距离小于等于rr,故uuvv^\prime的邻居的概率大于等于K/Br(v)K/|B_r(v^\prime)|
  3. Br(v)cBr/2(v)|B_r(v)| \leq c|B_{r/2}(v)|,且Br(v)cBr/2(v)cBr(v)c2Br/2(v)|B_r(v^\prime)| \leq c|B_{r/2}(v^\prime)| \leq c|B_r(v)| \leq c^2|B_{r/2}(v)|注解: 重点是Br/2(v)Br(v)|B_{r/2}(v^\prime)| \leq |B_r(v)|部分的推导,而此处可由图1明显推出。由于vv^\primevvr/2r/2-球中,vv^\primer/2r/2-球一定包含于vvrr-球中。
NN-Descent构建K近邻图——论文超详细注解
图1 不等式推导二维辅助理解图

由以上3个不等式和假定的各事件的独立性可得:
P{vB[v]uB[v]}K/Br/2(v)2(2) P\lbrace v^\prime \in B[v] \land u \in B[v^\prime]\rbrace \geq K/|B_{r/2}(v)|^2 \tag{2}
注解: 上式其实就是1.与2.两个事件同时发生的概率再由3.式化简的结果。它的意义是,对于Br/2[v]B_{r/2}[v]中的确定的点vv^\prime,它既是vv的邻居又是uu的反向邻居的概率大于等于K/Br/2(v)2K/|B_{r/2}(v)|^2

因此,当vv的邻居从Br/2(v)B_{r/2}(v)中取时,在Br/2(v)B_{r/2}(v)中的一点uu属于vv的邻居的邻居的概率为:
P{uB[v]}1(1K/Br/2(v)2)Br/2(v)K/Br/2(v)(3) P\lbrace u \in B^\prime[v]\rbrace \geq 1-(1-K/|B_{r/2}(v)|^2)^{|B_{r/2(v)}|} \approx K/|B_{r/2(v)}| \tag{3}
注解: 先考虑uu不是vv的邻居的邻居的概率。此时,从Br/2(v)B_{r/2}(v)中取出的一点设为xxxx不是vv的邻居或者uu不是xx的邻居,发生这种情况的概率由式(2)可得应为1K/Br/2(v)21-K/|B_{r/2}(v)|^2Br/2(v)B_{r/2}(v)中一共有Br/2(v)|B_{r/2}(v)|个点,它们都不满足上述情况(xx不是vv的邻居或者uu不是xx的邻居)的概率为:(1K/Br/2(v)2)Br/2(v)(1-K/|B_{r/2}(v)|^2)^{|B_{r/2(v)}|},这便是uu不是vv的邻居的邻居的概率,从而uuvv的邻居的邻居的概率为:1(1K/Br/2(v)2)Br/2(v)1-(1-K/|B_{r/2}(v)|^2)^{|B_{r/2(v)}|}。下面对该式进行化简,由于K<<Br/2(v)K<< |B_{r/2}(v)|,因此K/Br/2(v)2K/|B_{r/2}(v)|^2是无穷小,化简过程用到一个重要极限:
limx(1+1x)x=e(4) \lim_{x \rightarrow \infty}(1+\frac{1}{x})^x=e \tag{4}
一个等价无穷小公式:
ex1x e^x -1 \sim x
整个数据集的直径设为Δ\Delta,式(3)表明,只要我们取一个足够大的KK(取决于增长因子cc),即使我们从一个随机的K近邻图开始,通过探索每一个对象邻居的邻居,便可找到该对象的处于半径为Δ/2\Delta/2的范围内的K个近邻。不断的迭代这一过程,每个对象的邻居距离该对象的距离会不断收缩,最终,构建一个高质量近似K近邻图。

伪代码

NN-Descent构建K近邻图——论文超详细注解
算法1 NN-Descent基础算法

注解:(1)处为更新统计,如果某一个对象的K近邻列表更新了,cc就会加1。算法1的终止条件为自然终止,即没有更新时(c=0c=0)终止。

改进算法注解

局部连接

让每一个对象探索它邻居的邻居的操作也可通过局部连接等价实现。局部连接可这样理解:给定一点vv,它的邻居集为B[v]\overline{B}[v],在B[v]\overline{B}[v]上的局部连接是计算每一对不同的ppqq之间的相似性(pqB[v]p,q \in \overline{B}[v]),并且根据此相似性更新B[p]B[p]B[q]B[q]。通俗的将,局部连接就是每一个点介绍它的邻居去了解彼此

局部连接能代替一个对象探索它邻居的邻居的操作吗?看下面的示例:

NN-Descent构建K近邻图——论文超详细注解
图2 局部连接实现示例

如图2所示,bBK(a)b \in B_K(a)cBK(b)c \in B_K(b)。在算法1中,当探索到aa时,我们需要比较aacc,当探索到cc时,我们也需要比较aacc,这是冗余计算的一种情况,可通过索引编号的顺序来解决。同样地,aacc之间的比较可通过对B[b]\overline{B}[b]进行局部连接来实现。

局部连接实现起来很简单,那么它有什么好处呢?

  1. 增强了数据的局部性,使执行更有效。如果每一个对象的邻居的个数平均为K\overline{K},算法1每次迭代探索每一个对象的邻居的邻居时将接触到K2\overline{K}^2个点,而局部连接只需要接触K\overline{K}个点。
  2. 单机实施时,提升了cache的命中率,从而加速了K近邻图的构建。分布式实施时,能减少机器之间数据的复制。

增量搜索

随着算法的执行,每一个对象的K近邻更新的幅度逐渐减小。而且,在某次迭代中参与比较的两个点,就更可能在之前的迭代中已经比较过了。这就造成冗余计算,而增量搜索就是要解决这个问题的。

  1. 给每一个点的K近邻列表中的每一个对象附加一个布尔标记,当一个新对象插入到该列表中的某个条目时,它的标记初始化为true。
  2. 只有当两个对象至少一个的标记为true,它们才进行局部连接。一个对象参与局部连接之后,它被标记为false(true变false,false还是false)。

采样

采样是为了解决以下两个问题:

  1. 局部连接的高成本。一次迭代,就算只考虑K近邻,时间复杂度为K2NK^2N,如果再考虑反向近邻,时间复杂度更高。
  2. 冗余计算。两个点同时连接到多个不同对象,这两个点将比较多次。

使用采样来缓解这两个问题的具体方案如下:

  1. 邻居取样。局部连接之前,对用于局部连接的每一个对象,从标记为true的K近邻中取样ρK\rho K个对象(ρ(0,1]\rho \in (0, 1])。每一次迭代,仅仅这些被取出的数据被标记为false。
  2. 反向邻居。只根据取样对象和标记为false的对象来构建反向邻居列表。对构建得的反向邻居列表再次取样。
  3. 在标记为true对象之间进行局部连接,以及在标记为true对象与标记为false对象之间进行局部连接。

因此,我们就可以通过取样率ρ\rho来进行精度和速度的trade-off。

提前终止

一个很自然的终止标准是:某次迭代中,K近邻图不再被改善。实际上,开始迭代时,K近邻图能充分的更新,而随着迭代的进行,K近邻图更新的次数快速收缩,此时的迭代就显得意义不大了,考虑到迭代的计算成本,这些迭代其实没必要执行。为了解决这个问题,本文采取的方案是:在每次迭代中,统计所有对象K近邻列表更新的次数countcount,当$count < \delta KN 时终止发生,其中\delta$是精度参数,它粗略反应了由于提前终止允许错过的真正的K近邻的比例。

伪代码

NN-Descent构建K近邻图——论文超详细注解
算法2 NN-Descent改进算法

注解: 算法2是在算法1的基础上结合了四个改进(局部连接;增量搜索;采样;提前终止),注意算法2其实也不能完全避免冗余计算,先理解一下这个算法,然后我会给出示例。

(1)、(2)属于增量搜索和采样部分,对于当前对象vv,在它的邻居列表中取ρK\rho K个标记为true的邻居到new[v]new[v],并将这些邻居标记为false(对于伪代码中的(3)),在它的邻居列表中取出所有标记为false的邻居到old[v]old[v]

(4)是取vv的反向邻居,正如取vvold[v]old[v]一样,其它所有点也会取各自的oldold,以所有点的oldold集合中包含的点作为探索范围,检查它们的邻居列表中含vv的点,含vv则加入到old[v]old^\prime [v]old[v]old^\prime [v]的意义是:点vv的反向邻居,且在该反向邻居的邻居表中,vv被标记为false。newnew^\prime同理。

(5)是说最后参与局部连接的old[v]old[v]是由两部分组成:一部分是从vv的邻居列表中取出的标记为false的邻居集,另一部分是从old[v]old^\prime [v]中取样的ρK\rho K个点。最后参与局部连接的new[v]new[v]同理((6))。

(7)表示局部连接。new[v]new[v]里面的点相互之间进行局部连接,为防止重复比较,设定比较顺序。new[v]new[v]中的点与old[v]old[v]中的点进行局部连接。

(8)统计更新,某一对象的邻居列表更新时,新插入的对象标记为true(满足:增量搜索)。

(9)为终止条件。当更新量小于某一阈值时终止。

冗余计算示例

NN-Descent构建K近邻图——论文超详细注解
图3 冗余计算示例

如图3所示,第一次迭代时v3v_3v4v_4都取样了v1v_1,都没有取样v2v_2,因此,它们的邻居列表中v1v_1都标记为false,v2v_2都标记为true。此时,new[v1]new^\prime[v_1]v3v_3v4v_4,若v3v_3v4v_4都被取样加入到参与局部连接的new[v1]new[v_1],则v3v_3v4v_4会进行一次相似性计算。第二次迭代时,v3v_3v4v_4都取样了v2v_2,然后v2v_2在它们的列表中被标记为false。此时,new[v2]new^\prime[v_2]v3v_3v4v_4,若v3v_3v4v_4都被取样加入到参与局部连接的new[v2]new[v_2],则v3v_3v4v_4又会进行一次相似性计算。

当然,上述分两次迭代的说明也可在一次迭代中发生。不过,上述冗余计算的情况在取样过程的参与下发生的概率是很小的。

论文的创新点

一种新的构建K近邻图的方法,具体创新包括:

  1. 对于一个随机K近邻图,通过几次迭代而不断的完善K近邻图,最终得到一个更好的K近邻图。(构图思路)
  2. 处理某个点时,在该点的各邻居之间进行选边。这种方式相较于处理某个点时,该点与该点的邻居的邻居之间进行选边而言,局部性更好。两种方式实现的结果都是一样的。(选边策略)

论文的结论

具体实验分析可以看作者的原文。本文提出的NN-Descent方法可使用任意度量方式构建的K近邻图。经验复杂度为O(n1.14)O(n^{1.14}),很容易实现并行化。

我的观点或思考

本文一开始是随机构建一个K近邻图,这样做的优点是简单快速。但是,迭代的过程过多地依赖随机初始化的K近邻图,这样可能不够稳定,某些情况下只需几次迭代,而另一些情况则可能需要很多。因此,一个简单地改进可从初始化K近邻图这个角度入手。

最近提出的基于近邻图的近似最近邻搜索算法——NSG和NSSG,他们在构建索引时,第一步构建K近邻图与第二部MRNG或SSG选边策略是分开进行的,有没有可能在K近邻图构建的同时执行某一选边策略。

选边的时候将三角不等式考虑进去,从而避免一些不必要的计算。