乘积量化学习和实战总结

由于一直在做视频检索相关的工作,不可避免的要和各种图像检索的算法打交道(因为视频最终还是要解码成图像的形式)。乘积量化作为一种很优秀的图像编码方法,博主自然不会错过。在折腾了长达3个月之后,有所小成,特此记录下来,权当复习,同时也希望与相关领域的道友进行交流。

一、为什么要用乘积量化

乘积量化就是一种编码方法。当图像数据库过于庞大时,直接存储所有的数据并且做相似性度量检索是不现实的。为了能够减少存储资源的开销,并且提高检索的效率,必须对原始数据做一些瘦身操作。这其中包括提取图像的特征向量和对提取出的特征向量进行编码。

因为我们可能并不需要图像中的所有信息就可以判断它是否是我们的目标图像。比如,我们想要知道一副图中是否有猫,我们不用关心这只猫的颜色、姿态、位置等信息,我们只需要在图中找到猫的特征就可以证明猫的存在。而这些人类视觉的特征转换成机器语言就是特征向量。提取图像中的特征向量有很多成熟的算法,如SIFT、SURF、ORB、CNN的feature-map等。有很多现成的图像检索算法都是基于SIFT,所以博主建议如果有时间可以认真学习一下并且亲自动手实现,而不只是调用现成的工具。传统的图像检索方法,如VLAD、BOF、FV等是针对小数据集的,所以它们基本上没有针对大数据集的编码操作,而为了能够实现海量数据的检索工作,避免枚举计算,乘积量化(product quantization)是一个很理想的方法。哈希算法也是一个很不错的算法,但是空间复杂度过高。

考虑一个场景,从100万张图像中提取出了20亿的SIFT描述子用来建数据库。如果没用对这些数据进行编码操作,首先这些向量的存储就是一个大问题,虽然已经比直接保存图像小了很多,但数据量仍然很庞大,之后是查询一条SIFT向量需要计算20亿次!!!!!!这是无法用于实际生产的。乘积量化兼顾空间复杂度和时间复杂度,在两者之间取得了很好的平衡,既可以保证不用存储海量的数据,又保证了检索的速度。

二、乘积量化原理及算法步骤

考虑一种场景,用一条B=64 bit的数据表征一条128维的SIFT描述子。

传统量化算法:

(1)在training-data上学习出codebook;

(2)assign 每一条SIFT到与它最相似的codeword;

其中,第(1)步是在训练数据集图像提取的SIFT描述子上做K-means,codebook的大小是k*128。这个k值的选取很关键,参考论文数据k=256,并且k和B是有关系的

B=log2K

B是以2为底,k的对数。这种量化方法的缺点是显而易见的,当B=64 bit 时,k=2^64,这是一个非常大的数字,几乎是不可能跑的出来的。

乘积量化的思想是化整为零。

k=(k*)^m

我们不能直接做2^64的k-means,但是我们可以做k*=256的k-means,只需要把原始数据进行划分。

D*=D/m

当D=128时,m=8,D*=16,这些数据来源于论文,是经过大量数据验证的可用数据。

也就是说我们64bit 的B表示成了8个8bit的b的串联,即B=b1*b2....*bm,也即是乘积量化。

我们只要分别对D的8个小块做k*=256的k-means,然后把它们串联起来,就得到了我们想要的B。

这只是解决了编码的问题,但是没有解决枚举检索的问题。为了解决这个问题,论文提出了invert-file 这种结构。既是在做乘积量化之前做一个粗量化。即先对所有的SIFT做一个划分,依然是用k-means,不过k=1024,之后再用向量和它被分派到的centroid的残差做乘积量化,再检索时,对查询向量做同样的操作,就可以避免枚举检索。


编码算法:

(1)量化y到它的code work  qc(y)(codebook 1024*128,训练集上得到)

(2)计算y 和 qc(y)的残差,r(y)=y-qc(y)

  (3)  对r(y)做乘积量化,参考上述步骤,r(y)的codeword 是qp(r(y)),codebook 256*128,在r(y)上训练得到

(4)把r(y)的code word加到对应的Invert file中。

检索算法:

(1)量化x到它的code work  qc(x)(codebook 1024*128,训练集上得到)

(2)计算x 和 qc(x)的残差,r(x)=x-qc(x)

(3)在x属于的code word中计算x与所有向量之间的距离,然后输出最近邻的k个。

如图


整个算法流程就完成了。这其中还有很多细节问题,不是三言两语能够说明白的,有兴趣的同学可以和我交流。关于我做的东西会在之后的博文中展示。

猜你喜欢

转载自blog.csdn.net/zshluckydogs/article/details/80927776
今日推荐