为了加快向量之间距离计算和比较速度,有人发明的Product Quantization方法,这个方法并不是一种索引,所以它并不能减少目标向量(要查找的向量),与数据库中向量的比较次数,但是它可以加快与每个数据库中向量比较时的计算量。
这个方法分为两部分,
第一部分是量化,其思想如下:
a)把一个维度很高的向量切分成好几个段,例如,128维度,切分成4段每段32维度的小向量,怎么切分呢?其实没啥高深复杂的,就是简单的从左到右直接切分(至于网上论文中所说的什么笛卡尔积、向量乘法之类唬人的名词,根本就不是这么回事,当然也不排除可能有更合适的切分方法)
b) 向量数据库中的所有向量,切分后的第一个段(32维度的向量),都取出来,做kmeans,计算它们的中心点,至于这些向量要分成几个区域,就由量化设计者决定了,例如,我决定分为256个区域,那么向量数据库中所有向量都拿出第一个段(32维度的向量),做kmeans,计算出256个中心点后,然后再把所有向量的第一段,分配给这256个区域,怎么分呢?分配到与它距离最近的个中心点,并且,我们给每个中心点一个编号(ID),每个库向量的第一个段,分配到某个中心点后,就用这个中心点的ID表示这个段的32维度的向量,这里的分配并不是归类存储,而是计算每个库向量的第一个段,应由哪个中心点的ID代表。这个信息要记下来。
然后所有库向量取出第二个段,也是用kmeans算法得到256个中心点,并编号,然后每个库向量的第二个段,用与它最近的中心点的ID代替。
然后所有库向量取出第三个段,用kmeans算法得到256个中心点,编号,然后每个库向量的第三个段,用与它最近的中心点的ID代替。
然后所有向量库取出第四个段,用kmeans算法得到256个中心点,编号,然后每个库向量的第四个段,用与它最近的中心点的ID代替。
这样对于向量数据库中的每个128维向量,都可以用4个ID组成的数组代替了,由于这些ID的编号是0-255,因此每个ID只用一个byte就可以表示,可以把这4个ID组成的数组,也看成是一个向量,只有4维并且每个维度8bit,当然这个4维的向量需要一个参照,就是每个段的256个中心点。
有了每个段的256个中心点这个参照,就可以可以把数据库中的每个128维向量,按照上面的方法,转化成4个ID组成的数组,这4个ID组成的数组就可以近似的代替这个128维的向量,这个4维数组,就是128维向量“量化”后的结果。
这4段每段256个中心点就是一个“码表”(这个定义尚未统一,有人觉得码表也包括所有量化后的向量)
总之,经过上面的“量化”,得到了每段的中心点和所有原始向量量化后的向量,它们共同组成的信息库,后面就可以用来快速比较了。
第二部分是比较:
有了前面的量化后的数据:每段的中心点和(数据库中)每个向量的量化表示。当有目标向量到来,想要和库中的所有向量比较,找到最近的前K个时,这个比较方法是怎样的呢?
a)首先目标向量也要分段,按照其它向量的方式分,例如,128维的目标向量分为4段,每段是一个32维的向量。
b)数据库中存储着每个段的256个中心点,目标向量的每个段,要计算这个32维向量与每个中心点的距离,即每个段会得到256个距离,这些距离要保存下来。对于本例,一共需要计算4x256个距离。
c)前一步其实完成了目标向量的量化和码表计算,它的码表就是这4x256个距离,这些距离可以放到二维数组里,对于每个段,每个距离都有一个编号,这个编号和其对应中心点的编号相同,如下图:
d)然后就要比较了,比较时,对于一个量化后的库向量,它由4个ID组成,对于目标向量,之前已经计算好每个段的32维向量与各自段中256个中心点的距离,并且距离的编号与数据库码表中心点的编号一一对应,因此,假设取出一个库向量的第一个ID,在目标向量的距离码表的第一段中查出一个距离d1,这就是目标向量与库向量的距离在第一段中的距离(这只是两个向量总的距离指标的一个分量),然后取库向量的第二个ID,在目标向量的距离码表的第二段中查出一个距离d2,这是第二段的距离,然后再查出第三段距离d3、第四段的距离d4,最后,把d1+d2+d3+d4的和作为整个目标向量与这个库向量的距离指标。计算一个目标向量与一个库向量距离的过程,只要4次查表和3次加法,要比如实的计算两个128维向量的距离要快的多。
当然对于每个目标向量,都要有个建立距离表的过程,但是这只需要建立一次,就可以用于多次与库向量的距离计算。
参考
【Faiss】PQ和IVF介绍_ivf算法-CSDN博客
理解 product quantization 算法
https://zhuanlan.zhihu.com/p/560981386
图像检索:再叙ANN Search