RyanCodrai/turbovec
摘要
turbovec 是一个基于 Rust 的向量索引,带有 Python 绑定,实现了谷歌的 TurboQuant 算法,提供高效的向量搜索,支持在线摄入,性能优于 FAISS,并具备过滤搜索能力。
查看缓存全文
缓存时间: 2026/06/08 03:31
RyanCodrai/turbovec 来源:https://github.com/RyanCodrai/turbovec — 一个1000万文档的语料库以float32格式占用31 GB内存。turbovec将其压缩到4 GB,并且搜索速度比FAISS更快。 turbovec 是一个带有 Python 绑定的 Rust 向量索引,基于 Google Research 的 TurboQuant(https://arxiv.org/abs/2504.19874)算法构建——这是一种数据无关的量化器,其畸变达到香农下界,无需码本训练,也无需独立的训练阶段。 - 在线导入。 添加向量,它们即被索引——没有训练步骤,没有参数调优,语料库增长时无需重建。 - 比 FAISS 更快。 手写的 NEON(ARM)和 AVX-512BW(x86)内核在 ARM 上比 FAISS IndexPQFastScan 快 12–20%,在 x86 上与之持平或更快。 - 搜索时过滤。 向 search() 传递一个 id 白名单(或一个槽位位掩码),内核会直接将其纳入考虑。你始终从允许的集合中获得最多 k 个结果——不会过度获取,也不会因选择性过滤而降低召回率。 - 完全本地化。 没有托管服务,没有数据离开你的机器或 VPC。与任何开源嵌入模型配合使用,即可构建完全气隙的 RAG 堆栈。 在构建对隐私、内存或延迟有要求的 RAG 应用?你来对地方了。 ## Python bash pip install turbovec python from turbovec import TurboQuantIndex index = TurboQuantIndex(dim=1536, bit_width=4) index.add(vectors) index.add(more_vectors) scores, indices = index.search(query, k=10) index.write("my_index.tq") loaded = TurboQuantIndex.load("my_index.tq") 需要能在删除后仍然保持稳定的 id?使用 IdMapIndex: python import numpy as np from turbovec import IdMapIndex index = IdMapIndex(dim=1536, bit_width=4) index.add_with_ids(vectors, np.array([1001, 1002, 1003], dtype=np.uint64)) scores, ids = index.search(query, k=10) # ids 是你传入的 uint64 外部 id index.remove(1002) # 按 id 进行 O(1) 删除 index.write("my_index.tvim") loaded = IdMapIndex.load("my_index.tvim") ### 混合检索(过滤搜索) 将结果限制为由其他系统(SQL、BM25、ACL、时间窗口等)产生的候选集: python import numpy as np from turbovec import IdMapIndex idx = IdMapIndex(dim=1536, bit_width=4) idx.add_with_ids(vectors, ids) # 阶段 1:外部系统将范围缩小到候选 id。 allowed = np.array(db.execute("SELECT id FROM docs WHERE tenant=?", (t,)).fetchall(), dtype=np.uint64) # 阶段 2:在候选集内进行密集重排序。 scores, ids = idx.search(query, k=10, allowlist=allowed) 过滤操作发生在 SIMD 内核内部,以 32 向量块为粒度:没有允许槽位的块在执行任何 LUT 查找或评分工作之前被短路跳过,而在已评分块中不允许的个别槽位在堆插入时被丢弃。因此,选择性的白名单(仅允许索引的一小部分)可以避免大部分 SIMD 开销,而不是先付出代价再丢弃结果。 输出长度为 min(k, len(allowed)) —— 当白名单小于 k 时,你会得到恰好 len(allowed) 个结果,而不是填充的降级结果。 完整参考请参见 docs/api.md。 ### 框架集成 可直接替换各框架内置的参考向量/文档存储。相同的公共接口,相同的持久化语义,相同的检索器和管道连线——只需交换导入语句,保持管道不变。 - LangChain — pip install turbovec[langchain] · 替换 langchain_core.vectorstores.InMemoryVectorStore - LlamaIndex — pip install turbovec[llama-index] · 替换 llama_index.core.vector_stores.SimpleVectorStore - Haystack — pip install turbovec[haystack] · 替换 haystack.document_stores.in_memory.InMemoryDocumentStore - Agno — pip install turbovec[agno] · 替换 agno.vectordb.lancedb.LanceDb ## Rust bash cargo add turbovec rust use turbovec::TurboQuantIndex; let mut index = TurboQuantIndex::new(1536, 4); index.add(&vectors); let results = index.search(&queries, 10); index.write("index.tv").unwrap(); let loaded = TurboQuantIndex::load("index.tv").unwrap(); 对于能稳定存在并支持删除的外部 id: rust use turbovec::IdMapIndex; let mut index = IdMapIndex::new(1536, 4); index.add_with_ids(&vectors, &[1001, 1002, 1003]); let (scores, ids) = index.search(&queries, 10); index.remove(1002); index.write("index.tvim").unwrap(); let loaded = IdMapIndex::load("index.tvim").unwrap(); ## 召回率 TurboQuant vs FAISS IndexPQ(LUT256,nbits=8)——论文第4.4节的基准。100K 向量,k=64。FAISS PQ 子量化器数量与 TurboQuant 的比特率匹配(2-bit 时 m=d/4,4-bit 时 m=d/2)。 召回率 GloVe d=200 召回率 d=1536 召回率 d=3072 在 OpenAI d=1536 和 d=3072 上,TurboQuant 在 2-bit 和 4-bit 下 R@1 比 FAISS 高出 0.4–3.4 个百分点,两者在 k=4 时均收敛到 1.0。GloVe d=200 是更难的情况——在低维度下,渐近 Beta 假设较为宽松。TurboQuant 在 4-bit 的 R@1 上比 FAISS 高 0.3 个百分点,在 2-bit 的 R@1 上落后 1.2 个百分点,两者在 k≈16 时趋近于 FAISS。 关于基线的说明。 我们与 FAISS IndexPQ(LUT256,nbits=8,float32 LUT)进行比较,因为它是大多数用户会使用的默认生产级 PQ。这比 TurboQuant 论文(https://arxiv.org/abs/2504.19874)中使用的自定义 u8-LUT PQ 基线更强——FAISS 在评分时使用更高精度的 LUT,并使用 k-means++ 进行码本训练。我们在 OpenAI d=1536 / d=3072 上重现了论文中的 TurboQuant 数字,并在低维嵌入上达到与其他社区参考实现相似的数值(参见 turboquant-py(https://pypi.org/project/turboquant-py/)在 d=384 上的结果)。GloVe 上可见的差距反映了 FAISS 是一个强大的基线,而非 TurboQuant 实现问题。 完整结果:d=1536 2-bit,d=1536 4-bit,d=3072 2-bit,d=3072 4-bit,GloVe 2-bit,GloVe 4-bit。 ## 压缩 压缩 ## 搜索速度 所有基准测试:100K 向量,1K 查询,k=64,5 次运行的中位数。 ### ARM(Apple M3 Max) ARM 速度——单线程 ARM 速度——多线程 在 ARM 上,TurboQuant 在所有配置下都比 FAISS FastScan 快 12–20%。 ### x86(Intel Xeon Platinum 8481C / Sapphire Rapids,8 vCPU) x86 速度——单线程 x86 速度——多线程 在 x86 上,TurboQuant 在所有 4-bit 配置下领先 1–6%,在 2-bit 单线程上与 FAISS 相差约 1%。2-bit 多线程(d=1536 和 d=3072)是唯一稍微落后于 FAISS 的配置(2–4%),此时内部累加循环太短,展开的摊还效果无法与 FAISS 的 AVX-512 VBMI 路径匹配。 ## 工作原理 每个向量都是高维超球面上的一个方向。TurboQuant 通过一个简单的洞察来压缩这些方向:应用随机旋转后,每个坐标都遵循已知分布——无论输入数据是什么。 1. 归一化。 从每个向量中剥离长度(范数)并将其存储为一个浮点数。现在每个向量都是超球面上的单位方向。 2. 随机旋转。 将所有向量乘以同一个随机正交矩阵。旋转后,每个坐标独立地遵循一个 Beta 分布,该分布在高维下收敛于高斯分布 N(0, 1/d)。这对任何输入数据都成立——旋转使坐标分布变得可预测。 3. 逐坐标校准(TQ+)。 步骤2中的 Beta 分布是渐近的——在有限维下,各个坐标会偏离典型形状(尤其是低位和词向量风格的嵌入)。TQ+ 在首次添加时为每个坐标拟合两个标量——一个移位和一个缩放——将每个坐标的经验 5/95% 分位数映射到规范的 Beta 边际分布。然后 Lloyd-Max 码本针对其设计时所针对的 目标 分布进行量化。校准在首次添加后冻结,并在后续添加中重用——无需重新训练、无需重建、无需独立的训练阶段。召回率提升:在偏移最严重的单元上(例如 2-bit 的 GloVe)@1 时最多提升 +1.4 个百分点。 4. Lloyd-Max 标量量化。 由于分布已知,我们可以预先计算每个坐标的最优分桶方式。对于 2-bit,有 4 个桶;对于 4-bit,有 16 个桶。Lloyd-Max 算法(https://en.wikipedia.org/wiki/Lloyd%27s_algorithm)找到能使均方误差最小的桶边界和质心。这些计算仅基于数学,而非数据。 5. 位打包。 现在每个坐标都是一个很小的整数(2-bit 为 0-3,4-bit 为 0-15)。将这些紧凑地打包进字节中。一个 1536 维的向量从 6,144 字节(FP32)压缩到 384 字节(2-bit)。压缩比达到 16 倍。 6. 长度重归一化评分。 标量量化系统地低估了内积——重建的单位方向比原始方向稍短。我们在编码时为每个向量计算一个标量——旋转后的单位向量与其自身质心重建的内积——并将 ||v|| / ⟨u, x̂⟩ 与每个压缩向量一起存储。搜索内核在堆插入之前将每个候选的分数乘以这个标量,从而将内积估计量从有偏向下修正为无偏,且无需额外的搜索时间成本和额外存储。召回率提升在低比特宽度时最为明显,此时量化收缩最大。编码代价:每个向量额外计算一个 d 维点积以得到 ⟨u, x̂⟩。对于 100 万向量、d=1536 的情况,这相当于亚秒级的额外编码时间——在导入时一次性支付,而非在查询时支付。 搜索。 不是解压每个数据库向量,而是将查询旋转到相同域中,并直接根据码本值进行评分。评分内核使用 SIMD 内联函数(ARM 上的 NEON,现代 x86 上的 AVX-512BW,并带有 AVX2 降级方案),结合半字节分割查找表以实现最大吞吐量。Lloyd-Max 码本实现的畸变在信息论下界(香农畸变率限)的 2.7 倍以内;长度重归一化步骤消除了 Lloyd-Max 码本在内积估计器本身引入的残余偏差。 ## 构建 ### Python(通过 maturin) bash pip install maturin cd turbovec-python maturin build --release pip install target/wheels/*.whl ### Rust bash cargo build --release 所有 x86_64 构建通过 .cargo/config.toml 以 x86-64-v3(AVX2 基线,Haswell 2013+)为目标。任何能运行 AVX2 降级内核的 CPU 都能运行整个 crate——AVX-512 内核在运行时通过 is_x86_feature_detected! 进行检测,仅在支持的硬件上启用。 ## 运行基准测试 下载数据集: bash python3 benchmarks/download_data.py all # 所有数据集 python3 benchmarks/download_data.py glove # GloVe d=200 python3 benchmarks/download_data.py openai-1536 # OpenAI DBpedia d=1536 python3 benchmarks/download_data.py openai-3072 # OpenAI DBpedia d=3072 每个基准测试都是 benchmarks/suite/ 中的一个独立脚本。单独运行任意一个: bash python3 benchmarks/suite/speed_d1536_2bit_arm_mt.py python3 benchmarks/suite/recall_d1536_2bit.py python3 benchmarks/suite/compression.py 按类别运行所有基准测试: bash for f in benchmarks/suite/speed_*arm*.py; do python3 "$f"; done # 所有 ARM 速度 for f in benchmarks/suite/speed_*x86*.py; do python3 "$f"; done # 所有 x86 速度 for f in benchmarks/suite/recall_*.py; do python3 "$f"; done # 所有召回率 python3 benchmarks/suite/compression.py # 压缩 结果以 JSON 格式保存到 benchmarks/results/。重新生成图表: bash python3 benchmarks/create_diagrams.py ## 参考文献 - TurboQuant: Online Vector Quantization with Near-optimal Distortion Rate(https://arxiv.org/abs/2504.19874)(ICLR 2026)——本实现所基于的论文 - RaBitQ: Quantizing High-Dimensional Vectors with a Theoretical Error Bound for Approximate Nearest Neighbor Search(https://arxiv.org/abs/2405.12497)(SIGMOD 2024)——步骤5中采用的逐向量长度重归一化修正的来源 - FAISS Fast accumulation of PQ and AQ codes(https://github.com/facebookresearch/faiss/wiki/Fast-accumulation-of-PQ-and-AQ-codes-(FastScan))——turbovec 的 x86 SIMD 内核改编了 FastScan 的打包布局、半字节 LUT 评分和 u16 累加器策略
相似文章
@hasantoxr:向量数据库不再是云产品。它们正在变成 pip install。一个名为 turbovec 的新开源项目……
一个名为 turbovec 的开源项目在 GitHub 上获得了 1 万星标。它是一个基于 Rust、带有 Python 绑定的向量索引,使用谷歌研究的 TurboQuant 算法将嵌入压缩到接近理论香农极限,使得完全本地的 RAG(检索增强生成)成为可能——1000 万文档仅需 4 GB RAM,且搜索速度快于 FAISS。
@techwith_ram:一个1000万文档的语料库以float32格式占用31GB内存。大多数团队遇到这一瓶颈后会转向托管向量数据库。每月400美元……
turbovec 是一个开源的 Rust 向量索引,使用 Google Research 的 TurboQuant 算法,实现了16倍压缩,搜索速度比 FAISS 更快,并且集成了 LangChain、LlamaIndex 和 Haystack 等 RAG 框架。
@vintcessun: 1000万向量31GB压到4GB,搜索还比FAISS快——这事有点离谱,但turbovec真做到了。核心是Google TurboQuant的数据无关量化,无需训练、不用调参,加向量即索引。手写NEON/AVX-512核实打实快12-20…
turbovec 基于 Google TurboQuant 算法,将 1000 万向量从 31GB 压缩到 4GB,搜索速度比 FAISS 快 12-20%,支持过滤搜索,提供 Rust 实现和 Python 包。
@dr_cintas: 谷歌新算法将31GB内存压缩至4GB TurboVec是一款新的开源工具,用于存储数据……
谷歌的TurboVec是一款新的开源工具,能将AI搜索数据的内存占用从31GB降至4GB。它基于TurboQuant,实现比FAISS更快的搜索,可集成LangChain和LlamaIndex,并完全离线运行。
TurboQuant+MTP在ROCm(Llama CPP)上的实现
一位开发者成功在llama.cpp中让TurboQuant TBQ4 KV缓存和多Token预测在AMD ROCm上针对RDNA3 GPU运行,实现在24GB显存上支持64k上下文,并具有有竞争力的token速率。