文章Product Quantization Tree (PQT)的理解

首先话不多说,贴上文章《Efficient Large-scale Approximate Nearest Neighbor Search on the GPU》,点进去的是作者的个人主页,在里边找到这篇文章即可,最重要的是作者附带了源码哦(文章源码链接)。
按照惯例,还是先说说相关知识,再详细介绍本文。

相关知识

  • 最近邻检索的认识可以看看这个最近邻检索的简单综述。
  • 在基于内容的图像检索中,对于下面这样的一幅图片,我们首先会提取它的一些特征向量(图中框住的小短线),比如根据几何形状、颜色强度、表面纹理等提取的局部特征描述子SIFT,和根据前景与后景等提取的全局特征描述子GIST,这两个是在特征向量检索中最常用的数据集。然后对于这些特征向量,会通过一些变换对应到空间中的这些点集,最近邻检索其实就是在这些点集中寻找与这个查询点最近的点,很直观的办法就是计算这个点与所有的点的距离,然后排序找出最小的,但是在数据量与维度都很大的情况下,这种穷举的办法显然是不可行的。因此矢量量化的办法就是对这些空间中的点集先进行聚类,把它们划分成几种类别,每个类别中都有一个对应的中心点,然后将这些中心点用来构建码本。
    文章Product Quantization Tree (PQT)的理解_第1张图片码本就相当于一个词典,码本中的元素码字就相当于词典中的首字母索引,在查询的时候,我们可以先通过首字母找到它所属的类别,然后再在这个类别中查找与它最近似的元素。比如要查找与单词boot最相似的元素,首先找到首字母b开头的单词列表,再在其中找到与它最近似的元素book。这就从某种程度上很大的提高了检索效率,比线性搜索要快好多。
    文章Product Quantization Tree (PQT)的理解_第2张图片
    但是矢量量化仍存在的问题就是在大数据量、高维度的情况下,为了提高精度我们需要划分更多的类别,这就导致码本的大小越来越大,难以进行存储。
  • 因此就有了乘积量化的出现(很经典的算法,论坛各种相关解析),简单地说,在这样的一个二维空间中,灰色的点代表原本的数据集,红色的点代表矢量量化的量化结果,而乘积量化则是先将这个二维空间划分为两个相互正交的子空间,即x与y,然后再分别在这两个子空间中独立地进行矢量量化,将量化结果做笛卡尔乘积就可得到最终的结果。
    文章Product Quantization Tree (PQT)的理解_第3张图片乘积量化的最大优势就是,比如在一个128维的空间中,将其划分为四个子空间,如果在每个子空间生成100个码字,那么做笛卡尔积就相当于构成了一亿个码字,这就彻底解决了以前因为码字太多难以存储的问题。

本文内容

本文提出的乘积量化树是结合了倒排多索引与分层乘积量化的思路,主要工作有两级的乘积量化树、码字的启发式提名、通过直线量化的重排序,以及在GPU上的实现。

  • 首先是两级的树结构,对于这些灰色的点集首先进行乘积量化,也就是在每个子空间先聚类生成这些蓝色的小方块,再对这些方块类别中的元素进行二次聚类生成这些红色的点,将各个子空间作乘积就得到了乘积量化树的结果。图中蓝色小方块代表一级量化,每一个小方块再量化为四个(每维两个)二级红色的点。
    文章Product Quantization Tree (PQT)的理解_第4张图片
    下面这个是检索空间的示意图,上下部分代表划分的两个子空间,在一级量化后生成4个码字,然后通过计算查询向量x与它们的距离,筛选出前两个最近的码字再进行二次量化。这样的树形结构加速了检索的效率,在每个子空间第一层进行4次距离计算,第二层10次距离计算,总共28次的距离计算就可以检索20*20=400个码字。
    文章Product Quantization Tree (PQT)的理解_第5张图片
  • 通过上面的两级量化会在每个子空间生成可能的最近码字,对于这些码字会按照它们与查询向量的距离从小到大排序,而最终要编码的码字则是按照笛卡尔积组合这些所有的子空间的码字。
    文章Product Quantization Tree (PQT)的理解_第6张图片
    对于最近邻检索,则是以它们的最近距离的组合为起点,即Bi, i = (i10, i20, … , iP0),进行启发式地遍历其邻近的点。文章Product Quantization Tree (PQT)的理解_第7张图片这个是倒排多索引中进行遍历的一个例子,查询向量q被划分到v和u两个子空间上,在每个子空间中计算它与不同码字之间的距离并按从小到大排列,将这两个序列组合就能构成多种距离值,以u3、v4组合的最小值0.6为起点,按照迪杰斯特拉算法进行探索查找,最终会构成一个距离查询向量从小到大的候选集。

    上面的方法是可以产生一个比较理想的候选集,对应的是这里的绿色箭头,然而由于它的连续性,无法实现在GPU上的并行。采用这样的(蓝色)各向同性扩散的方法可以实现并行化,但是很明显这样遍历的候选集存在误差(两个10包含进去,两个8却没有包含进去)。因此本文采用一种各向异性扩散的方法(红色),可以采用不同的斜率使得每个部分用来组合的码字数量不同,从而生成的遍历序列更接近于采用迪杰斯特拉(绿色)的办法。
    文章Product Quantization Tree (PQT)的理解_第8张图片

  • 在传统的乘积量化中,数据库中点x1、x2所属bk这个类别,对于查询点y,若bk作为候选集,那么仍需要计算y与bk中的所有元素的距离来寻找最近邻。
    文章Product Quantization Tree (PQT)的理解_第9张图片
    在本文中,选择将每一个数据库中的点映射到离它最近的一级量化类中心的连线上,即用这些紫色的点来表示原本的数据点,这些点的确定需要一个系数λ,以及两个码字ci、cj,因此对于数据库中的所有向量可以用这样的一个三元组来编码,这些都是在离线阶段完成的。
    三元组
    通过将数据点x映射为这个紫色的点,那么查询点y与x之间的距离就变成了到这个紫色点的距离hp,hp的计算可以通过一个简单的三角测量法实现,其中ap、bp在树的遍历时已经计算,cp和λp在离线阶段进行数据库的构建时已经完成。因为计算都是利用已经计算过的中间值,且可以并行实现,所以本文的重排序特别的高效。
    文章Product Quantization Tree (PQT)的理解_第10张图片
  • 在GPU上并行实现采用的是CUDA,有三个主要的核函数,第一个用来计算查询向量到所有的第一层类中心的距离,并对它们进行排序,第二个基于第一层的输出计算第二层的类中心,第三个核函数用来计算直线量化,每个block负责处理一个候选集,block中的多个线程根据之前映射点计算的办法,并行计算这些候选向量并进行排序。文章Product Quantization Tree (PQT)的理解_第11张图片

总结

文章是发表在2016年ieee计算机视觉与模式识别会议上,依照作者的源码简单跑了一下他给的cpu版本的,效果还不错,gpu版本奈何硬件条件不够,只能暂时搁置了。按照文章的思路,可以将不同的算法用来组合这种树形结构。
注:文中部分例图来自于网络或相关论文(另外小弟不太会编辑数学公式,就勉强截图看看了)。

你可能感兴趣的:(学习记录,最近邻检索)