首页
/ Faiss contrib 模块深度解析:从分布式索引、磁盘合并到 PyTorch 互操作的 Python 辅助库

Faiss contrib 模块深度解析:从分布式索引、磁盘合并到 PyTorch 互操作的 Python 辅助库

2026-09-05 09:26:20作者:何举烈Damon

faiss 的 contrib/ 目录是一组随 Python 包一起编译为 faiss.contrib 模块的辅助工具库,覆盖分布式检索、磁盘索引合并、超大规模暴力搜索、PyTorch 张量互操作、IVF 索引高级操控等场景。本文基于仓库内的 contrib/README.md 逐模块展开,并结合各模块源码实现与测试用例,说明每个模块的定位、关键 API 与底层工作方式,帮助你在索引放不下内存、需要跨机器分片或与 PyTorch 工作流集成时,直接复用这些经过验证的工具。

1. contrib 的编译方式与依赖模型

contrib/README.md 的 "Code structure" 一节可以确认两条基本规则:

  1. 编译产物:整个 contrib 目录会被编译进 Python 包的 faiss.contrib 模块,因此导入方式为 from faiss.contrib import client_server 这类形式,仓库中的测试文件 tests/test_contrib.py 第 18–34 行展示了这种用法(直接导入 big_batch_searchclusteringdatasetsevaluationfactory_toolsinspect_toolsivf_toolsondisk.merge_ondisk 等符号)。
  2. 可选依赖不自带:部分模块依赖 GPU 版 faiss、PyTorch、h5py 等外部库,这些依赖不会被编译进包里,需要用户自行提供。也就是说:在没有安装 GPU 版的普通 CPU 环境里,faiss.contrib 仍然可以导入,只是涉及 GPU 的分支不可用;同理 contrib/clustering.py 第 16–19 行对 scipy.sparse 的导入做了 try/except 降级处理,缺失 scipy 时仅提示 "Python k-means will not work" 而不中断导入。

这种设计让 contrib 保持了"低耦合、按需提供"的特性:核心 faiss 包不因此膨胀,高级功能按需启用。

2. 模块总览

模块 职责 典型使用场景
rpc.py 极简 pickle 序列化 RPC 框架 作为 client_server 的通信底座
client_server.py 将 faiss 索引暴露为远程服务,客户端合并多机结果 数据集跨机器分片的分布式检索
ondisk.py 将多个内存索引分片合并写入一个磁盘倒排索引 超大规模 IVF 索引落盘
exhaustive_search.py 分块计算 ground truth(支持 GPU) 召回率评测、超大库精确 KNN
torch_utils.py 让 PyTorch 张量可直接作为 faiss 参数 深度学习 + 向量检索混合流水线
inspect_tools.py 读取 SWIG 包装的 C++ 对象内部字段 检查倒排列表、PQ 码本、变换矩阵
ivf_tools.py 覆盖/扩展 IVF 粗量化与指定列表搜索 自定义分配策略、重排倒排列表
datasets.py 标准数据集的统一访问接口(可能依赖 h5py) 下载/读取 sift1M、bigann、deep 等
factory_tools.py 解析与反推 index_factory 字符串 计算编码长度、由索引对象还原字符串
evaluation.py 检索结果的多种评测函数 KNN/Range 结果的 Precision-Recall
clustering.py Python 版 kmeans 与两级聚类 特殊数据类型聚类、训练 IMI 类索引
big_batch_search.py 按倒排列表逐桶批量检索 IVF 大库 + 大批量查询的搜索加速

仓库中还存在一个未在 README 列出的 contrib/vecs_io.py,提供 fvecs/bvecs/ivecs 格式的文件读取、内存映射与分块迭代(bvecs_iterbvecs_iter_chunked 等),datasets.py 中大容量数据集的 mmap 访问正是建立在这些函数之上。

3. rpc.py:pickle 化的极简 RPC

