原文: http://cto.gcgchina.com/lshlocality_sensitive_hashing/
两点之间的距离可以用两种方式来衡量,一是几何距离,二是非几何距离。很显然距离的定义满足下面的条件:
- d(x,y) > 0.
- d(x,y) = 0 iff x = y.
- d(x,y) = d(y,x).
- d(x,y) < d(x,z) + d(z,y)
几何距离包括:
- L2 norm : d(x,y) 是平方和的开方
- L1 norm : d(x,y) 是每个维度的距离之和
- L∞ norm : d(x,y) 是x和y在每个维度上距离的最大值
非几何距离用的就比较多了:
- Jaccard距离:1减去Jaccad相似度
- 余弦距离:两个向量之间的角度
- 编辑距离(Edit distance):将一个串变为另一个串需要的插入或删除次数
- 海明距离(Hamming Distance):Bit向量中不同位置的个数
这里有一个重要的公理:三角形公理(Triangle Inequality),也就是距离的第四个性质。编辑距离d(x,y) = |x| + |y| – 2|LCS(x,y)|,其中LCS是longest common subsequence,最长公共子序列。
LSH的一个核心思想就是两个元素哈希值相等的概率等于两个元素之间的相似度。
下面介绍一个重要概念:Hash Family,哈希家族?不管怎么翻译,它指的是能够判断两个元素是否相等(h(x) = h(y) )的Hash函数集合。LS Hash Family,局部敏感哈希家族的定义是满足下面两个条件的哈希函数家族:
- 如果d(x,y) < d1,那么哈希家族H中的哈希函数h满足h(x) = h(y)的概率至少是p1.
- 如果d(x,y) > d2,那么哈希家族H中的哈希函数h满足h(x) = h(y)的概率至多是p2.
就是如果x和y离得越近,Pr[h(p)=h(q)]就越大。如果x和y离得越远,Pr[h(p)=h(q)]就越小。我们把局部敏感哈希家族记为(d1,d2,p1,p2)-sensitive。那什么样的函数满足呢?Jaccard就是。我们令S为一个集合,d是Jaccard距离,有Prob[h(x)=h(y)] = 1-d(x,y),我们就可以得到一个局部敏感哈希家族:a(1/3, 2/3, 2/3, 1/3)-sensitive。事实上,只要满足d1<d2,就可以得到一个局部敏感的哈希家族:(d1,d2,(1-d1),(1-d2))-sensitive。
(d1,d2,p1,p2)-sensitive将整个概率空间分成了三部分:<p1,p1-p2,>p2。为了有更好的区分度,我们想让p1-p2的空间尽可能小,让d2-d1尽可能大。选择合适的参数,能够有类似于下面的S曲线应该就是不错的了。可如何来做呢?
定义两种哈希函数的操作:AND和OR。
AND操作:在局部敏感哈希家族H中选出r个哈希哈数,构成哈希家族H’。对于H’家族中的h = [h1,…,hr],h(x)=h(y)当且仅当对所有的i,所有hi(x)=hi(y)都满足。这样得到的H’同样也是一个局部敏感哈希家族。并且若源哈希家族是(d1,d2,p1,p2)-sensitive,新哈希家族H’是(d1,d2,(p1)^r,(p2)^r)-sensitive。
OR操作:在局部敏感哈希家族H中选出b个哈希哈数,构成哈希家族H’。对于H’家族中的h = [h1,…,hb],h(x)=h(y)当且仅当存在i,满足hi(x)=hi(y)。这样得到的H’同样也是一个局部敏感哈希家族。并且若源哈希家族是(d1,d2,p1,p2)-sensitive,新哈希家族H’是(d1,d2,1-(1-p1)^b,1-(1-p2)^b)-sensitive。
可以看出AND操作是降低了概率,但如果选取一个合适的r,可以使下限概率接近0,而上限概率没有多大影响。类似的,OR操作是增加了概率,但如果选择一个合适的d,可以使上限概率接近1,而下限概率没有多大影响。
我们对AND操作和OR操作做级联:
AND-OR,1-(1-p^r)^b
OR-AND,(1-(1-p)^b)^r
举个例子,1-(1-p^4)^4,当p取不同值时:
p | 1-(1-p4)4 |
.2 | .0064 |
.3 | .0320 |
.4 | .0985 |
.5 | .2275 |
.6 | .4260 |
.7 | .6666 |
.8 | .8785 |
.9 | .9860 |
(1-(1-p)^4)^4,当p取不同值时:
p | (1-(1-p)4)4 |
.1 | .0140 |
.2 | .1215 |
.3 | .3334 |
.4 | .5740 |
.5 | .7725 |
.6 | .9015 |
.7 | .9680 |
.8 | .9936 |
得到这样的S曲线之后,可以找到一个点t,满足1-(1-t^r)^b = t。在t点之后,概率快速上升,在t点之前,概率快速下降。根据需要的灵敏度,可以选择合适的上限概率和下限概率来满足应用需求。
参考上图,如果我们要返回距离中心为r的点,LSH会返回给我们范围更远、更多的点,也就是说,LSH返回的结果会带有一定的false positive。我们或许需要使用linear search进行二次筛选,但这毕竟大大减少了计算的时间。
由此可见,LSH与一般的加密型哈希函数有很大的区别,参见下图:
一种实现(LSH)的最简单的方式是采用random bits sampling的方式,即将待索引的多维整型向量转化为0或1的字符串;再采用随机选取其中的K位拼接成新的字符串;最后再采用常规的哈希函数(例如MD5)等算法获取带索引向量的LSH Code。这样的Hash Code有一个特点,就是Hamming Distance相近的两个向量,其冲突的概率越大,即结果相等的可能性越大。为了减少增强KNN搜索的能力,与Bloom Filter类似,采用多个Hash Table增加冲突的概率,参见下图:
来看一下LSH的复杂度:
可见,与各种其它的数据结构相比,基于lsh的索引结构的query时间复杂度,可以做到与向量维度无关,有效地克服了维度灾难的问题,因此更适合高维向量的索引。
基于LSH实现的图像近似检索,其原理也很类似,如下图所示: