跳到主要内容

故障排查指南

问题报告

需要报告的内容

为确保问题能够被有效地复现和解决,请在提交Bug报告时务必包含以下信息(如内容较多可用 gist 进行分享):

  • 能复现问题的最简代码示例
  • 如为C++崩溃,请附上gdb的堆栈信息(stacktrace)
  • 除非确定与已存在问题完全一致,请新开一个Issue,便于团队分流和追踪
  • 如为GPU相关问题,请补充以下信息:
    • 操作系统版本、GPU型号、nvidia-smi命令的输出
    • 可执行文件或Python版本的_swigfaiss_gpu.soldd命令输出
提示

更多关于高效报告Bug的说明,请参考这里

important

请不要通过邮件或电话寻求Faiss的技术支持。所有问题请通过Faiss的Issues页面提交。

注意

请不要截图提交文本内容,直接复制并粘贴文本内容,这样有利于问题的排查。

问题处理流程

我们会持续关注并处理提交的问题。问题会被打上如下标签:

  • unconfirmed bug(未确认的bug):如您报告的确属实,则为程序错误
  • cant-repro(无法复现):由于信息不足或我们测试时无法复现
  • bug(已确认bug):已核实确实存在问题
  • feature request(功能请求):已经接收到的功能建议
  • enhancement(优化建议):我们考虑进行修复,但未必会很快
  • documentation(文档相关):文档、注释或Wiki方面存在的问题
  • install(安装相关):安装过程中的问题(如编译、conda等)
  • GPU(仅GPU相关):仅与GPU版本有关的问题
  • Performance(性能相关):如并行、内存管理、性能回退等问题
  • Implementation(算法实现或数值问题):算法实现相关问题
  • Integration(集成相关):与第三方库/软件集成的问题
  • Platform(平台特有问题):如非x86 CPU、非GPU、非Linux系统
  • ez(适合初学者贡献):适合新手贡献的问题

我们鼓励用户自行关闭已解决的问题,但对于15天内没有任何更新的Issue,即使尚未解决,我们也会主动关闭。若您依然有相同问题,可以随时重新打开。

关于questions/help wanted等类型的问题,我们将其迁移到Discussions 讨论区

PR(拉取请求)处理流程

我们欢迎社区对Faiss代码的贡献,请参考CONTRIBUTING指南

备注

合入PR(Pull Request)需要消耗一定管理成本,请耐心等待审核和合并。

编译错误

TODO:后续会补充当前构建系统下真实的编译错误示例。

运行时错误

模块缺失

ImportError: No module named swigfaiss

出现该错误说明Faiss尚未被正确编译。

GPU预计算表相关错误

若在使用预计算表(precomputed table)构建GpuIndexIVFPQ时遇到如下断言错误:

Faiss assertion usePrecomputed_ || IVFPQ::isSupportedNoPrecomputedSubDimSize( this->d / subQuantizers_) failed in void faiss::gpu::GpuIndexIVFPQ::assertSettings_() const at GpuIndexIVFPQ.cu:469Aborted (core dumped)

请确保特征维度(dimension,记为d)与PQ的子量化器数(M)的比例d/M为该函数指定的支持值之一,参考:

函数定义链接

提示

若不满足条件,可使用OPQ变换预处理输入向量。

OpenBLAS下暴力搜索速度慢

当使用OpenBLAS库与OpenMP多线程一起运行时,搜索性能可能会显著下降。这是OpenMP与OpenBLAS线程调度冲突导致的。可通过设置环境变量解决:

export OMP_WAIT_POLICY=PASSIVE

详见Issue #53

FAISS + OpenMP + OpenBLAS 的意外线程数暴涨

在Ubuntu下使用FAISS配合OpenBLAS时,请优先选择libopenblas-openmp-devlibopenblas0-openmp而非libopenblas-devlibopenblas0-pthread,否则可能会生成意外的N²个线程(OpenMP的N个线程每个都调用sgemm(),每次sgemm()又会启动N个OpenBLAS线程)。

