最近邻算法和向量模型——第二部分——算法和数据结构

来源:互联网 发布:神魔诛天宠物进阶数据 编辑:程序博客网 时间:2024/06/06 17:05


这篇博客是在我上周NYC MachineLearning做得报告基础上改写而成的。内容中包括Annoy,我开源的一个高维空间求(近似)最近邻的工具库。在第一部分,我介绍了几个例子,并说明向量模型是非常有用的。在第二部分,我将解释Annoy是怎么去找近似最近邻的(approximate nearest neighbor queries),以及相应的算法和数据结构。

 

言归正传,我们的目的是要在一个空间找到一个已知点的最近邻集合。我们看下图是一个二维空间,里面有很多点,当然现实情况,向量模型的维度会比这高很多。


我们的目标是设计一个数据结构,使我们能够以压线性的时间查找一个点的最邻近点集。

我们将构建一棵树,查询时间在 Olog n)。这就是Annoy的原理,实际上,构建的是一个二叉树,其中每个节点都是任意划分的。那我们先看看如何进行一次空间划分:


Annoy通过随机挑选两个点,并使用垂直于这两个点的等距离超平面将集合划分成两部分。图中灰色线是连接两个点,超平面是加粗的黑线。

然后我们按照上述方法在每个子集上进行迭代划分!


一个非常小的二叉树就开始形成了:


我们继续划分:


以此类推,直到每个节点最多剩下K个点。下图是一个K=10的情况:


相应的完整二叉树结构:

 

很好!最后我们得到一颗二叉树,并且这棵树把空间做了划分。这样的好处是原先空间中相邻的点,在树结构上也表现出相互靠近的特点。换句话说,如果两个点在空间上相互靠近,它们也很有可能被多个超平面划分到一起。

 

如果要在空间中查找邻近点,我们只需要遍历这个二叉树。每个中间节点(上图中方形节点)用超平面来定义,所以我们能够计算出该节点的往哪个方向遍历。搜索一个点能够在log时间内完成,这个正好是树的高度。

假如我们要搜索下图中红色X


二叉树的搜索路径看上去会是这样:


结果我们找到了7个最近邻。非常棒,但仍然有两个问题

1.    如果我们想找到最近邻数目大于7,该怎么办?

2.    有些最近邻在我们遍历的叶子节点的外面

 

技巧1——使用优先队列

这个技巧是,如果一个划分的两边“靠得足够近”(量化方式在后面介绍),我们就两边都遍历。这样就不只是遍历一个节点的一边,我们将遍历更多的点:


与之对应的二叉树遍历路径:


我们可以设置一个阈值,用来表示是否愿意搜索划分的一遍。如果设置为0,我们将总是遍历“对”的一片。但是如果设置成0.5,就按照上面的搜索路径。

这个技巧实际上是利用优先级队列,依据两边的最大距离。好处是我们能够设置比0大的阈值,逐渐增加搜索范围。

 

技巧2——构建一个森林

第二个技巧是构建多棵树森林。每棵树都是按照任意划分构建。我们将同时搜索所有的树:


我们能够用一个优先级队列,同时搜索所有的树。这样有另外一个好处,搜索会聚焦到那些与已知点靠得最近的那些树——能够把距离最远的空间划分出去

 

每棵树都包含所有的点,所以当我们搜索多棵树的时候,将找到多棵树上的多个点。如果我们把所有的搜索结果的叶子节点都合在一起,那么得到的最近邻就非常符合要求。


按照这个方法,我们最后找到一个邻近的集合。你可能会注意到,到目前为止,我们都没有提到如何计算点点之间的距离。下一步是计算所有的距离和对点进行排序。


我们根据点距离进行排序,然后返回K个最相近的点。很好!这就是Annoy算法的工作原理。

还是有一个问题,我们实际上仍然丢掉了一些点:


但是正如Annoy中的A,代表了近似(approximate,其实少一些点也是可以接受的。Annoy在实际使用的时候,提供了一种机制可以调整(搜索k,你能够根据它来权衡性能(时间)和准确度(质量)。

 

近似算法的主要思想是通过牺牲一点准确度换取性能的巨大提升(数量级的)。举例来说,我们能够得到一个不错的搜索结果,仅仅是计算1%的点之间的距离——却可以带来100倍相比于穷尽搜索的性能。

树越多效果越好。通过增加树,你更有可能找到你想要的划分。一般来说,只要不超过内存,你可以增加越多越好。

Annoy算法总结:

 

预处理时间:

1.    构建一批二叉树。每棵树都按照随机超平面迭代划分。

Query time:

查询时间

1.    插入每棵树到优先级队列

2.    搜索优先队列中的所有树,直到得到k个候选点

3.    对候选点去重

4.    计算候选点与已知点之间的距离

5.    对候选得到的距离进行排序

6.    返回最近的那几个邻近点

 

如果你感兴趣,请查阅头文件annoylib.h中的_make_tree_get_all_nns

 

OK差不多讲完了,如果你想获取更多信息,请期待我的下一个分享。顺便说一句,请查看这个幻灯片;另外文中的所有图片绘制代码,你也可以看看。

 

(翻译自:http://erikbern.com/2015/10/01/nearest-neighbors-and-vector-models-part-2-how-to-search-in-high-dimensional-spaces/)

 

廖博森@DataSpark

1 0
原创粉丝点击