rpc.py 是一个"仅用于演示"的远程过程调用实现,README 中对其的定位是:"函数参数与结果都用 pickle 序列化,供 client_server.py 使用"。源码揭示了它的具体协议与安全设计:

  • 传输层:FileSock 类(第 47–87 行)把 socket 包装成支持 read/write 的文件对象,使 pickle 可以直接在其上序列化,发送时以 512KB 为块循环 send
  • 调用协议:客户端发送 (fname, args),服务端执行 Server 对象的同名方法,回送 (st, ret)——st 为 None 或执行期异常的 traceback 字符串,ret 为返回值。Client.__getattr__(第 233–234 行)使得客户端可以像调用本地方法一样透明地调用远程方法,异常在客户端被重新抛出。
  • 安全白名单:RestrictedUnpickler(第 35–44 行)只允许反序列化 numpynumpy.core.multiarray 两个模块的对象,其他一律抛出 UnpicklingError。模块 docstring 明确声明:"This code is for demonstration purposes only...not meant to be run on an untrusted network or in a production environment",即不能直接用于不受信任的网络或生产环境。
  • 服务入口:run_server(new_handler, port=PORT, ...),默认端口 PORT = 12032,每个连接在新线程中执行 exec_loop;report_to_file 参数可把"主机:端口"写入文件,便于客户端发现服务。

4. client_server.py:把索引分片到多台机器

client_server.py 是 contrib 中"分布式索引"方案的核心:服务器把请求转发给本地 faiss 索引,客户端把多台机器的子索引结果用堆合并。

4.1 服务端

SearchServer(第 17–34 行)继承 rpc.Server,在构造时通过 faiss.extract_index_ivf(index) 取出内部 IVF 子索引,从而暴露:

  • set_nprobe(nprobe):远程设置探测半径;
  • get_ntotal():远程查询向量数;
  • __getattr__:其余所有方法透明转发给索引对象本身。

启动入口为 run_index_server(index, port, v6=False)(第 37–39 行),该函数会永久循环地服务请求。

4.2 客户端

ClientIndex 的构造接受 machine_ports: List[Tuple[str, int]](主机、端口对列表),内部为每台机器建立 rpc.Client 连接,并用 ThreadPool 并发下发搜索。其 search(x, k) 的实现要点(第 76–85 行):

def search(self, x, k: int):
    rh = faiss.ResultHeap(x.shape[0], k)
    for Di, Ii in self.pool.imap(
        lambda idx: idx.search(x, k), self.sub_indexes
    ):
        rh.add_result(Di, Ii)
    rh.finalize()
    return rh.D, rh.I

即:各子索引各自返回 top-k,faiss.ResultHeap 做增量合并,最终 finalize() 得到全局 top-k。此外还提供 set_omp_num_threadsget_ntotal(跨机器求和)等便捷方法。

4.3 端到端示例:demos/demo_client_server_ivf.py

demos/demo_client_server_ivf.py 完整演示了以 SIFT1M 为例的四机分片流程,按命令行参数 stage 分阶段执行:

  • stage 0(第 37–44 行):读取 sift_learn.fvecs,用 faiss.index_factory(d, "IVF4096,Flat") 训练并保存 /tmp/trained.index;
  • stage 1–4(第 47–56 行):把 sift_base.fvecs 均分 4 份,每份分别 add_with_ids 到 trained index 的副本中,写出 block_0..3.index(注意用 add_with_ids 保持全局 ID 连续);
  • stage 5–8(第 67–76 行):各自读取一个分片,在 localhost 的 12010–12013 端口调用 run_index_server;
  • stage 9(第 79–91 行):构造 ClientIndex(machine_ports),执行 client_index.set_nprobe(16)client_index.search(xq, 5),并与 sift_groundtruth.ivecs 对比输出 recall@1。

这套"训练一次 → 分片写入 → 多进程起服务 → 客户端合并"的模式,正是 README 所链接的 wiki "Distributed index" 方案的参考实现,适合数据集总量超过单机内存的场景。

5. ondisk.py:把多个分片合并成一个磁盘索引

ondisk.py 只提供一个核心函数 merge_ondisk(trained_index, shard_fnames, ivfdata_fname, shift_ids=False)(第 13–64 行),其流程非常值得细读:

  1. 以 mmap 方式读取分片:对每个 shard_fnames 中的索引调用 faiss.read_index(fname, faiss.IO_FLAG_MMAP),注释明确说明这样做的目的——"避免真正把数据读进内存,因此倒排列表总大小可以超过可用 RAM";
  2. 脱离所有权:取出 index_ivf.invlists 后设置 index_ivf.own_invlists = False,防止倒排列表随索引对象析构而释放;
  3. 构建输出倒排列表:创建 faiss.OnDiskInvertedLists(nlist, code_size, ivfdata_fname),其数据写入 ivfdata_fname 文件;
  4. 合并:invlists.merge_from_multiple(ivf_vector.data(), ivf_vector.size(), shift_ids) 把所有分片的倒排列表合并,shift_ids 控制是否按分片偏移全局 ID;
  5. 替换并移交所有权:index_ivf.replace_invlists(invlists, True) 后调用 invlists.this.disown(),让底层 C++ 对象接管生命周期。