这是因为OpenBLAS默认采用pthread调度,而若OpenMP线程从非主线程启动则会出发这种问题。

纯Python代码崩溃

在1.4.0版本及以后的Faiss中,已支持在Python中自动追踪C++对象的引用。 若在 >=1.4.0 版本仍遇到此问题,请提交Issue报告。

无GPU版Faiss

最常见的症状为:

AttributeError: module 'faiss' has no attribute 'StandardGpuResources'

其中StandardGpuResources是使用GPU时最常访问的对象。

Faiss会尝试加载GPU支持库,若失败则自动回退至CPU模式。无论是否编译时包含GPU支持,Faiss默认不会提示报错信息。

如需具体错误信息,可执行:

from faiss import _swigfaiss_gpu

可以得到可读性更强的错误,如:

ImportError: libcudart.so.9.2: cannot open shared object file: No such file or directory

GPU初始化速度慢

首次调用Faiss的GPU函数可能会非常慢,若CUDA代码不是专门为你的GPU架构编译。这是因为CUDA缓存机制会预编译计算内核并存储到~/.nv目录。

备注

如果该目录不可写或为挂起的符号链接,或磁盘很慢,则每次启动Faiss时都会很慢。请确保~/.nv目录可用。

已知的GPU相关问题

  • 对于GPU版本的Faiss,addsearch等接口在处理大规模输入时,32位/64位整数处理会出现问题。GPU上的32位整数计算速度比64位快,但这导致GPU Faiss在CPU侧也采用32位整数。此问题仍在修复计划中。理想情况下,GPU Faiss将自动处理数据分页(paging),比如你可以传递1TB大小的内存映射向量给addsearch,但实际还需完善。

  • 对GPU的大内存请求目前未能给出友好的报错(比如对有大量粗量化中心的大型数据库启用预计算编码,可能需要超过5GB的显存)。未来我们会逐步优化,给出更友好的提示。

FAISS死锁问题

通过Python与pybind11结合的情况下可能导致死锁。示例如下:

Python 代码:

import faiss

from faisstest_module import RunFaissTest

if __name__ == "__main__":
RunFaissTest()

C++ pybind11模块:

#include "faiss/Index.h"
#include "faiss/IndexIVFPQ.h"
#include "faiss/impl/io.h"
#include "faiss/index_factory.h"
#include "faiss/index_io.h"

void DoTest() {
constexpr size_t numEmbeddings = 16384;
constexpr size_t embeddingDim = 16;

std::vector<float> input(numEmbeddings * embeddingDim);

std::unique_ptr<faiss::Index> index(faiss::index_factory(embeddingDim, "PQ4np"));

index->train(numEmbeddings, input.data());

std::cout << "Trained!" << std::endl;
}

PYBIND11_MODULE(faisstest_module, m) {
m.def("RunFaissTest", []() {
std::thread thr([] {
// PyThreadState* state = PyEval_SaveThread();
DoTest();
// PyEval_RestoreThread(state);
});
thr.join();
});
}

若如下两行未取消注释,则会发生死锁:

      PyThreadState* state = PyEval_SaveThread();
DoTest();
PyEval_RestoreThread(state);

原因是:FAISS的Python包装器会安装一个处理器,用于检测Python是否需要终止某些计算,这需要与GIL(全局解释器锁)进行交互。相关代码可查阅:handler实现

Faiss函数接收无效数据类型

某些Numpy函数可能返回np.int64类型(如从np.int64数组取值),而Faiss通过SWIG包装的接口无法处理这种类型。需要显式转换为Python的int类型,例如:

k = np.array([1, 3])[0]
D, I = index.search(x, k) # 会报错!
D, I = index.search(x, int(k)) # 正确

如有进一步疑问,请参见Faiss的官方文档或在Issue区提问。