Product Quantizer 是一种将空间内的点x,通过kmeans算法映射到多个聚类中心, 然后在通过聚类中心表示该点x的向量压缩方法.
笔者在ANN算法和fasttext算法中, 都见识到了ProductQuantizer的应用. 并为节约内存,减少时延起到了关键性的作用.
using in fasttext
在fasttext 算法中, 每个词都由一个dim维的embedding表示. 因此, 对于一个有N个词的fasttext模型,存储embedding的空间就是dim * N. ProductQuantizer, 是将每个embedding的dim做一个dsub个分组,每一组有dim/dsub维. 将每一组的embedding做kmeans聚类,取出k个centroids. 每一组的embedding都可以映射到k个聚类中心. 聚类中心的个数为k * dsub个.
ProductQuanizer之后,会有两个集合,一个是mapcentriod: 也就是每个embedding可以映射到哪个centroids, 大小[N* dsub * k]; centroids聚类中心的点, 大小:[dim * k];
对运算时延的影响: 而对每个embedding做projection的时候, 都会做一个embedding * [dim * T]的乘法, 就可以将矩阵乘法的复杂度变成: [dim/dsub * dim/dsub].
对空间的影响: fasttext 模型的ProductQuantizer是用在embedding与后面dense层的映射, 将embedding压缩到 dim * k,其中, dim为原有维数, k 为聚类中心数. 原有embedding的存储空间是 dim * N, 现有embedding的存储空间是dim * k, 将空间减少了 dim * (N-k).
可以达到1/1000的压缩效果, 将1G的模型压缩到1M左右. 分类f1值的损失不超过2%.
整体Product Quantizer流程如下:
using in ANN
ANN一般用于推荐场景中。将每个doc用D维的向量表示,如果doc的数量为N,那么一共是N * D维的矩阵。 对于每一个user,有相同维数D的vector表示,那么,对于该user来说,需要做的就是N * D *D的乘法来计算user与doc之间的相似度,取出top的文章来做召回。
NDD per user的算法复杂度对于推荐系统来说,是非常大的。
那么,首先第一步,就是使用ProductQuantizer的方法对向量进行压缩量化。
步骤与之前介绍的类似,将D维的向量分为M组,每组的维数D/M, 并将每一组用kmeans将分裂后的向量映射到k个聚类中心,聚类中心一共有k*M个.
在寻找与user vector(uv)最相似的doc时,可以采用两种方法:
计算uv对应的聚类中心,q(uv), 并计算对应 doc的聚类中心, q(doc), 使用q(uc)与q(doc)的对应向量的相似度代表uv 和doc的相似度。当然,q(uc)与q(doc)的相似度是提前计算好的,那么时间复杂度就集中在寻找user id的聚类中心的复杂度上(doc的可以提前算好放到队列里面)。从NDD-> DD/M*K
时间复杂度有所减小。
为了追求更高的精度,往往计算的是uv 与q(doc)之间的相似度。q(doc)是直接计算好的,那么就需要求出similarity(uv, q(doc)). 时间复杂度就多了一层uv 与聚类中心的相似度的计算,相似度计算的复杂度为K * D/M *D. 时间复杂度也会很大程度的减小。
当然,在实际ANN应用过程中,还会根据聚类中心做聚类中心与doc向量残差的分桶和倒排,分桶的过程也同样基于ProductQuantizer, 实现更精确的查询和检索,这个有兴趣的读者可以进一步了解。关于ProductQuantizer 算法的介绍就这么多了.
参考文档:
ANN: https://zhuanlan.zhihu.com/p/378725270
fasttext 源码: GitHub - facebookresearch/fastText: Library for fast text representation and classification.