图像检索中,对一幅图像编码后的向量的维度是很高。以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\)。
所以就有两个准则:

  1. 使用\(L_1\)也就是曼哈顿距离进行度量。 基于假设\(L_1\)和\(L_2\)的度量效果相差不大。
  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位相同的所占的比例,即有:
\[
P_1 = 1 - \frac{R}{d},P_2 = 1-\frac{cR}{d}
\]
其中,\(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算法:

  1. 找到数据集中所有向量的所有分量的最大值\(C\)。
  2. 对于向量\(x = (x_1,x_2,\cdots,x_n)\),\(n\)是向量的维度。将向量每个分量\(x_i\)转换为长度为\(C\)的二进制序列,二进制序列为前\(x_i\)个1,剩余的为0。假设\(x_i = 5,C=10\),转换后的二进制序列为\(1111100000\)。
  3. 这样一个\(d\)维的向量就转变为\(nC\)长度的二进制串。

Embedding操作是保持距离的,转换后两个向量的距离是不变的。转变为Hamming距离后,就可以利用Hamming距离下的LSH函数了

LSH的哈希函数要满足以下两个条件,

  1. 如果\(d(x,y) \le R\),则\(h(x) = h(y)\)的概率不小于\(P_1\)
  2. 如果\(d(x,y) \ge cR\),则\(h(x) = h(y)\)的概率不大于\(P_2\)

设向量的二进制表示的长度为\(nC\),如果向量\(x,y\)的Hamming距离为\(d\),则通过上面哈希函数的变换后,
\[P(h(x)=h(y)) = \frac{nC-d}{nC}\]
则有:

  1. 如果\(d(x,y) \le R\),则\(h(x) = h(y)\)的概率不小于\(P_1\),\(P_1 = \frac{nC-R}{nC} = 1 - \frac{R}{nC}\)
  2. 如果\(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_1 = \frac{nC-R}{nC} = 1 - \frac{R}{nC} \\
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)]\) 则有:
    \[
    P(g(p) = g(q)) = P(h_1(p) = h_1(q))\cdot P(h_2(p) = h_2(q)) \cdots P(h_k(p) = h_k(q)) = P_1^K
    \]
    由于\(0 < P_1 < 1\),则\(P_1^K < P_1\),也就是说缩小了概率。

  • 增加哈希表\(L\)
    设现在有\(L\)个哈希表(也就是\(L\)个哈希函数簇\(H\)),每个哈希表都使用上面的方法产生一个组合的哈希函数\(g\),
    这样可以得到\(L\)个哈希函数\(g_1,g_2,\cdots,g_l\),将这几个组合的哈希函数再组合到一起得到哈希函数\(G\)。
    \[
    G = [g_1(p),g_2(p),\cdots,g_l(p)]
    \]