两个硬约束在源码中可以直接看到:assert not isinstance(trained_index, faiss.IndexIVFPQR)(IVFPQR 因需要额外元数据而不支持落盘)与 assert index.ntotal == 0("works only on empty index",只能合并进空索引)。这个函数与 demos/demo_client_server_ivf.py 的内存分片方案互补,构成"合并到磁盘"的 On-disk storage 标准路径。

6. exhaustive_search.py:超出内存的精确搜索

exhaustive_search.py 提供在不把整个库载入内存的前提下计算 ground truth 的能力,README 指明其测试位于 tests/test_contrib.TestComputeGT(对应 tests/test_contrib.py 第 37 行起的 TestComputeGT 类)。

6.1 knn_ground_truth:分块 KNN + 堆合并

knn_ground_truth(xq, db_iterator, k, metric_type=faiss.METRIC_L2, shard=False, ngpu=-1)(第 15–53 行)的算法是:

  • 用一个只容纳当前块的 faiss.IndexFlat(必要时经 faiss.index_cpu_to_all_gpus 克隆到全部 GPU,shard 选项控制多卡分片)做逐块精确搜索;
  • 每块搜索后用 I += i0 修正全局偏移,再 rh.add_result(D, I)faiss.ResultHeap(keep_maxfaiss.is_similarity_metric 自动设置以支持内积度量);
  • 块处理完 index.reset() 释放,循环结束后 rh.finalize() 返回全局 top-k。

测试用例(第 39–59 行)用 10000 个库向量按 1000 一批的迭代器计算 k=10 的 GT,与一次性 IndexFlat.search 的结果比对索引完全相等、距离在 1e-4 内一致。

6.2 GPU 上的范围搜索:range_search_gpu

由于 GPU 索引不原生支持 range search,range_search_gpu(xq, r2, index_gpu, index_cpu, gpu_k=1024)(第 60 行起)采用"KNN 模拟 + CPU 兜底"策略:先在 GPU 上做 k=min(ntotal, gpu_k) 的 KNN;若某个查询的第 k 近邻距离未覆盖阈值(即 D[:, k-1] < r2(L2)或 > r2(相似度)),说明结果可能不全,则把这些查询回落到 index_cpu(可以是支持 range search 的 CPU 索引,或直接是 numpy 矩阵——后者会自动构建 Flat 索引)做精确 range search,最后用 faiss.CombinerRangeKNNfloat/int16(二进制索引)两种查询无遗漏地拼合结果。range_ground_truth(第 159 行起)进一步把该逻辑包装成分块 GT 计算,CPU/GPU 两条路径共用同一套 lims/D/I 输出格式。

6.3 结果数量受控的范围搜索:range_search_max_results

range_search_max_results(index, query_iterator, radius, max_results, min_results, ...)(第 277 行起)面向查询量巨大的场景:它边搜索边统计总结果数,一旦 totres > max_results 就调用 apply_maxres——用 np.partition 在所有已收集距离中快速选出新半径,使结果数回落到 min_results(默认 0.8 * max_results)。exponential_query_iterator(xq, start_bs=32, max_bs=20000)(第 382 行起)则提供"32 → 64 → 128 → …"指数增长的查询分批,让半径在早期小批量上快速收敛,避免中间结果爆炸。

7. torch_utils.py:让 PyTorch 张量直喂 faiss

torch_utils.py 实现 README 所述"导入后 pytorch Tensors(CPU 或 GPU)即可作为 faiss 索引和函数的参数"。其实现机制与约束值得掌握:

7.1 指针桥接

核心是一组 swig_ptr_from_*Tensor 函数(第 36–88 行),它们通过 x.untyped_storage().data_ptr() + x.storage_offset() * 元素大小 拿到张量的真实内存地址,再经 faiss.cast_integer_to_float_ptr 等函数转成 SWIG 指针——这一步等价于 numpy 路径中 faiss.swig_ptr 的作用,且要求张量 is_contiguous()、dtype 严格匹配(float32/float16/bfloat16/int32/int64/uint8)。

7.2 方法猴子补丁

