首页/AI/AI 应用速查/IVF / PQ 量化索引:省内存的大规模方案

IVF / PQ 量化索引:省内存的大规模方案

IVF 用聚类把向量分桶、查询只扫部分桶;PQ 把向量切片量化压缩,能把内存降一个数量级。适合千万级以上、内存敏感的离线或大规模场景,需接受少量精度损失。

AI 应用速查AI更新于 2026-10-13

IVF 与 PQ 是什么

两者是互补的向量压缩手段:IVF 先把向量聚成若干桶,查询时只扫距离最近的几个桶,用少量遍历换速度;PQ 把向量切成若干段、每段各自量化成编码,用少量精度换内存。叠加使用可在千万级规模把常驻内存压下一个数量级,代价是量化误差导致召回变差,工程上通常再配一层重排把精度补回来。

基本信息

IVF 结构nlist 个聚类中心,查询只扫其中 nprobe 个桶
PQ 结构维度切段后每段独立聚类成码本,向量存为编码
参数重心nlist 定分桶粒度,nprobe 定速度与召回的平衡点
精度代价量化压缩有信息损失,需用原始向量重排兜底
使用顺序必须先 train 训练聚类与码本,再 add 入库
实现参考FAISS 的 index_factory 可以一行声明组合索引

典型使用场景

  • 千万级知识库常驻内存吃紧,需要把向量占用压到单机可承载
  • 成本敏感的多租户共享向量集群,内存是主要计费项
  • 离线批量检索任务:允许一次粗排加一次重排,追求吞吐而非单次精度
  • 边缘或私有化部署环境,机器规格受限但数据量不小
  • 作为两级检索的粗排层,先扩候选再用原始向量或重排模型精挑

FAISS 组合索引示例

FAISS 组合索引示例
import faiss
dim = 768
index = faiss.index_factory(dim, "IVF4096,PQ96")  # 768 能被 96 整除,PQ 段数需整除维度
res = faiss.StandardGpuResources()          # 需装 GPU 版 FAISS 才能用
index = faiss.index_cpu_to_gpu(res, 0, index)  # 把索引放显存,省主机内存
index.train(xb)      # 先训练聚类中心与量化码本,训练集要显著大于桶数
index.add(xb)        # 训练完成后才能入库,未训练直接 add 会报错
index.nprobe = 32    # 查询扫描桶数,越大越准也越慢,需用评测集扫
D, I = index.search(xq, 10)  # D 是距离、I 是索引编号,供后续重排
ids = [meta[i] for i in I[0]]  # 用编号回查原始分块与元数据

参数与取舍

参数含义调大调小的影响
nlist聚类桶数量桶多则每桶样本少,召回上升但训练成本高
nprobe查询扫描的桶数调大召回上升、延迟线性增长
PQ 段数向量被切成几段量化段数越多压缩比越低、精度越高,须整除维度
训练样本量用于 train 的向量数过少则聚类中心不可靠,召回明显下降
是否重排对粗排候选再精排开启可补回量化损失,代价是一次额外计算
量化索引基本都要配重排:先粗排扩大候选规模(例如取前 100 条),再用原始向量或重排模型精排,否则压缩带来的漏检会直接体现在答案缺失上。
nprobe 不要凭经验拍值:它和 nlist、数据分布强相关,正确做法是固定数据集扫几组取值,画出召回率与延迟曲线后选取折中。

易错点

  • 没训练就直接入库:FAISS 会直接报错,或返回不可用的搜索结果
  • PQ 段数不能整除向量维度:建索引阶段即失败,换模型或换维度时必须重算
  • nprobe 设得过小:召回率骤降,表现为答案库里有资料却检索不到
  • 训练样本量不足:聚类中心质量差,即使 nprobe 调大也补不回来
  • 只上量化不做重排:精度损失直接暴露给用户,反而比用更小的全精度索引更糟

数据来源与参考

  • FAISS 官方 wiki(Index factory);Jégou et al., Product Quantization 论文

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