图像检索(6):局部敏感哈希索引(LSH)
图像检索中,对一幅图像编码后的向量的维度是很高。以VLAD为例,基于SIFT特征点,设视觉词汇表的大小为256,那么一幅图像编码后的VLAD向量的长度为$128 \times 256 = 32768 $。通常要对编码后的VLAD向量进行降维,降维后的向量长度应该根据图像库中图像量的大小来,如果只是几百张的小的图像库,那么可以降维到128甚至是64维,在这种情况下降维后的VLAD向量仍然有很好的区分度;但是如果图片库的数量是几千,几万张,如果VLAD降维的维度太低,损失的信息过多,就不能有很好的区分度,维度过低检索的精度就会低很多。为了保证检索的精度,VLAD向量要有1024或者2048的维度。
以上数据是笔者经历的项目的经验值,并不一定适合所有的情况。
如果是在低维度的小数据集中,可以使用线性查找(Linear Search)的方法,但是在高纬度大数据集中,线性查找的效率很低,显然是不可行的。如何的从大的高维数据集中找到与某个向量最相似的一个或多个向量,是图像检索中一个难点。
在这种高纬度大数据集中的检索,通常需要使用最近邻最相似查找(Approximate Nearest Neighbor,ANN)的方法。ANN的相似性检索算法,大体可以分为三大类:
- 基于树的方法,KD-树为代表。对于低维度的数据,KD树的查找性能还是比较高效的;但当空间维度较高时,该方法会退化为暴力枚举,性能较差,这时一般会采用下面的哈希方法或者矢量量化方法。
- 哈希方法
- LSH Locality Sensitive Hashing 为代表,对于小数据集和中等数据集效果不错
- 矢量量化
- vector quantization,在矢量量化编码中,关键是码本的建立和码字搜索算法。比如常见的聚类算法,就是一种矢量量化方法。而在相似搜索中,向量量化方法又以PQ方法为代表
- 对于大规模数据集,矢量量化是个很好的选择
LSH
LSH(Locality Sensitive Hashing)位置敏感哈希,局部敏感哈希
最近邻最相似搜索算法的一种,有比较可靠的理论根据且在高维数据中表现比较好,很适合应用在图像检索中。
与一般的哈希算法不同的是其位置敏感性,也就是散列前类似的点(距离近的点),在散列后仍然能够保证在一定程度的相似,且有一定的概率保证。
LSH和普通哈希的区别
基本思想
LSH不像树形结构的方法可以得到精确的结果,LSH所得到的是一个近似的结果,因为在很多领域中并不需非常高的精确度。即使是近似解,但有时候这个近似程度几乎和精准解一致。
LSH的主要思想是,高维空间的两点若距离很近,那么设计一种哈希函数对这两点进行哈希值计算,使得他们哈希值有很大的概率是一样的。同时若两点之间的距离较远,他们哈希值相同的概率会很小。
LSH哈希函数要满足的性质
一个哈希函数满足以下性质时,被称为\((R,cR,P_1,P_2)\)-sensive,对于高维空间的任意两点\(x,y\)
- 如果\(d(x,y) \le R\),则\(h(x) = h(y)\)的概率不小于\(P_1\)
- 如果\(d(x,y) \ge cR\),则\(h(x) = h(y)\)的概率不大于\(P_2\)
其中\(d(x,y)\)是两个点\(x,y\)之间的距离,\(h\)是哈希函数,\(h(x)\)和\(h(y)\)是对点\(x,y\)的哈希变换,并且需要满足:
- \(c > 1\)
- \(P_1 > P_2\)
LSH的原理是挺简单的,其核心有两个:
- 两个高维向量的相似性的度量
- \((R,cR,P_1,P_2)\)-sensive哈希函数的选择
LSH的哈希函数的选择取决于其选择的相似性度量方法,当然并不是所有向量相似性度量的方法都能找到相应的LSH函数,比如LSH最初提出的时候时候基于欧式距离的度量方法就没有找到合适的LSH函数。
Origin LSH
最初设计的LSH应该是想基于欧式距离(\(L_2\)),但是对于欧式距离当时没有找到合适的LSH函数;但是在曼哈顿距离(\(L_1\))下找到了合适的LSH函数。所以,就有了一个假设,向量所在的原始空间中\(L_1\)和\(L_2\)度量的效果相差不大,也就是说用\(L_1\)来代替\(L_2\)。
所以就有两个准则:
- 使用\(L_1\)也就是曼哈顿距离进行度量。 基于假设\(L_1\)和\(L_2\)的度量效果相差不大。
- 向量的各个分量,要被正整数化,方便进行01编码。
为什么要进行01编码呢,因为在\(L_1\)的度量下也不是很容易找到合适的LSH函数,而在Hamming距离下有合适的LSH函数。最初在提出LSH的时候,使用一种方法将向量从\(L_1\)准则下的欧几里空间嵌入(Embedding)到Hamming空间。
Hamming距离下的LSH
Hamming距离指的是两个相同长度的二进制数据中相同位置处比特位值不同的个数。 例如,8和5使用长度为4的二进制表示分别为: \(8=(1000),5 = (0101)\),那么8和5的Hamming距离就是:3。
假如有两个二进制表示的向量\(x,y\),向量的每个分量的值不是0就是1,使用Hamming距离计算这两个向量的距离。假设有一组哈希函数\(H\),其定义为:每一个哈希函数h随机的选择向量特定位置的bit值返回,\(H\)中包含了所有从\(\{0,1\}^d\)映射到\(\{0,1\}\)函数,其中\(h_i(x) = x_i\)。
从\(H\)中随机的选择哈希函数\(h_i\)应用到向量\(x\)上,则\(h_i(x) = x_i\),返回向量\(x\)特定位置的bit值。那么\(h(x) = h(y)\)的概率就为向量\(x,y\)中bit位相同的所占的比例,即有:
\]
其中,\(d\)为向量二进制的长度。则对于任意的\(c>1\),都有\(P_1 > P_2\),满足以上提到的LSH函数的条件。
假设两个点\(x = (1000),y = (0101)\),则\(x,y\)的Hamming距离为3,则通过上述的哈希函数映射后具有相同哈希值的概率,$$P(h(x)=h(y)) = 1 – \frac{3}{4} = \frac{1}{4}$$
曼哈顿距离(\(L_1\))转换为Hamming距离
Hamming距离只能应用于二进制表示的向量,这就有很大局限性。所以Origin LSH 就提出了一种方法称为Embedding,将向量的表示从\(L_1\)准则下的欧几里空间Embedding到Hamming空间,并且保证转换前后两个向量的距离是不变的。
Embedding算法:
- 找到数据集中所有向量的所有分量的最大值\(C\)。
- 对于向量\(x = (x_1,x_2,\cdots,x_n)\),\(n\)是向量的维度。将向量每个分量\(x_i\)转换为长度为\(C\)的二进制序列,二进制序列为前\(x_i\)个1,剩余的为0。假设\(x_i = 5,C=10\),转换后的二进制序列为\(1111100000\)。
- 这样一个\(d\)维的向量就转变为\(nC\)长度的二进制串。
Embedding操作是保持距离的,转换后两个向量的距离是不变的。转变为Hamming距离后,就可以利用Hamming距离下的LSH函数了
LSH的哈希函数要满足以下两个条件,
- 如果\(d(x,y) \le R\),则\(h(x) = h(y)\)的概率不小于\(P_1\)
- 如果\(d(x,y) \ge cR\),则\(h(x) = h(y)\)的概率不大于\(P_2\)
设向量的二进制表示的长度为\(nC\),如果向量\(x,y\)的Hamming距离为\(d\),则通过上面哈希函数的变换后,
\]
则有:
- 如果\(d(x,y) \le R\),则\(h(x) = h(y)\)的概率不小于\(P_1\),\(P_1 = \frac{nC-R}{nC} = 1 – \frac{R}{nC}\)
- 如果\(d(x,y) \ge cR\),则\(h(x) = h(y)\)的概率不大于\(P_2\),\(P_2 = \frac{nC-cR}{nC} = 1 – \frac{cR}{nC}\)
向量的Hamming距离和其映射后相等的概率之间的关系如下图:
当两个向量的Hamming距离为0,映射后其相等的概率为1;两个向量的二进制完全不同,Hamming距离为\(nC\)则其映射后相同的概率为0。
LSH参数
再来回顾下LSH的思想:在原空间中很近(相似)的两个点,经过LSH哈希函数的映射后,有很大概率它们的哈希是一样的;而两个离的很远(不相似)的两个点,映射后,它们的哈希值相等的概率很小。
从上面这句话可以看出LSH需要的四个参数:
- 原空间中两向量的距离\(R\)
在原空间中,如果两个向量的距离小于\(R\),表示这两个向量相似,经过映射后,其哈希值有有很大的概率是相同的。 - 相似的向量映射后哈希值相等的概率\(P_1\)
- 常数\(c\)
在原空间中,如果两个向量的距离大于\(cR\),表示这两个向量不相似,经过映射后,其哈希值相等的概率很小 - 不相似的向量映射后哈希值的概率相等的概率\(P_2\)
也就是说,对于任意向量\(x,y\),如果在原空间中其距离\(d(x,y) \le R\),则认为其是相似的。经过LSH哈希函数映射后,其哈希值相等的概率很大(\(P_1\));而对于在原空间中距离\(d(x,y) \ge cR\),则认为其是不相似的,经过LSH哈希函数映射后u,其哈希值相等的概率很小(\(P_2\))。
对于Origin LSH 已Hamming距离来度量向量的相似性来说,概率
P_2 = \frac{nC-cR}{nC} = 1 – \frac{cR}{nC}
\]
\(P_1,P_2\)可以通过上述公式求得,也就是说,只需要指定两个参数
- 向量相似的距离\(R\)
- 常数\(c(c>1)\),向量大于距离\(cR\)则表示不相似
概率增大
LSH的核心思想是,通过哈希变换后,变换前相似的向量在变换后有很大的概率(\(P_1\))哈希值是相同的;不相似的呢,其哈希值只有很小的概率(\(P_2\))是相同的。这样,两个概率\(P_1,P_2\)就是影响LSH检索的关键。理想的情况下,是相似的向量,其哈希值相同的概率是\(P_1=1\);不相似的向量,其哈希值相同的概率\(P_2 = 0\)。 理想情况毕竟是理想嘛,面对实际问题还是要现实一点的,对于\(P_1,P_2\)的关系:\(P_1\)尽可能的大,\(P_2\)较小,\(P_1,P_2\)有足够大的间隔。
通过上面的分析知道,\(P_1,P_2\)可以通过设置较大的相似距离\(R\)和一个小的常数\(c\),来保证\(P_1,P_2\)有足够大的间隔。在极端情况下,可以设置相似距离\(R\)等于二进制串的长度\(nC\),这样只有两个向量二进制串是完全相同情况下,\(P_1=1\)。 但这会导致相似检索的精度变的不那么可靠,对数据的噪声比较敏感。
所以对于指定了相似距离\(R\)以及常数\(c\)来说,可能其\(P_1,P_2\)之间的间隔不是足够的大,可以使用增加哈希键长度\(K\)以及哈希表的个数\(L\)来增大\(P_1,P_2\)之间的差。
增加哈希表个数\(L\)和哈希键长\(K\)实际上是不同哈希函数的组合。
- 增加哈希键长\(K\)
设\(h_i\)是哈希函数簇\(H\)中的任意函数,对于任意向量\(p,q\)满足$$P(h_i(p) = h_i(q)) = P_1$$
从\(H\)中随机的挑选\(K\)个哈希函数将向量映射为\(K\)长度的串,\(g(p) = [h_1(p),h_2(p),\cdots,h_k(p)]\) 则有:
\]
由于\(0 < P_1 < 1\),则\(P_1^K < P_1\),也就是说缩小了概率。
- 增加哈希表\(L\)
设现在有\(L\)个哈希表(也就是\(L\)个哈希函数簇\(H\)),每个哈希表都使用上面的方法产生一个组合的哈希函数\(g\),
这样可以得到\(L\)个哈希函数\(g_1,g_2,\cdots,g_l\),将这几个组合的哈希函数再组合到一起得到哈希函数\(G\)。
\]
由于使用一个哈希表找到最近邻的概率为\(P_1^K\),招不到最相似的概率是\(1 – P_1^K\)。那么使用\(L\)个哈希表找到最相似的概率
\]
上面公式给出了,使用\(L\)个哈希表,\(K\)个哈希函数的情况下,查找到最近邻的概率\(P = 1 – (1-P_1^k)^l\),下表给出了\(K = 4,L = 4\)的情况下,查找到最相似向量的概率
\(P_1\) | \(1 – (1-P_1^4)^4\) |
---|---|
0.9 | 0.9860 |
0.8 | 0.8785 |
0.7 | 0.6666 |
0.5 | 0.2275 |
0.4 | 0.0985 |
0.3 | 0.0320 |
0.2 | 0.0064 |
LSH 编码实例
下面看一个实例,假设有数据集合中有6个点:
A=(1,1) B=(2,1) C=(1,2)
D=(2,2) E=(4,2) F=(4,3)
首先进行Embedding操作点表示为二进制串,上述坐标的最大值为4,所以\(C=4\),维度为2,则\(n = 2\),所以二进制串的长度为8.
v(A)=10001000
v(B)=11001000
v(C)=10001100
v(D)=11001100
v(E)=11111100
v(F)=11111110
采用\(K=2,L=3\)的哈希函数组合,\(G = [g_1,g_2,g_3]\),其中\(g_i = [h_1,h_2]\)。
假设随机选择的哈希函数组合如下:
- \(g_1\)分别取第2位,第4位,也就是\(h_1(p) = p_2,h_2(p) = p_4\)
- \(g_2\)分别取第1位,第6位,也就是\(h_1(p) = p_1,h_2(p) = p_6\)
- \(g_3\)分别取第3位,第8位,也就是\(h_1(p) = p_3,h_2(p) = p_8\)
利用上面的哈希函数将6个点映射到三个哈希表中,结果如下:
设查询向量\(q = (4,4) = (11111111)\),可以计算出
g_2(q) = [11] \\
g_3(q) = [11]
\]
将上面3个哈希表中映射到\([11]\)号的向量取出来为\((C,D,E,F)\),接下来将这四个向量分别与\(q\)计算距离,距离最近的向量,即为最相似的向量,也就是向量\(F = (4,3)\)。
上述例子引用自局部敏感哈希深度解析
LSH的检索过程
从上面的例子中可以总结处LSH检索过程。
- 离线建立索引
- 选择满足\((R,cR,P_1,P_2)\)-sensive的哈希函数
- 根据对查找结果的准确率(即相邻的数据被查找到的概率)确定哈希表的个数\(L\),每个table内的hash functions的个数,也就哈希的键长\(K\),以及跟LSH hash function自身有关的参数
- 利用上面的哈希函数组,将集合中的所有数据映射到一个或多个哈希表中,完成索引的建立。
- 在线的查找
- 将查询向量\(q\)通过哈希函数映射,得到相应哈希表中的编号
- 将所有哈希表中相应的编号的向量取出来,为了保证查找速度,通常只需要取出来前\(2L\)个。
- 对这\(2L\)个向量进行线性查找,返回与查询向量最相似的向量。
总结
在做图像检索时,搜索资料发现使用KD树做索引效果不是很好,由于使用的是OpenCV的库,就像改为使用LSH的索引,但是OpenCV集成的LSH只支持整型的,而且对其中一些参数的设置不是很明白,搜集了些资料,形成了该篇文章。
搜集资料的过程才发现哈希函数的应用之广泛,就LSH这个点来说,搜集资料形成的本篇文章也也只是冰山一角,奈何没有太多的精力,目前仅止于了解。
相似性度量及LSH哈希函数
可以使用不同的方法来度量两个点的相似性,针对不同的度量方法,在进行局部哈希时使用的哈希函数也是不同的。
两个向量的相似性度量的方式很多,这里仅列举几个在计算机视觉中常用的几个度量方法,当然并不是所有的度量方式都能够找到相应的LSH哈希函数。例如,在LSH最初提出的时候,就没有找到基于欧式距离的LSH函数。
Hamming距离的LSH哈希函数
这也是Origin LSH,本文描述使用的距离度量。
在对图像进行匹配时,通常是将图像的描述子与数据中的图像描述子进行匹配实现的。在实时应用中,通常是使用二进制描述子,比如BIREF、BRISK、ORB等。对于二进制描述子使用的是Hamming距离。
对于二进制描述子,哈希函数就是直接选择描述子的某一个比特位,通过若干个哈希函数选择出来的位的级联,就形成了一个哈希键了。通过对这个哈希键对数据库中的描述子进行索引,即形成了一个哈希表,选择若干个哈希表来增大找到近似最近邻的概率。
Hamming距离指的是两个具有相同长度的向量中对应位置处值不同的次数。
Hamming距离的LSH哈希上面已经有描述,这里不再重复。
向量的夹角余弦的LSH哈希函数
用两个向量的夹角来衡量两个向量是不是相似,向量的夹角越小,表示它们越相似。
向量夹角的计算公式
\]
其中,\(\Vert \cdot \Vert\)表示向量的\(L_2-norm\).
例如,两个向量\(x = (1,2,-1),y = (2,1,1)\),则有
\]
\(\cos(\theta)\)的取值范围是\([0,\pi]\),仅在两个相同的方向相同时,其夹角的余弦值为0;当两个向量的方向相反时,其 夹角的余弦值为\(\pi\)。
适应向量的夹角余弦度量,对应的LSH hash function为:\(H(V) = sign(V·R)\),\(R\)是一个随机向量。\(V·R\)可以看做是将\(V\)向\(R\)上进行投影操作,其是\((d_1,d_2,(180-d_1)180,(180-d_2)/180)\)-sensitive的。
欧氏距离的LSH哈希
两个向量相似性度量,欧氏距离应该是比较常用的方法,但是在LSH才提出的时候,在欧氏距离下并没有找到合适的LSH函数。
关于更多E2LSH的信息可参考http://www.mit.edu/~andoni/LSH/