Faiss 1.15.0:RaBitQ 向量检索量化,1024 维向量只占 128 字节

Faiss 1.15.0:RaBitQ 向量检索量化,1024 维向量只占 128 字节

【免费下载链接】faiss A library for efficient similarity search and clustering of dense vectors. 【免费下载链接】faiss 项目地址: https://gitcode.com/GitHub_Trending/fa/faiss

Faiss 1.15.0 是 Meta 开源的高效稠密向量相似性搜索与聚类库。这一版把 RaBitQ 检索路径打磨成生产可用状态:每个维度只用 1 个比特存码,1024 维向量每条约 128 字节,FastScan 查询路径 QPS 再提 80%(出处见 CHANGELOG.md 中 "Optimize RaBitQ fastscan query setup + 80% qps (#5396)")。

这个版本到底改了什么

RaBitQ 从"新特性"变成了"快特性",这一版的改动集中在检索提速、硬件覆盖和加载方式三个层面,每条都对应你关心的业务指标。

  • RaBitQ FastScan 全链路提速:查询建表优化使 QPS 提升 80%(#5396),并融合了 AND-dot 与 popcount 扫描(#5412)、AVX512 查表量化(#5397)、SIMD 位平面运算(#5392)。直接影响:同等硬件下查询吞吐量。
  • 可平滑迁移的转换构造器:实现了 IVFRaBitQ → FastScan 变体的转换构造(#5422)。直接影响:旧 IVFRaBitQ 索引无需重建即可切到更快的扫描路径。
  • RISC-V 支持:新增 RVV 向量距离内核(#5354)与 RaBitQ 内核(#5369)。直接影响:非 x86 平台的可用性。
  • 内存映射 I/O:Flat 与静态 Vamana(SVS)索引支持 mmap(#5271),配合 faiss/impl/mapped_io.cpp。直接影响:索引加载时间与大内存机器上的可服务规模。
  • HNSW 热点路径:visited 表跨查询复用不再逐次重分配(#5448),哈希表阈值从 50 万提升到 1000 万(#5446)。直接影响:HNSW 高并发下延迟方差。

一句话总结:这一版让 RaBitQ 从"能用的新索引"变成"值得上线的快索引"。

核心技术,一次讲透

✨ 关键点:RaBitQ 的本质是"随机旋转 + 符号位编码",把浮点距离比较变成了比特运算。

它是什么。 编码时分三步:先用一个随机旋转矩阵把向量坐标打散(让能量均匀分布在所有维度上);再减去全局中心点;然后逐维判断"旋转后坐标的正负",每维记 1 个比特,d 维向量的主码就是 d 个比特 = d/8 字节(faiss/impl/RaBitQuantizer.h)。生活化类比:像把一团乱麻先抖匀(随机旋转),再用"每根线头朝上还是朝下"记一份清单(符号位)——清单很小,但抖匀过之后它能可靠地反推出毛线团的大致形状。

它不是什么。 它不是无损压缩,reconstruct 出来的是近似向量而非原值;也不是降维——维度数不变,变的是每维的表示精度(1 比特)。

为什么更好。 搜索端把查询同样量化成少量比特(默认 qb=4,见 faiss/IndexRaBitQ.h 中的 RaBitQSearchParameters),距离计算就退化成"按位与 + 数 1 的个数"(AND + popcount),这类运算在 SIMD 里一条 512 位指令就能处理 512 个维度,而传统 PQ 需要查码本表加浮点累加。benchs/bench_rabitq.py 开头注释解释了这一点:d=1024 时每比特平面只需 2 轮 512 位指令。

一句话总结:旧做法是"子块查码本",新做法是"整体符号位 + 比特运算",编码更便宜、搜索更快,代价是精度略低于 PQ。

用数据验证

基准脚本 benchs/bench_rabitq.py 在合成数据(10 万训练、20 万库、1000 查询)上横扫 d ∈ {256, 512, 768, 1024},对 RaBitQ、IVFRaBitQ 与 PQFastScan、HNSWFlat、SQ 做 recall/QPS/内存三维对比。表内为可直接核验的量化事实,跑分数字以你自己环境的输出为准:

方案每向量主码大小(d=1024)距离计算方式关键参数出处
全精度 Flat4 KB(1024 × 4B fp32)浮点 L2
RaBitQ(nb_bits=1,默认)128 B(1 bit/维)+ 少量统计量比特 AND + popcount,SIMDfaiss/IndexRaBitQ.h
IVFRaBitQ + FastScan128 B/条,按簇组织同左 + nprobe 粗筛faiss/IndexIVFRaBitQ.h

如何自己复现

# 在仓库根目录运行官方 RaBitQ 基准,输出 recall/QPS/内存
python benchs/bench_rabitq.py
# 正确性对照(RaBitQ 估计距离 vs 暴力精确距离):
python -m pytest tests/test_rabitq.py

📊 数据来源:上表代码尺寸按 nb_bits=1 直接计算(d 比特 = d/8 字节);吞吐对比由脚本运行时打印,本仓库不内置固定跑分数字,引用第三方数字请以自测为准。

一句话总结:128 字节 vs 4 KB 是 32 倍码长压缩,QPS 数字跑一遍 bench_rabitq.py 即得,无需引用二手数据。

三步跑通最小闭环

环境准备

装预编译 wheel 最快,源码编译用于吃满 AVX512/新硬件:

pip install faiss-cpu
# 或源码编译(AVX512 优化在 faiss/utils/simd_impl/ 下按 FAISS_OPT_LEVEL 选择)
git clone https://gitcode.com/GitHub_Trending/fa/faiss
cd faiss
cmake -B build -DFAISS_OPT_LEVEL=avx512
cmake --build build -j$(nproc)

最小可运行示例

下面用工厂字符串一行创建"IVF 粗量化 + RaBitQ 编码"索引,训练后检索:

import faiss, numpy as np
d, n, nlist = 1024, 100_000, 1000
x = np.random.randn(n, d).astype("float32")
index = faiss.index_factory(d, "IVF1024,RaBitQ")  # 128B/条码
index.train(x)
index.add(x)
# 检索(k=10)
faiss.vector_to_array(index.search(np.random.randn(4, d).astype("float32"), 10))
# 注意:先 train 再 add;查询向量同样走 RaBitQ 量化(qb=4)

生产配置模板

生产建议显式控制 nprobe 与查询比特数 qb,二者共同决定延迟/召回曲线:

import faiss
index = faiss.index_factory(1024, "IVF4096,RaBitQ")  # 4096 簇,1bit/维
index.train(xtrain); index.add(xdb)
p = faiss.IVFRaBitQSearchParameters()  # bench_rabitq.py 同款参数对象
p.qb = 4        # 查询量化比特数:4=默认速度/精度折中
# 检索时: faiss.search_with_parameters(index, xq, k, p)
# p.nprobe 越大召回越高、延迟越高,按 SLO 调

💡 提示:训练点数要有下限——benchs/bench_rabitq.py 注释给出的经验值是 39 × nlist,即 nlist=1000 时至少约 3.9 万条。

一句话总结:工厂字符串 + IVFRaBitQSearchParameters 两个对象,就是 RaBitQ 的生产配置面。

按业务场景选方案

按"数据规模 × 硬件约束"对号入座,不用背参数:

场景数据规模硬件约束推荐方案
精确基线 / 小规模< 100 万任意IndexFlatL2(fp32,召回=1.0)
通用实时检索100 万 ~ 亿CPU(AVX2/AVX512)IVFnlist,RaBitQ,nlist 取千级,调 nprobe
内存受限的大库千万 ~ 亿内存紧张RaBitQ 码(128B/条@1024 维)+ Flat 索引 mmap(#5271)
极高召回、低延迟百万级有 GPUHNSW / CAGRA(见 tutorial/cpp/6-HNSW.cpp
精度要求 > 99%百万级内存充足IVFPQ 或 IVFFlat 全精度码
RISC-V / 非 x86 平台任意RVV 支持RaBitQ(RVV 内核 #5369)

这些坑,先知道再动手

  1. 症状:FastScan 相关路径报错。原因:码按 8 维一组打包,维度必须整除 8。解法:确认 d % 8 == 0,不满足就退回非 FastScan 变体或补齐维度。
  2. 症状:设 qb=0 后速度断崖。原因:qb=0 意味着查询不做量化、直接走 fp32 距离计算机,SIMD 查表路径失效(faiss/IndexRaBitQ.h 第 28 行注释明确写了 FastScan 不支持 qb=0)。解法:追求速度保持默认 qb=4,只对"必须精确复核"的少量查询临时用 fp32。
  3. 症状:召回率不达预期。原因:nprobe 太小,粗量化漏检邻近簇。解法:用 benchs/bench_rabitq.py 的 nprobe 4/16/32 扫描法(脚本内 handle_ivf_index 就这么做)画召回-延迟曲线,按 SLO 选点。
  4. 症状reconstruct 结果与原向量差距可见。原因:RaBitQ 是有损距离估计器,重建靠 1 比特符号 + 范数统计量反推,不是原始向量。解法:需要原值时把原始向量单独落盘,索引只用于定位 ID。
  5. 症状:升级后 QPS 与预期不符。原因:SIMD 动态分发依赖 CPU 能力,AVX512 优化在 faiss/utils/simd_impl/ 下,老 CPU 会自动回退到更窄的指令集。解法:升级前先跑 tests/test_simd_levels.cpp(配套 tests/test_simd_dispatch.py)确认当前生效的 SIMD 档位。

一句话总结:先确认 d 整除 8 与 qb 默认值,再谈调优。


下一步:① 用 IVF1024,RaBitQ 替换你现在的 IVFPQ 建一条对照索引;② 跑 python benchs/bench_rabitq.py 拿到本机 QPS/召回数字;③ 用 tests/test_rabitq.py 核对估计距离与精确距离的偏差。 社区资源:README.mdtutorial/benchs/

【免费下载链接】faiss A library for efficient similarity search and clustering of dense vectors. 【免费下载链接】faiss 项目地址: https://gitcode.com/GitHub_Trending/fa/faiss

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

抵扣说明:

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

余额充值