faiss - PQ(ProductQuantizer) 源码详解

Product Quantizer是一种高效的向量量化方法,相对于普通Quantizer,它将向量分段并分别进行聚类,从而能用更少的码本表达大量中心点。在训练时,每个子空间独立聚类,查询时通过组合每个段的最近中心点,实现更多可能的组合,节省存储空间。此方法在大规模数据处理和检索中具有优势。
摘要由CSDN通过智能技术生成

PQ (Product Quantizer), 相对与普通的Quantizer而言

普通Quantizer 将整个向量通过单次聚类达到量化。

Product Quantizer 则通过对向量分段(这里的分段是针对向量本身的,例如128维的向量分为2个64维的向量),每段分别聚类得到多个量化结果(每段一个量化结果),这样的好处是同较小的码本来表达非常大量的码

把256个128维的向量分为4段,每段有256个32维的向量,每段独立训练中心点,这样在查询时从每个段中选一个最近的中心点(可以采用排列组合的思想理解),所以可能的情况有256*256*256*256, 这样可以用较少的向量,训练出更多的中心点,而且还省空间。

而普通Quantizer就只有256个中心点。

 

 

void ProductQuantizer::train (int n, const float * x)
{
    if (train_type != Train_shared) { ///共享词典
        train_type_t final_train_type;
        final_train_type = train_type;
        if (train_type == Train_hypercube ||
            train_type == Train_hypercube_pca) { ///使用超立方体初始化中心点
            if (dsub < nbits) { ///猜测是形成不了nbits个空间
                final_train_type = Train_default;
                printf ("cannot train hypercube: nbits=%ld > log2(d=%ld)\n",
                        nbits, dsub);
            }
        }
        ///为每个子空间分配内存(向量个数 * 子向量维度)
        float * xslice = new float[n * dsub];
        ScopeDeleter<float> del (xslice);
        for (int m = 0; m < M; m++) { ///处理每个子空间
            for (int j = 0; j < n; j++)
                memcpy (xslice + j * dsub,
                        x + j * d + m * dsub,
                        dsub * sizeof(float));

            Clustering clus (dsub, ksub, cp); /*dsub:子向量空间维度,ksub:子向量空间中心点个数 cp:参数*/

            // we have some initialization for the centroids

            if (final_train_type != Train_default) {
                clus.centroids.resize (dsub * ksub); ///为中心点分配内存(空间维度 * 中心点个数)
            }

            switch (final_train_type) {
            case Train_hypercube:
                init_hypercube (dsub, nbits, n, xslice,
                                clus.centroids.data ());
                break;
            case  Train_hypercube_pca:
                init_hypercube_pca (dsub, nbits, n, xslice,
                                    clus.centroids.data ());
                break;
            case  Train_hot_start:
                memcpy (clus.centroids.data(),
                        get_centroids (m, 0),
                        dsub * ksub * sizeof (float)); ///只是从子空间中赋了值
                break;
            default: ;
            }

            if(verbose) {
                clus.verbose = true;
                printf ("Training PQ slice %d/%zd\n", m, M);
            }

            IndexFlatL2 index (dsub); ///
            clus.train (n, xslice, assign_index ? *assign_index : index); ///子空间
            set_params (clus.centroids.data(), m); ///保存每个子空间的中心点
        }


    } else {

        Clustering clus (dsub, ksub, cp);

        if(verbose) {
            clus.verbose = true;
            printf ("Training all PQ slices at once\n");
        }


        IndexFlatL2 index (dsub);

        clus.train (n * M, x, assign_index ? *assign_index : index);
        for (int m = 0; m < M; m++) {
            set_params (clus.centroids.data(), m);
        }

    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值