论文名称《Product quantization for nearest neighbor search》
摘要
论文介绍了一种叫做乘积量化(Product quantization,PQ)的方法实现近似的最近邻检索。主要的思想是将数据进行切分,分块进行量化,然后在笛卡尔空间内计算各块量化结果的积得到整个数据数据的量化结果。并且作者提供了对称距离计算(SDC)和非对称距离计算(ADC)进行距离的比较,实验表明了ADC的准确率更高;作者进一步将ADC与反向文件系统进行结合实现了IVFADC的快速检索算法。
简介
在很多应用中都需要计算高维向量之间的欧氏距离,也就是最近邻检索。
常用的最近邻检索方法有KD树、Hash方法,但是KD树在特征维度比较高时效率并不优于简单的循环比对,算法的复杂度依然是O(nD)。
Hash的方法了解的不太多,2个开源工具FALCONN和NMSLIB。
理论知识
向量量化
向量量化的目的在于降维,量化的过程就是定义一个量化函数
q
将输入向量
量化会带来误差,平均一个量化器优劣的标准是 MSE(q)=EX[d(q(x),x)2] =∫p(x)d(q(x),x)2dx ,其中 d(x,y)=||x−y|| 就是向量x和y之间的欧氏距离。
为了获取最有的量化器,就需要满足Lloyd最优化条件,首先,向量x必须量化到和它距离最近类中心;第二个条件是重建结果是属于一个Voronoi Cell的向量集的期望。一般都是用k-means方法来进行量化,首先随机制定几个中心位置,将向量集中的每个向量分配到离它最近的类中心,然后再重新计算分配后的类中心的位置,迭代,得到最优化的分配结果。
由于量化之后的类中心个数一共是k个,所以每一个向量构建的索引的长度为 log2k ,一般情况下k为2的整数次幂。
乘积量化
参考了 http://blog.youkuaiyun.com/CHIERYU/article/details/50321473
乘积量化是对普通向量量化的优化。
对于128维的向量,一个普通的量化器产生64bits的code,那么类中心的个数为
264
,那么训练一个k-means需要的样本上为k的数倍,这么多的样本很难获取,同时即便是存储表示k个类中心的D*k(D是向量的维度)个浮点数也需要非常大的存储空间,因此实际应用中很难实现。
乘积量化是将向量分为独立的
m
个子向量,每个子向量的长度为
PQ算法中
m
和
作者实验表明了
m,k∗
与MSE之间的关系,如下图所示:
m固定时,
k∗
越大,MSE越小,但所需的存储空间和计算复杂度越大。
m=8,k∗=256
是一组通常比较合理的参数设置。
量化后的检索
参考了 http://blog.youkuaiyun.com/CHIERYU/article/details/50347735
检索分为了两种ADC和SDC两种方式,如下图所示:
SDC就是计算两个向量都量化后的码之间的差值,ADC则是计算未量化的x向量和量化后的y向量之间的差值。
ADC方法的距离误差上限就是量化器的MSE(q),但SDC的距离误差上限为2*MSE(q),同时SDC需要更多的计算过程,因此ADC更加适用。
检索的具体实现
使用IVFADC算法进行向量在大数据集中的最近邻匹配的查找。整个过程分为了构建索引和查询两个过程。如下图所示:
下面的内容转载自:http://blog.youkuaiyun.com/CHIERYU/article/details/50347735
构建索引的过程主要分为上图中主要涉及三个过程,coarse quantizer,product quantizer和append to inverted list。
- coarse quantizer。
对数据库中的所有特征采用K-means聚类,得到粗糙量化的类中心,比如聚类成1024类,并记录每个类的样本数和各个样本所属的类别。这个类中心的个数就是inverted list的个数。把所有类中心保存到一张表中,叫coarse_cluster表,表中每项是d维。 - product quantizer
计算y的余量,这里写图片描述,用y减去y的粗糙量化的结果得到r(y)。r(y)维数与y一样,然后对所有r(y)的特征分成m组,采用乘积量化,每组内仍然使用k-means聚类,这时结果是一个m维数的向量,这就是上篇文章中提到的内容。把所有的乘积量化结果保存到一个表中,叫pq_centroids表,表中每项是m维。 - append to inverted list
前面的操作中记录下y在coarse_cluster表的索引 i ,在pq_centroids表中的索引j,那么插入inverted list时,把(id,j)插入到第i个倒排索引Li 中,id是y的标识符,比如文件名。list的长度就是属于第i类的样本y的数目。处理不等长list有些技巧。
检索的过程主要包括四个操作:
- 粗糙量化
对查询图像x的特征进行粗糙量化,即采用KNN方法将x分到某个类或某几个类,分到几个类的话叫做multiple assignment。过程同对数据集中的y分类差不多。 - 计算余量
计算x的粗糙量化误差 r(x)=x−qc(x) 。 - 计算d(x,y)
对r(x)分组,计算每组中r(x)的特征子集到pq_centroids的距离。根据ADC的技巧,计算x与y的距离可以用计算x与q(y)的距离,而q(y)就是pq_centroids表中的某项,因此已经得到了x到y的近似距离。 - 最大堆排序
堆中每个元素代表数据库中y与x的距离,堆顶元素的距离最大,只要是比堆顶元素小的元素,代替堆顶元素,调整堆,直到判断完所有的y。
multiple assignment:
如上图所示,x与y都分到了1这个voronoi包,如果不采用multiple assignment方法,则只会在voronoi包1中搜索与x接近的y,明显voronoi包2,voronoi包3中与x更近的y不会被检索到,采用multiple assignment的方法,在x的w个最近粗糙类中心中搜索y,那么准确率就提高了。但这要求遍历w个list,费内存和时间,是以牺牲空间和时间换准确率。
PQ算法的高效实现可以参考:https://github.com/facebookresearch/faiss