由于使用一个哈希表找到最近邻的概率为\(P_1^K\),招不到最相似的概率是\(1 - P_1^K\)。那么使用\(L\)个哈希表找到最相似的概率
\[
P(G(p) = G(q)) = 1-[1 - P(g_1(p) = g_2(q)) \cdots P(g_l(p) = g_l(q))] = 1 - (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_1(q) = [11] \\
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哈希函数

用两个向量的夹角来衡量两个向量是不是相似,向量的夹角越小,表示它们越相似。

向量夹角的计算公式
\[
\cos(\theta) = \frac{x \cdot y}{\Vert x \Vert \cdot \Vert y \Vert}
\]
其中,\(\Vert \cdot \Vert\)表示向量的\(L_2-norm\).
例如,两个向量\(x = (1,2,-1),y = (2,1,1)\),则有
\[
\cos(\theta) = \frac{1 \times 2 + 2 \times 1 + (-1) \times 1}{\sqrt{6} \cdot \sqrt{6}} = \frac{1}{2}
\]
\(\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/

图像检索(6):局部敏感哈希索引(LSH)的更多相关文章

  1. 在茫茫人海中发现相似的你——局部敏感哈希(LSH)

    一.引入 在做微博文本挖掘的时候,会发现很多微博是高度相似的,因为大量的微博都是转发其他人的微博,并且没有添加评论,导致很多数据是重复或者高度相似的.这给我们进行数据处理带来很大的困扰,我们得想办法把 ...

  2. 局部敏感哈希(LSH)之simhash和minhash

    minhash 1. 把文档A分词形成分词向量L 2. 使用K个hash函数,然后每个hash将L里面的分词分别进行hash,然后得到K个被hash过的集合 3. 分别得到K个集合中的最小hash,然 ...

  3. 从NLP任务中文本向量的降维问题,引出LSH(Locality Sensitive Hash 局部敏感哈希)算法及其思想的讨论

    1. 引言 - 近似近邻搜索被提出所在的时代背景和挑战 0x1:从NN(Neighbor Search)说起 ANN的前身技术是NN(Neighbor Search),简单地说,最近邻检索就是根据数据 ...

  4. 海量数据挖掘MMDS week7: 局部敏感哈希LSH(进阶)

    http://blog.csdn.net/pipisorry/article/details/49686913 海量数据挖掘Mining Massive Datasets(MMDs) -Jure Le ...

  5. 局部敏感哈希LSH

    之前介绍了Annoy,Annoy是一种高维空间寻找近似最近邻的算法(ANN)的一种,接下来再讨论一种ANN算法,LSH局部敏感哈希. LSH的基本思想是: 原始空间中相邻的数据点通过映射或投影变换后, ...

  6. 大规模异常滥用检测:基于局部敏感哈希算法——来自Uber Engineering的实践

    uber全球用户每天会产生500万条行程,保证数据的准确性至关重要.如果所有的数据都得到有效利用,t通过元数据和聚合的数据可以快速检测平台上的滥用行为,如垃圾邮件.虚假账户和付款欺诈等.放大正确的数据 ...

  7. 局部敏感哈希(Locality-Sensitive Hashing, LSH)方法介绍

    局部敏感哈希(Locality-Sensitive Hashing, LSH)方法介绍 本文主要介绍一种用于海量高维数据的近似近期邻高速查找技术--局部敏感哈希(Locality-Sensitive ...

  8. 局部敏感哈希(Locality-Sensitive Hashing, LSH)

    本文主要介绍一种用于海量高维数据的近似最近邻快速查找技术——局部敏感哈希(Locality-Sensitive Hashing, LSH),内容包括了LSH的原理.LSH哈希函数集.以及LSH的一些参 ...

  9. 局部敏感哈希(Locality-Sensitive Hashing, LSH)方法介绍(转)

    局部敏感哈希(Locality-Sensitive Hashing, LSH)方法介绍 本文主要介绍一种用于海量高维数据的近似最近邻快速查找技术——局部敏感哈希(Locality-Sensitive ...

随机推荐

  1. BZOJ_4756_[Usaco2017 Jan]Promotion Counting_树状数组

    BZOJ_4756_[Usaco2017 Jan]Promotion Counting_树状数组 Description n只奶牛构成了一个树形的公司,每个奶牛有一个能力值pi,1号奶牛为树根. 问对 ...

  2. hello spring春天来了

    这是小小小零食  废话不多说 现在看到 spring这个管家 先说第一个 ioc :在每个框架的中都有一个容器的概念,所谓的容器就是将常用的服务,封装起来,然后,用户只需要遵循一定的规则,就可以达到统 ...

  3. 我手写的简易tomcat

    前述 自己手写的简易的tomcat,实现了tomcat的基本响应功能,项目代码已经上传到我的Github,刚刚开始学习这里,当前还存在很多问题 项目简述及代码 当我们的Web运行的时候,从浏览器发出的 ...

  4. 从壹开始 [ Id4 ] 之二║ 基础知识集合 & 项目搭建一

    前言 哈喽大家又见面啦,感觉好久没更新了,这几天看了一本书<解忧杂货铺>,嗯挺好的,推荐一下

  5. 【Python3爬虫】最新的模拟登录新浪微博教程

    一.写在前面 首先呢,由于之前重装系统,又要重新配置环境,然后还有一些别的事,导致我一直没有写爬虫了,不过现在又可以继续写了. 然后我这次说的模拟登录新浪微博呢,不是使用Selenium模拟浏览器操作 ...

  6. JenKins使用pm2部署.net core网站

    登录事先准备好的 Jenkins 1 新建任务 2 源码管理 git 输入正确地址 3 构建环境:Delete workspace before build startsAbort the build ...

  7. Java集合 - List介绍及源码解析

    (源码版本为 JDK 8) 集合类在java.util包中,类型大体可以分为3种:Set.List.Map. JAVA 集合关系(简图) (图片来源网络) List集合和Set集合都是继承Collec ...

  8. 判空、判等、转码的StringUtil

    目录 StringUtil类 StringUtil类 import java.io.UnsupportedEncodingException; /** * 字符串工具 */ public class ...

  9. win10环境下如何运行debug

    在学习汇编的时候,会需要用到debug调试程序,但是现在win10默认已经移除了这个插件,我们需要手动安装,下面就告诉大家如何在win10环境下安装debug. 1:准备工具 1.1 DOSBox 1 ...

  10. 【Android】用Cubism 2制作自己的Live2D——官方App样例源码学习(1)!

    前言- 上几篇文章,我们一个一个的研究了Cubism官方提供的Android使用Live2D的简单例子,但是依旧和大家平时见到的还是有很大差距的.在研究了代码差不多一周以后,我决定还是用文字的形式记录 ...