Faiss之IVF详解

目录

1. 构建

2. 训练

2.1 训练量化器

2.2 训练残差

3. 添加向量

3.1 寻找最近的聚类中心

3.2 将向量id和值添加到对应倒排list中

4. 搜索

4.1 pmode=0

4.2 pmode=1

4.3 pmode=2

5. 总结


老规矩,先上一张图:

总的概括:IVF主要利用倒排的思想保存每个聚类中心下的向量(id,vector),每次查询向量的时候找到最近的几个中心,分别搜索这几个中心下的向量。通过减小搜索范围,大大提升搜索效率。

本文依次从IVF索引的构建(初始化),训练,添加向量,搜索四个方面剖析IVF索引。

1. 构建

先呈上一张IVF索引相关的几个类的关系图:

IVFIndex主要继承自一个通用的Index类和一个量化器类。Index类是所有索引的基类,提供了一些通用的接口,比如添加,查询;量化器类根据quantizer成员负责向量的编码与存储。本文主要介绍IVFIndex这个类,但是在实际使用过程中都是通过IVFIndex的子类来实例化索引的,不同的子类指定不同的quantizer,code size以及invlists类型等参数。IndexIVFFlat是最朴实的子类,选用的quantizer是最简单的Flat索引,也就是暴力索引,实际invert list里存储的是向量本身,所以code size就是向量本身的大小。本文中涉及到这些地方,如无特殊指定,均指IVFFlat下选定的参数。

struct IndexIVF: Index, Level1Quantizer {
    /// Access to the actual data
    InvertedLists *invlists; //由各中心的倒排list组成的数组
    size_t code_size;              ///< code size per vector in bytes
    size_t nprobe;            ///< number of probes at query time

    /** Parallel mode determines how queries are parallelized with OpenMP
     *
     * 0 (default): parallelize over queries
     * 1: parallelize over inverted lists
     * 2: parallelize over both
     *
     * PARALLEL_MODE_NO_HEAP_INIT: binary or with the previous to
     * prevent the heap to be initialized and finalized
     */
    int parallel_mode;
}

以上参数在上面的关系图中均有解释。

2. 训练

训练的作用主要是事先找到各个聚类中心。主要分两步,  训练量化器和残差训练

void IndexIVF::train (idx_t n, const float *x)
{
    train_q1 (n, x, verbose, metric_type); //训练量化器
    train_residual (n, x); //训练残差
    is_trained = true;
}

2.1 训练量化器

train_q1, 训练量化器。前文已经介绍过,量化器其实也是一个索引,用来找寻向量最近的聚类中心的。那么量化器的训练,在IVF索引中其实就是对量化器采用kmeans聚类,具体的聚类实现参见另一篇文章

        Clustering clus (d, nlist, cp);
        quantizer->reset();
        ...
        clus.train (n, x, *quantizer); // kmeans聚类
        quantizer->is_trained = true;

2.2 训练残差

 train_residual,  训练残差,IVFIndex不同的子类会有不同的实现,在IVFIndex和IndexIVFFlat中啥也没干。

void IndexIVF::train_residual(idx_t /*n*/, const float* /*x*/) {
  if (verbose)
    printf("IndexIVF: no residual training\n");
  // does nothing by default
}

 所以说,IVF索引的训练其实就是对量化器的一次聚类,获取各聚类中心。

### Faiss 中的不同 IVF 类型及实现方式 Faiss 是一种高效的相似度搜索库,广泛应用于大规模向量检索场景。以下是关于 Faiss 的不同 IVF(Inverted File Indexing)类型的详细介绍。 #### 1. **基本概念** IVF 方法的核心思想是通过聚类算法将数据划分为多个簇(cluster),并为每个簇分配一个唯一的 ID。查询时,仅需在与目标最近的几个簇中查找即可减少计算复杂度[^1]。 ```python import faiss dim, measure = 64, faiss.METRIC_L2 index = faiss.IndexFlatL2(dim) print(index.is_trained) # 判断索引是否已经训练完成 ``` --- #### 2. **常见 IVF 类型** ##### (1) **IVFFlat** `IVFFlat` 是最基本的倒排索引结构之一。它通过对输入向量进行 k-means 聚类来划分簇,并存储原始向量以便精确距离计算。 - 实现方式:先对数据集执行一次全局 k-means 计算得到质心集合;之后,在查询阶段找到离查询点最近的若干个质心对应的簇,并逐一比较这些簇中的向量。 - 参数说明: - `nlist`: 表示总的簇数量。 - `metric`: 使用的距离度量标准,默认为 L2 距离。 ```python quantizer = faiss.IndexFlatL2(dim) index_ivf_flat = faiss.IndexIVFFlat(quantizer, dim, nlist=100, metric=faiss.METRIC_L2) index_ivf_flat.train(xb) # 需要显式调用 train 函数 index_ivf_flat.add(xb) ``` --- ##### (2) **IVFPQ** `IVFPQ` 结合了乘积量化技术,进一步压缩了向量表示的空间需求。其主要特点是将高维空间切分成更小的部分,每部分独立编码后再组合成最终结果。 - 特点:相比传统方法显著降低了内存占用率,但引入了一定程度上的精度损失。 - 参数解释: - `M`: 向量被分割的数量。 - `nbits`: 每一段使用的比特数决定码本大小 \(2^{nbits}\)。 ```python param_pq = f'PQ{m}x{nbits}' index_ivfpq = faiss.index_factory(dim, param_pq, measure) assert not index_ivfpq.is_trained index_ivfpq.train(xb) index_ivfpq.add(xb) ``` --- ##### (3) **IVFSQ** 平方根量化 (`Scalar Quantization`) 提供了一个简单而有效的替代方案用于降低存储成本。尽管它的性能可能不如 PQ 复杂模型那么优越,但在某些特定条件下仍然非常实用。 - 主要优势在于易于理解和部署以及较低的时间开销。 ```python index_sq8 = faiss.IndexIVFScalarQuantizer( quantizer, dim, nlist=100, sq_type=faiss.ScalarQuantizer.QT_8bit_uniform ) index_sq8.train(xb) index_sq8.add(xb) ``` --- #### 3. **优劣对比分析** | 索引类型 | 存储效率 | 查询速度 | 数据准确性 | |----------|-----------|------------|--------------| | IVFFlat | 较低 | 快 | 高 | | IVFPQ | 极高 | 很快 | 中等偏下 | | IVFSQ | 高 | 快 | 中等 | 上述表格总结了几种主流 IVF 变体之间的权衡关系[^2]。 --- #### 4. **实际应用场景建议** 对于大多数常规任务而言,“IVFxPQy”的配置通常是首选解决方案因为它综合表现良好既兼顾了资源利用率又保持一定水平的服务质量。 ---
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jevenabc

请我喝杯咖啡吧~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值