handle_torch_Index(the_class)(第 149 行起)重写了 addadd_with_idsassigntrainsearchsearch_preassignedsearch_and_reconstructremove_idsreconstructreconstruct_nupdate_vectorsrange_searchsa_encodesa_decode 等方法,并在模块底部(第 649–654 行)遍历 faiss 模块中所有 Index 子类批量应用。每个重写方法遵循统一模式:

  • 参数是 np.ndarray → 转发回 numpy 版本(如 self.search_numpy(...)),保证兼容;
  • 参数是 GPU 张量 → 断言索引本身是 GPU 索引(hasattr(self, "getDevice")),并在 using_stream(self.getResources()) 上下文内调用 *_ex/*_c 底层接口;
  • 参数是 CPU 张量 → 直接调用底层 *_ex/*_c

7.3 GPU 流同步

using_stream(res, pytorch_stream=None)(第 96–123 行)是互操作的正确性关键:它把 faiss GpuResources 的默认 CUDA 流切换为 torch.cuda.current_stream(),退出时恢复原流。这样 faiss GPU 索引与 PyTorch 计算在同一 CUDA 流中按序执行,无需显式同步,也不会破坏 PyTorch 的异步执行模型——这正是 README 中"自动完成与当前 pytorch 流的同步"的具体实现。

7.4 模块级函数与使用约束

faiss.knnfaiss.knn_gpufaiss.pairwise_distance_gpu 也被打了同样的补丁:knn 支持 CPU torch 张量(L2/内积/扩展度量分别落到 knn_L2sqrknn_inner_productknn_extra_metrics);knn_gpu 支持 float32/float16/bfloat16 查询与库向量,并允许 int64/int32 索引输出,通过 faiss.GpuDistanceParams 一次性传给 faiss.bfKnn

使用约束(与 README 完全一致):导入后 numpy 数组仍可用,但同一次调用的所有参数必须统一为 numpy 或 torch,禁止混用;torch GPU 张量只能配 faiss GPU 索引。测试覆盖见 tests/torch_test_contrib.py(CPU)与 GPU 侧的 GPU 测试。

8. inspect_tools.py:窥探 SWIG 包装的 C++ 对象

inspect_tools.py 正如 README 所说,"大多只是读取字段并转换为合适的 python 数组"。常用函数:

  • get_invlist(invlists, l):返回第 l 个倒排列表的 (list_ids, list_codes);对普通 InvertedLists 码长即 code_size,对 BlockInvertedLists 则按 (ls_round, bs // npb, npb) 形状整形;并通过 release_ids/release_codes 正确释放 SWIG 临时对象;
  • get_invlist_sizes(invlists):全部列表的规模数组,常用于检查 IVF 桶的均衡性;
  • get_pq_centroids(pq):PQ 码本展开为 (M, ksub, dsub) 数组;
  • get_LinearTransform_matrix(pca) / make_LinearTransform_matrix(A, b):从 PCA/OPQ/随机旋转等线性变换中提取或注入矩阵 A 与偏置 b,后者会自动 set_is_orthonormal(),方便手工构造正交变换;
  • get_flat_data(index) / get_flat_codes(index_flat):从 IndexFlat/IndexFlatCodes 导出数据矩阵或码字;
  • get_NSG_neighbors(nsg):导出 NSG 图的 N×K 邻居表;
  • print_object_fields(obj):列出 SWIG 已知的所有字段,排障时很实用。

9. ivf_tools.py:IVF 粗量化与指定列表搜索的扩展

ivf_tools.py 提供 README 所称"覆盖 IVF 粗量化器的若干函数,为分配提供额外灵活性":

  • add_preassigned(index_ivf, x, a, ids=None):分配结果 a 已算好时,直接经 add_core 写入倒排列表,跳过量化器计算;
  • search_preassigned(index_ivf, xq, k, list_nos, coarse_dis=None):在用户指定的倒排列表编号 list_nos(形状 (n, nprobe))上执行搜索。源码注释指出它相对 IndexIVF.search_preassigned 的优势是支持带 pretransform 的复合索引(链长为 1 时自动先 transform.apply(xq) 再下探),且对 coarse_dis 缺省时自动补零矩阵(内积 + 残差编码时该值会真正参与距离计算);
  • range_search_preassigned:同样思想的范围搜索版,经 range_search_preassigned_c 拿到原始指针后拷贝为 numpy 数组返回;
  • replace_ivf_quantizer(index_ivf, new_quantizer):原子地替换粗量化器——新量化器为空时会自动用原 reconstruct_n() 得到的质心完成训练并添加;旧量化器通过 own_fields 交接干净释放,并登记进 referenced_objects 防悬垂;
  • permute_invlists(index_ivf, perm)sort_invlists_by_size(index_ivf):按任意置换重排倒排列表并同步 quantizer.permute_entries,后者按桶规模升序排列,便于把小桶排在前面以改善尾延迟。

10. datasets.py:标准数据集的统一访问

datasets.py 定义 Dataset 抽象基类(第 23 行起,统一 get_queries/get_database/get_groundtruth/distance 等接口)与一批具体数据集:DatasetSIFT1MDatasetGIST1MDatasetBigANNDatasetDeep1BDatasetGloveDatasetMusic100DatasetDINO10B,以及无需下载的 SyntheticDataset。统一入口是 dataset_from_name(dataset="deep1M", download=False)(第 508–547 行),支持 sift1Mgist1Mbigann1M..1Bdeep1M..1Bmusic-100glovedino* 等名称解析;set_dataset_basedir(path)(第 150 行)用于切换数据根目录。

面向超大规模数据的两个设计细节:

  • DatasetDINO10B.get_database()(第 464–475 行)在库规模超过 1000 万时直接抛出 NotImplementedError,提示改用 database_iterator 或限制规模——避免误把几十 GB 数据 mmap 后一次取回;database_iterator(bs=10_000) 基于 vecs_io.pybvecs_iter_chunked 顺序读取 chunk_XXXX.bvecs 分块文件,且自带块序号连续性校验(缺块即报 Gap detected);
  • 小数据集(如 SIFT1M)的查询则通过 bvecs_mmap 内存映射读取后经 sanitize 转换为 float32,几乎零拷贝。

README 提示该模块"may require h5py",即部分数据集路径依赖 h5py,使用前需确认环境已安装。

11. factory_tools.py:factory 字符串的双向解析

factory_tools.py 处理 index_factory 字符串相关的两个高频需求:

11.1 由字符串算编码长度:get_code_size(d, indexkey)

get_code_size(第 10–76 行)对裸 key(去掉 IVF 前缀后)逐一匹配:

  • PQ(M)x(n)(fs|fsr)?:(M*n+7)//8 字节(fast-scan 变体也按字节码计算);
  • SQ8dSQ4(d+1)//2SQ6(d*6+7)//8SQfp16/SQbf162d;
  • HNSW(M):约 4d + M*2*4 字节;
  • IMIIVF...(…) 复合前缀递归拆解;Refine(x) 为两段之和;OPQ/PCA/RR 前缀替换维度后递归。

这在没有实际构建索引的情况下预估磁盘占用非常有用,且与 faiss.Index.code_size 语义一致。

11.2 由对象反推字符串:reverse_index_factory(index)

reverse_index_factory(第 83 行起)按类型分派还原 factory 字符串:IndexFlatFlat;IndexIVF 根据量化器类型拼出 IVF{nlist}IMI{M}x{nbits}IVF{nlist}_HNSW{M} 前缀,再按 Flat/SQ/PQ/PQfs/RaBitQ 拼接后缀;IndexPreTransform 还原 OPQ{M}_{d}ITQPCA/PCAR 前缀;还处理 IndexRefineIndexLSHIndexRaBitQIndexIDMap/IDMap2 嵌套(注意 IndexIDMap2 必须先于 IndexIDMap 判断)。源码注释也坦诚:SQ8u/SQ4u 这类合成名不可通过 index_factory 往返。

12. evaluation.py:非平凡的检索结果评测

evaluation.py 对应 README 中"若干非平凡的搜索结果评测函数":

  • knn_intersection_measure(I1, I2)(第 17–22 行):两张 (nq, rank) 结果表的交集占比,衡量两种索引/参数配置的稳定性;
  • filter_range_results(lims, D, I, thresh)range_PR(lims_ref, Iref, lims_new, Inew, mode="overall")(第 29–76 行):range search 结果可当集合用 Precision-Recall 评测,内部用 ThreadPool(20) 并行计算每个查询的交集;counts_to_PR 则支持 overall/per-query 等模式,是 OperatingPoints(第 300 行起,扫描多个阈值绘制工作点曲线)的底层;
  • range_PR_multiple_thresholds(第 151 行起):一次计算多组半径下的 PR;
  • check_ref_knn_with_draws(Dref, Iref, Dnew, Inew, rtol, atol):参考结果与待测结果的容差比对,显式处理**距离并列(draws)**导致的合法索引差异,是写测试时的实用断言工具;
  • TimerIter/RepeatTimer(第 438/464 行):可计时的迭代器,方便在分块搜索脚本里统计吞吐。

13. clustering.py:Python kmeans 与两级聚类

contrib/clustering.py 对应 README 列出的三点内容:

  1. Python 实现的 kmeans(kmeans,第 435 行起):用 DatasetAssign 抽象分配阶段,派生出 DatasetAssignGPU(GEMM 加速分配)与 DatasetAssignSparse(scipy 稀疏矩阵分配——这正是 README 说的"可用于稀疏矩阵等特殊数据类型"),并配 sparse_assign_to_densereassign_centroidsimbalance_factor 等辅助函数;
  2. 两级聚类 two_level_clustering(xt, nc1, nc2, rebalance=True, clustering_niter=25, **args)(第 26–102 行):先对 xtfaiss.Kmeans(d, nc1, max_points_per_centroid=2000) 粗聚类,再按第一层桶规模按比例分配第二层质心数(rebalance 开启时用 bc_sum * nc2 // bc_sum[-1] 的前差实现;关闭时按 nc2 // nc1 均匀切分),逐桶训练后 np.vstack 汇总。返回值是 (centroids, iteration_stats);
  3. 训练 IVF 索引 train_ivf_index_with_2level(index, xt, **args)(第 105 行起):对 IndexPreTransform 会先链式 train/apply 再递归处理内层;对 IndexIVF 断言 metric_type == faiss.METRIC_L2 后,把两级质心填入粗量化器——这是用 factory 之外的方式训练 IMI/大 nlist 索引的典型工具。

14. big_batch_search.py:逐桶批处理的 IVF 搜索

big_batch_search.py 解决 README 所述"大库放不进 RAM 查询量也很大"的场景:把查询按粗分配聚桶,对每个倒排列表一次性完成"该桶全部查询 × 该桶全部库向量"的批量匹配,再经堆合并得到全局 top-k。

入口 big_batch_search(index, xq, k, ...)(第 237 行起)的关键参数(docstring 即源码注释,原样继承):

  • method:三种计算方式——"index"(为每个桶建 Flat 索引)、"pairwise_distances"(解码码字后算全 pairwise 距离入堆)、"knn_function"(解码后调 knn);支持 IVFFlat、IVFPQ、IVFScalarQuantizer;
  • pairwise_distances/knn:可传入自定义的 GPU 版本距离函数,使桶内计算落在 GPU 上;
  • threaded:0 顺序执行;1 预取下一个桶;2 同时预取 prefetch_threads 个桶,计算与桶准备/结果写回做 tile 流水;
  • use_float16:全链路 float16(GPU GEMM 更快);
  • q_assign:可外部指定粗分配矩阵(形状 nq × nprobe),与 ivf_tools.py 的 preassigned 思路呼应;
  • checkpoint/checkpoint_freq(默认 7200,须为 threaded 倍数):长跑任务断点续算;start_list/end_list 只处理部分倒排列表。

BigBatchSearcher(第 23 行起)承载全部数据组织:先 coarse_quantization()(以 65536 为批对 index.quantizer.search 求分配),再 reorder_assign()faiss.matrix_bucket_sort_inplace 按桶重排查询(-1 无效分配归到 0 桶后裁掉),随后逐桶 prepare_bucket——残差编码索引会先减去质心 quantizer.reconstruct(l)report() 会实时打印当前桶进度、各阶段耗时、ETA 与 faiss.get_mem_usage_kb() 内存占用,便于长跑监控。

15. 如何验证与延伸阅读

使用建议小结:单机内存放得下时优先用核心 API;库太大落盘用 ondisk.merge_ondisk;库太大且要多机用 client_server + RPC 客户端;训练期需要自定义分配/大 nlist 用 clustering.two_level_clustering;评测期需要精确 GT 或受控 range 结果用 exhaustive_search;深度学习流水线里则导入 torch_utils 后即可让张量零拷贝直喂 faiss。所有模块都随 faiss.contrib 自动可导入,外部依赖(GPU 版 faiss、PyTorch、h5py、scipy)按需自备即可。

登录后查看全文
热门项目推荐
相关项目推荐