ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

turbovec 实战指南:基于 Google TurboQuant 算法的 Rust 向量索引与 Python 绑定

turbovec 实战指南:基于 Google TurboQuant 算法的 Rust 向量索引与 Python 绑定 turbovec 实战指南基于 Google TurboQuant 算法的 Rust 向量索引与 Python 绑定【免费下载链接】turbovecA vector index built on TurboQuant, written in Rust with Python bindings项目地址: https://gitcode.com/GitHub_Trending/tu/turbovecturbovec 是一个以 Rust 编写、提供 Python 绑定的向量索引核心是 Google Research 的 TurboQuant 数据无关量化算法——无需训练、无需重建即可在线摄入向量并以手写 SIMD 内核完成高速近邻搜索。本文以仓库 README.md 为主线结合 turbovec/src 的源码实现与 docs/api.md 的 API 参考系统讲解其算法原理、Python/Rust 双层 API、混合检索过滤、增量持久化与文件格式并给出可复现的构建与基准测试方法帮助你基于 turbovec 搭建隐私优先、内存紧凑、延迟敏感的 RAG 检索栈。项目定位为隐私、内存、延迟而生的向量索引turbovec 面向对隐私、内存占用或查询延迟敏感的场景如本地 RAG其核心设计主张体现在 README 的五条特性中在线摄入Online ingest向量加入即完成索引没有独立训练步骤、没有参数调优、语料增长也无需重建。快速 SIMD 搜索手写内核——ARM 上的 NEON SDOT/SMMLA、x86 上的 AVX-512 VNNI 与vpermb并带有 AVX2 与标量回退——在实测配置中全面领先 FAISS IndexPQFastScan4-bit 平均约 3.4×、2-bit 平均约 23%详见下文「性能」小节。增量保存Incremental savessync(path)只持久化自上次同步以来变化的部分每次调用一次 fsync任何字节处崩溃都安全删除或小规模追加仅需毫秒级无论索引多大。write/load则保留用于全量快照。搜索时过滤Filter at search time向search()传入 id 白名单或槽位掩码内核直接在 SIMD 层遵循该约束始终从允许集合中返回至多k个结果——不超额抓取选择性过滤时无召回损失。纯本地Pure local无托管服务数据不离开你的机器或 VPC可搭配任意开源 embedding 模型构建完全隔离网络的 RAG 栈。从仓库结构看工程被划分为三个层次核心 Rust crateturbovec、Python 绑定 crateturbovec-python以及一整套基准测试与图表生成脚本benchmarks。TurboQuant 算法原理六步压缩管线TurboQuant 的核心洞察是每个向量都是高维超球面上的一个方向。经过随机旋转后每个坐标都服从一个已知分布与输入数据无关——于是可以绕开从数据学习码本的训练环节。turbovec 的编码管线在 turbovec/src/encode.rs 中实现可拆解为 README 描述的六个步骤1. 归一化Normalize。从每个向量中剥离长度norm以单个 float 存储得到超球面上的单位方向向量。2. 随机旋转Random rotation。所有向量乘以同一个随机正交矩阵。旋转后每个坐标独立地服从一个 Beta 分布在高维下收敛到高斯 N(0, 1/d)。这一结论对任意输入数据成立——旋转使坐标分布可预测。turbovec 的具体实现是全局置换的分块 Walsh-Hadamard 变换block-Hadamard transform见 turbovec/src/rotation.rs。与旧版 QR-of-Gaussian 旋转相比该变换逐比特确定deterministic bit-for-bit无矩阵、无 GEMM只有符号翻转、块内 Hadamard 蝴蝶变换与整数置换随机性来自固定种子的 ChaCha8 字节流。这保证编码字节在不同平台、不同 CPU 架构、不同线程数下完全一致即 v5 格式的冻结线格式不变量。旋转轮数K 2且置换先行于 Hadamard使变换对坐标顺序不敏感——对 matryoshka/MRL、PCA 投影这类能量随坐标索引单调衰减的 embedding 尤为重要。3. 逐坐标校准Per-coordinate calibration, TQ。步骤 2 的 Beta 分布是渐近结论在有限维度下个别坐标会偏离标准形态低位宽与 word-vector 风格 embedding 尤其明显。TQ 为每个坐标拟合两个标量——一个 shift 和一个 scale——把该坐标的经验分位数映射到码本最外侧质心上。概率水平取自码本本身因此随位宽变化2-bit 约 0.9334-bit 约 0.996而不是固定值。随后 Lloyd-Max 码本针对其设计所对应的目标分布进行量化。校准是显式的在添加向量前调用一次index.calibrate(sample)取约 1024 行随机且有代表性的样本即可该规模的抽样与在全语料上拟合相当之后校准被提交并为每次 add 复用——无重训、无重建、无独立训练阶段。从不校准的索引就是纯 TurboQuantindex.calibration_state会报告uncalibrated或calibrated。在漂移最严重的单元上如 2-bit GloVe召回率增益最高可达 2.2pp 1。4. Lloyd-Max 标量量化。既然分布已知就可以预先计算每个坐标的最优分桶方式2-bit 为 4 个桶4-bit 为 16 个桶。Lloyd-Max 算法迭代求解使均方误差最小的分桶边界与质心——这些是一次性从数学推导得出而不是从数据学习。实现见 turbovec/src/codebook.rs对 Beta((d-1)/2, (d-1)/2) 分布做 200 次 Lloyd-Max 迭代每次迭代对 Beta 概率密度做2^bits次自适应 Simpson 积分epsabs1e-14求解耗时 25–100 ms结果以(bits, dim)为键在进程内全局记忆化memoized。5. 位打包Bit-pack。每个坐标现在是一个小整数2-bit 为 0–34-bit 为 0–15紧密打包进字节。一个 1536 维向量从 6144 字节FP32压缩到 384 字节2-bit——16 倍压缩。位平面到 SIMD 块布局的重打包实现在 turbovec/src/pack.rs。6. 长度重归一化评分Length-renormalized scoring。标量量化会系统性低估内积——重建的单位方向比原始方向略短。turbovec 在编码时为每个向量计算一个标量——旋转单位向量与其自身质心重建的内积⟨u, x̂⟩——并将||v|| / ⟨u, x̂⟩与压缩向量一同存储这一校正源自 RaBitQ。搜索内核在堆插入前将该标量乘到每个候选得分上以零搜索时间成本、零额外存储把内积估计从向下偏差转为无偏。偏差修正对低位宽收益最明显因为那里量化收缩最大。编码代价是每个向量额外一次d维点积在 d1536 的 100 万向量上仅为亚秒级附加编码时间——一次摄入期支付的一次性成本查询期不再发生。TQ 校准的源码级细节从 turbovec/src/encode.rs 的文档注释可以看到校准的精确数学形式u_calibrated[d] (u_rot[d] shift[d]) * scale_tq[d]量化作用于u_calibrated搜索路径在查询侧应用逆变换q_calib[d] q_rot[d] / scale_tq[d]并加每查询偏差校正-q_rot, shift。净效果是同一套内核、同一份码本但码本匹配更准。校准状态的语义值得注意见 turbovec/src/lib.rs 中CalibrationState枚举只有两种状态且只有显式calibrate调用能改变它add/remove/保存/加载都不会改变。一个已校准索引中每一行存储向量都编码在该校准下——包括校准调用之前添加的行因为那次调用会重新编码它们。README 与 docs/api.md 都强调样本质量是调用方的责任。calibrate会使用你给的每一行。约 1024 行在大多数语料上即可达到全语料拟合的 R10 半分之差2048 行在所有实测语料上均达标但样本必须是有代表性、随机的——排序或聚簇的前缀样本会拟合出偏移且过窄的分位数反而主动破坏召回率。传入全语料永远安全。校准时机有讲究先校准再大规模摄入优于后校准后校准是对已量化编码的第二次量化会损失数个点的召回率而一个严重偏差的早期校准无法通过重新拟合修复——过窄拟合已在编码时把坐标裁剪到外侧质心上后续任何参数都恢复不了被裁剪破坏的信息必须从源向量重建。Python 快速上手TurboQuantIndex 与 IdMapIndex安装pip install turbovec最简单的用法——位置索引from turbovec import TurboQuantIndex index TurboQuantIndex(dim1536, bit_width4) index.add(vectors) index.add(more_vectors) scores, indices index.search(query, k10) index.write(my_index.tv) loaded TurboQuantIndex.load(my_index.tv) index.sync(my_index.tv) # after more changes: durable incremental savevectors和query是形状为(n, dim)的二维float32数组——其他 dtype 会被拒绝而非静默转换所以必要时先用np.asarray(x, dtypenp.float32)转换。需要删除后仍稳定的外部 id 时使用IdMapIndeximport numpy as np from turbovec import IdMapIndex index IdMapIndex(dim1536, bit_width4) index.add_with_ids(vectors, np.array([1001, 1002, 1003], dtypenp.uint64)) scores, ids index.search(query, k10) # ids are your uint64 external ids index.remove(1002) # O(1) by id index.write(my_index.tvim) loaded IdMapIndex.load(my_index.tvim) index.sync(my_index.tvim) # durable incremental save, ids included构造参数与方法速查两种索引的构造参数一致详见 docs/api.md参数/方法说明TurboQuantIndex(dimNone, bit_width4)/IdMapIndex(dimNone, bit_width4)bit_width ∈ {2, 3, 4}dim必须是 8 的正倍数且≤ 16384MAX_DIM。dim可省略由第一次add/add_with_ids推断并锁定。add(vectors)/add_with_ids(vectors, ids)ids为uint64数组长度等于vectors.shape[0]。对非有限值NaN/Inf或\|value\| ≥ 1e16的坐标抛ValueErrorL2 范数 ≤1e-10的向量没有可表示方向以 scale 0 存储、对一切查询得 0 分这是文档化行为而非错误。search(queries, k, *, maskNone)/search(queries, k, *, allowlistNone)返回(scores, indices/ids)形状(nq, effective_k)effective_k min(k, n_allowed)。mask是长度len(idx)的 bool 数组allowlist是uint64id 数组自动去重。返回的排序对查询乘任意正常数不变内积分数本身随查询缩放。swap_remove(idx)O(1)。最后一个向量移入idx槽非 shift 语义删除后槽位索引不保序。prepare()可选。提前构建旋转矩阵、Lloyd-Max 质心与 SIMD 块布局让首次search不支付一次性开销。sync(path)/write(path, *, durableTrue)/load(path)write全量重写sync增量提交见下节load两种格式都能读。durableFalse跳过原子重命名前的 fsync更快但断电可能丢文件。to_bytes()/from_bytes(data)内存中的线格式序列化字节与write(path)写入文件的内容完全一致。len(idx)/idx.dim/idx.bit_width/idx.calibration_state内省。未提交 dim 的懒索引idx.dim为None。pickle/copy.copy/copy.deepcopy均受支持通过from_bytes(to_bytes())归约实现可跨multiprocessingspawn 边界。Python 绑定turbovec-python/src/lib.rs还做了一系列防御性处理强制 C 连续数组否则提示np.ascontiguousarray、严格校验 dtype、以原始字节读取 numpy bool 掩码以避免未定义行为等。Rust APIcargo add turbovecuse turbovec::TurboQuantIndex; let mut index TurboQuantIndex::new(1536, 4).unwrap(); index.add(vectors); let results index.search(queries, 10); index.write(index.tv).unwrap(); let loaded TurboQuantIndex::load(index.tv).unwrap();需要稳定外部 iduse turbovec::IdMapIndex; let mut index IdMapIndex::new(1536, 4).unwrap(); index.add_with_ids(vectors, [1001, 1002, 1003]).unwrap(); let (scores, ids) index.search(queries, 10); index.remove(1002); index.write(index.tvim).unwrap(); let loaded IdMapIndex::load(index.tvim).unwrap();Rust API 与 Python 镜像flat [f32]输入另有两个 Python 没有的低层入口见 docs/api.mdTurboQuantIndex::from_parts(...)直接由内存中的解码头字段dim、bit_width、n_vectors、packed_codes、scales、TQ shift/scale构造索引跳过文件往返——适合把索引载荷存在数据库页/自研存储中的嵌入方。所有结构不变量一次性校验违反时返回具名FromPartsError。write_with_durability(path, io::Durability::Fast | Durable)Python 中durable标志的 Rust 等价形式。混合检索搜索时过滤Filtered Search把检索限制在另一系统SQL、BM25、ACL、时间窗口……产出的候选集内import numpy as np from turbovec import IdMapIndex idx IdMapIndex(dim1536, bit_width4) idx.add_with_ids(vectors, ids) # Stage 1: external system narrows to candidate ids. allowed np.array(db.execute(SELECT id FROM docs WHERE tenant?, (t,)).fetchall(), dtypenp.uint64) # Stage 2: dense rerank within the candidate set. scores, ids idx.search(query, k10, allowlistallowed)过滤发生在 SIMD 内核内部、以 32 向量块为粒度没有允许槽位的块在 LUT 查找或评分工作之前就被短路评分块内的非允许槽位在堆插入时被丢弃。因此选择性白名单只允许索引的小部分会避开大部分 SIMD 成本而不是先付全量代价再丢弃结果。输出长度为min(k, n_allowed)n_allowed统计去重后的允许向量数——允许向量少于k时返回恰好那么多结果而不是用填充兜底。一个重要的陷阱docs/api.md 特别强调任何变更都会使掩码失效而不仅是改变长度的变更。掩码按槽位命名而swap_remove会重编号槽位——swap_remove(i)add(...)组合能恢复原长度同时让槽位i变成另一个向量旧掩码通过长度校验却静默选中了错误集合。因此每次变更后都要重建掩码。IdMapIndex的白名单没有此缺陷因为它命名外部 id索引永不重编号 id对已删除 id 的白名单条目会抛KeyErrorRust 侧为SearchError::UnknownId而非悄悄解析到别的向量。持久化write 全量快照、sync 增量提交两种持久化 API 的取舍是理解 turbovec 落地方式的关键write(path)全量重写为单个.tv/.tvim文件fsync 原子重命名崩溃安全。sync(path)只写自上次同步以来的增量使用第二套容器格式.tv/.tvimmagicTV7\0为重复的小型提交而设计idx.sync(index.tv) # first sync to a fresh path: writes the whole container idx.add(more_vectors) idx.swap_remove(3) idx.sync(index.tv) # writes the delta and commits reloaded TurboQuantIndex.load(index.tv) # load() recognises both formats从源码结构看turbovec/src/lib.rs 中sync_cursor、sync_pending、sync_fresh、sync_capture_buf等字段增量机制可总结为追加操作写新的 32 行块加一个提交头删除不写任何块——它以 redo 操作搭提交头由后续 sync 折叠进块中。显式calibrate()重编码全部存储码和累积删除超过提交头操作容量会触发整文件重写压实走与write()相同的临时文件重命名路径。持久性语义README 明确每次sync返回时即已持久——无快速模式fsync 是sync_all而非仅数据变体任何字节处崩溃都保留上一次提交因为文件携带两个交替提交头撕裂的头校验失败后采用另一个且每个头列出其 sync 写入的块及其摘要先于数据落盘的提交会被检测而非被服务。文件还会被随机 nonce 打戳若另一进程在绑定的索引下方替换了文件下一次sync会报告而非覆盖他人提交——每个路径只允许一个写者并发同步不被支持检查只是让不支持的情况变得响亮而非安全。注意sync()文件只能通过路径读取from_bytes/load_from_reader读的是write()格式。文件格式与加载性能.tvTurboQuantIndex与.tvimIdMapIndex多一份slot_to_id表均为 v6/v7 版本化的紧凑格式magic 版本字节 核心头bit_width、dim、n_vectors Lloyd-Max 码本 32 向量块分组、补齐到整块的编码载荷 每向量长度重归一化 scale TQ 尾部shift/scale。3-bit 时一个字节只装 2 个码而非 8/3载荷比dim * bit_width / 8每向量约大 33%。加载性能docs/api.md Load performance 一节文件存储的是搜索内核直接消费的架构中立顺序块布局外加码本因此加载直接播种搜索缓存——首次搜索无需 O(n·dim) 重打包、无需码本求解。x86 在加载时做一次廉价的块内 nibble 交错线程化 SIMD 趟77 MB 索引约 2 ms旋转矩阵是确定性的由 dim 在亚毫秒内重建。跨平台 load → re-save 字节一致格式本身无平台依赖。安全边界加载在分配前校验头——bit_width必须为 2/3/4dim为 8 的正倍数且 ≤ 16384所有载荷大小用检查算术计算并通过限长读取器读取畸形或不可信文件干净地报错而非 panic 或驱动超大分配MAX_DIM 16384同时防止资源耗尽型 DoS。但格式不做载荷完整性校验实测翻转一个 4114 字节.tv文件的全部 32912 位仅 1460 位4%被拒绝其余 96% 能加载并返回不同索引——其中 24576 个码位最大区块0 个被拒绝。这是刻意范围选择写入是原子的写者不会留下撕裂索引落盘后来自外部的损坏需要你自己做校验和或用提供它的文件系统兜底。并发搜索与惰性初始化从 turbovec/src/lib.rs 的文档可以看到明确的并发模型search取self可从多线程并发调用。旋转矩阵、Lloyd-Max 质心、SIMD 块布局内部通过std::sync::OnceLock惰性初始化第一个调用者支付一次性成本后续调用者无锁读取缓存prepare()可提前支付该成本。变更仍走mut self其维护的不变量是只要索引经self可达每个已填充缓存都精确描述索引当前持有的len()行。旋转、边界、质心仅是(dim, bit_width)的纯函数且永不陈旧块布局与打包位平面行是同一批行的两种编码变更在整个持续期内持有mut self因此不存在并发的读者。两种编码给出的搜索结果逐位一致。性能压缩、召回率与搜索速度README 给出的全部性能数据均来自 benchmarks/suite/ 下自包含的基准脚本结果以 JSON 存于 benchmarks/results图表由 benchmarks/create_diagrams.py 生成。所有搜索基准的公共条件10 万向量、1000 查询、k64、5 次运行取中位数。压缩。README 的开篇声明是1000 万文档语料以 float32 存储需 31 GB RAMturbovec 可将其装入 4 GB——并比 FAISS 搜得更快。1536 维向量 2-bit 打包后为每向量 384 字节即 16 倍压缩。召回率。基准对照为 FAISSIndexPQLUT256, nbits8即论文 Section 4.4 的基线FAISS 的 PQ 子量化器数量按匹配 TurboQuant 比特率配置2-bit 为 md/44-bit 为 md/2。跨 OpenAI d1536 与 d3072校准版 TQ 在四个单元中的三个于 R1 超过 FAISS高出 0.9–2.9 点d1536 4-bit 落后 0.7两者在 k8 时均达 1.0k≤4 时已 ≥0.997。GloVe d200 是更难的低维区间——低维下渐近 Beta 假设较宽松——TQ 在两个位宽下 R1 均领先 FAISS4-bit 1.92-bit 0.8FAISS 在 2-bit 自 k≈8 起保持微弱优势。完整结果见 recall_d1536_2bit.json 等 6 个 JSON 文件。搜索速度。x86 上 TurboQuant 全面胜出4-bit 平均 3.4×各单元 3.2–3.5×AVX-512 VNNI 点积内核直接评分向量主序布局2-bit 平均 20%5–32%其中vpermbLUT 扫描承担短的 2-bit 累加循环。ARM 上平均 3.5×4-bit3.4–3.7×SDOT/SMMLA 点积内核与 26%2-bit22–29%。速度内核的实现见 turbovec/src/search.rsNEONARM 顺序布局、x86 的 AVX-512BWFAISS 风格 perm0 交错布局与 AVX2 回退在运行时经is_x86_feature_detected!选择其他目标走标量回退。插入与删除延迟同为 10 万 OpenAI 向量、5 次取中位数、计时循环含每次操作实际支付的 Python 调用开销单向量add()落在 6.3–19.7 µs视单元而定比 FAISS 单次 add 快 7.6–13.9×100 向量批量把 TurboQuant 摊薄到 4.6–16.3 µs/向量比同一批量进 FAISS 快 4.6–15.1×。IdMapIndex.remove(id)是 O(1) 的 swap-and-pop 加 id 表簿记落在 0.44–1.22 µsn1与 0.59–1.37 µs/opn100。FAISS 对照列是IndexIDMap上的remove_ids它每次调用都重打包存储码10 万规模下单次删除 0.19–1.02 s成本随码尺寸翻倍——这正是删除图用对数轴的原因。单线程单元固定RAYON_NUM_THREADS1。完整结果见 benchmarks/results 下各speed_insert_*/speed_remove_*JSON。保存与加载。TurboQuant 序列化为单个.tv文件fsync 原子重命名FAISS 对照为比特率匹配的IndexPQFastScan的write_index/read_index。基准区分暖保存搜索后写入块布局缓存已填充、加载→首次搜索分离裸反序列化与首查询成本与往返变更 1K 向量 → 保存 → 重开 → 服务首个查询FAISS 无此路径的实测等价物仅对 TurboQuant 展示。在较小载荷上往返可能低于隔离的后变更脏写入两者在独立套件步骤中计时小文件下独立 fsync 占据主导而放大该数值——是基准夹具的测量产物而非组合路径中的重打包收益。完整结果见 benchmarks/results 下各speed_persist_*JSON。构建与基准测试构建Python 绑定经 maturinpip install maturin cd turbovec-python maturin build --release pip install target/wheels/*.whlRustcargo build --release所有 x86_64 构建以x86-64-v2SSE4.2 基线Nehalem 2008为目标AVX-512 与 AVX2 内核经#[target_feature]门控、运行时经is_x86_feature_detected!选择因此只要硬件支持就会启用CPU 不支持则走标量回退。注意 crate 是 64 位专属设计——在非 64 位目标上会编译失败compile_error!这是故意的安全边界。运行基准先下载数据集python3 benchmarks/download_data.py all # all datasets python3 benchmarks/download_data.py glove # GloVe d200 python3 benchmarks/download_data.py openai-1536 # OpenAI DBpedia d1536 python3 benchmarks/download_data.py openai-3072 # OpenAI DBpedia d3072单个基准脚本自包含于 benchmarks/suite/python3 benchmarks/suite/speed_d1536_2bit_arm_mt.py python3 benchmarks/suite/recall_d1536_2bit.py python3 benchmarks/suite/compression.py按类别跑全部基准for f in benchmarks/suite/speed_*arm*.py; do python3 $f; done # all ARM speed for f in benchmarks/suite/speed_*x86*.py; do python3 $f; done # all x86 speed for f in benchmarks/suite/recall_*.py; do python3 $f; done # all recall python3 benchmarks/suite/compression.py # compression结果存为 JSON 于benchmarks/results/重绘图表python3 benchmarks/create_diagrams.py另有面向优化迭代的 Rust 快速 harnesscargo run --release --example insert_bench -- --dim 1536 --bits 2或RAYON_NUM_THREADS1 cargo run --release --example insert_bench在确定性合成向量上复现冷批量添加、暖追加、单次添加、删除四项变更指标——无需数据集与 FAISS 即可在任何机器上秒级验证假设。它是筛选工具不是已发布数字的来源。examples/encode_hash打印编码管线各阶段哈希CI 在每个 OS 上运行并要求一致用于跨平台编码字节同一性检查。框架集成与典型选型建议turbovec 为四个常见框架提供即插即用的向量/文档存储替换详见 docs/integrations公共接口、持久化语义、检索器与管线接线均保持不变——只需换 importLangChainpip install turbovec[langchain]替换langchain_core.vectorstores.InMemoryVectorStoreLlamaIndexpip install turbovec[llama-index]替换llama_index.core.vector_stores.SimpleVectorStoreHaystackpip install turbovec[haystack]替换haystack.document_stores.in_memory.InMemoryDocumentStoreAgnopip install turbovec[agno]替换agno.vectordb.lancedb.LanceDb集成实现与对应测试位于 turbovec-python/python/turbovec 与 turbovec-python/tests且根据 docs/api.md这些框架集成内部统一使用IdMapIndex理由正是它提供稳定外部 id。两种索引的选型结论也很清晰从不删除或能接受位置 id 时用TurboQuantIndex更小更快需要稳定外部 id如调用方维护 string-id → vector 映射时用IdMapIndex。结合 turbovec/tests 下覆盖并发搜索、过滤、持久化、校准确定性、交换删除等行为的测试用例可以确认上述 API 语义均有对应的行为验证。结语turbovec 的价值在于把数据无关量化从论文带到了可落地的工程形态在线摄入免去了训练环节SIMD 内核在 ARM 与 x86 上双向对标 FAISS FastScansync()让大索引的增量提交以毫秒计而搜索时过滤使混合检索不牺牲召回。若要进一步深入建议依次阅读 docs/api.md完整 API 参考、turbovec/src/encode.rs 与 turbovec/src/rotation.rs编码与旋转的确定性契约、turbovec/src/search.rsSIMD 内核与并行调度并在自己的 embedding 上以 benchmarks/suite 的脚本为模板复现压缩、召回与速度数据。【免费下载链接】turbovecA vector index built on TurboQuant, written in Rust with Python bindings项目地址: https://gitcode.com/GitHub_Trending/tu/turbovec创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表