局部敏感哈希是工程实际中主流的快速 Embedding 向量最近邻搜索方法,它属于近似最近邻查找(Approximate Nearest Neighbor, ANN)的一种。
1 局部敏感哈希的基本原理
局部敏感哈希的基本思想是:让相邻的点落入同一个“桶”中,在进行最近邻搜索时,只需要在一个桶,或者相邻的几个桶内进行搜索。
LSH 算法基本原理是:用一个Hash 方法将数据从原空间映射到一个新的空间中,使得在原空间相似(距离近)的数据,在新的空间中也相似的概率很大,而在原空间不相似(距离远)的数据,在新的空间中相似的概率很小。
例如我们基于欧式距离进行最近邻搜索时,原空间为高维的欧式空间,映射的新的空间为一个低维欧式空间,我们容易推得:在原高维空间中相似的点,在低维的空间肯定也相似,但原本不相似的点在低维空间中是有一定的小概率成为相似的点的。
1.1 哈希函数(Hash Functions)应满足的条件
令 h ( x ) h(x) h(x) 表示样本 x x x 的哈希变换, x x x 与 y y y 为两个任意的样本, d ( x , y ) d(x,y) d(x,y) 为 x x x 与 y y y 之间的距离, d 1 d_1 d1 与 d 2 d_2 d2 为两个常量值,且 d 1 < d 2 d_1<d_2 d1<d2, p 1 p_1 p1 与 p 2 p_2 p2 为两个介于 0 与 1 之间的常量值,若 h ( x ) h(x) h(x) 满足以下两个条件,则称哈希函数 h ( x ) h(x) h(x) 为 ( d 1 , d 2 , p 1 , p 2 ) (d_1,d_2,p_1,p_2) (d1,d2,p1,p2)-senstive:
- 如果 d ( x , y ) ≤ d 1 d(x,y)\leq d_1 d(x,y)≤d1,则 h ( x ) = h ( y ) h(x)=h(y) h(x)=h(y) 的概率至少为 p 1 p_1 p1
- 如果 d ( x , y ) ≥ d 2 d(x,y)\geq d_2 d(x,y)≥d2,则 h ( x ) = h ( y ) h(x)=h(y) h(x)=h(y) 的概率至多为 p 2 p_2 p2
通过一个或多个 ( d 1 , d 2 , p 1 , p 2 ) (d_1,d_2,p_1,p_2) (d1,d2,p1,p2)-senstive 的哈希函数对原始数据集合进行哈希运算,得到一个或者多个哈希表的过程就称为是 局部敏感哈希。
1.2 LSH 的多桶策略
因为哈希映射过程损失了部分的距离信息,如果只使用一个哈希函数进行分桶,则会存在相似点误判的情况,解决的方式是采用多( m m m)个哈希函数同时进行分桶,同时掉进 m m m 个哈希函数同一个桶中的两个点,是相似点的概率则大大增加。
通过分桶找到候选集合后,就可以在有限的候选集合中通过遍历的方法找到最近的 K K K 个近邻。
在用多个哈希函数进行分桶时,应该通过“与”(And/交集)操作还是“或”(Or/并集)操作生成最终的候选集合呢?
- 如果通过“与”操作生成候选集,则候选集合中近邻点的准确率将提高,候选集合的样本数量也会减少,从而使最后遍历的时间缩短,但有可能会漏掉一些近邻点;
- 如果通过“或”操作生成候选集,那么候选集合的规模会变大,遍历的计算开销则会增加,但好处是候选集中近邻点的召回率会提高;
在实际应用中, m m m 的取值、使用“与”还是“或”需要在准确率和召回率之间权衡。
1.3 LSH 的特点
LSH 是一种从海量的高维数据集中查找近似 K K K 近邻的方法,需要注意的是,LSH 并不能保证一定能查找到最相邻的数据,
2 局部敏感哈希的基本流程
2.1 离线建立索引
- 根据对准确率和召回率的需求,确定哈希函数的个数 m m m,以及每个哈希函数分桶的个数 w w w
- 选取 m m m 个满足 ( d 1 , d 2 , p 1 , p 2 ) (d_1,d_2,p_1,p_2) (d1,d2,p1,p2)-senstive 的哈希函数
- 将所有数据经过 LSH 哈希函数映射到相应的桶中,构成多个哈希表
2.2 在线查找
- 将查询数据经过 m m m 个哈希函数得到各个相应的桶号
- 根据“与”或者“或”操作对桶进行合并,获得最终的候选集
- 计算查询数据与候选集合中每个数据点之间的相似度或者距离,返回最近的 K K K 个近邻
从上面的流程可以看出,在线查找的时间包括两个部分:
- 步骤1中通过 LSH 哈希函数计算桶号的时间
- 步骤3中遍历所有候选点,计算与查询数据点距离的时间
3 不同距离度量下的 LSH
3.1 欧式距离
假设 v v v 是高维空间中的 k k k 维向量, r r r 是一个随机向量,则内积操作可以将 v v v 映射到一维空间:
h ( v ) = v ⋅ r h(v)=v\cdot r h(v)=v⋅r
因为一维空间也能部分保留高维空间的近似距离信息,因此就可以利用下面的哈希公式进行分桶:
h r , b ( v ) = ⌊ v ⋅ r + b w ⌋ h^{r,b}(v)=\lfloor \frac{v\cdot r + b}{w} \rfloor hr,b(v)=⌊wv⋅r+b⌋
其中, ⌊ ⌋ \lfloor \rfloor ⌊⌋是向下取整操作, w w w 是分桶宽度, b b b 是 0 0 0 到 w w w 之间的一个均匀分布的随机变量,目的是避免分桶边界固化。
3.2 余弦距离
余弦距离衡量的是两个向量夹角的大小,夹角越小,则两个向量越相似。
基于余弦距离的 LSH 哈希函数为:
H ( v ) = s i g n ( v ⋅ r ) H(v)=sign(v\cdot r) H(v)=sign(v⋅r)
其中, r r r 是一个随机向量, v ⋅ r v\cdot r v⋅r 可以看作是将 v v v 向 r r r 上进行投影。