故障排查指南
问题报告
需要报告的内容
为确保问题能够被有效地复现和解决,请在提交Bug报告时务必包含以下信息(如内容较多可用 gist 进行分享):
- 能复现问题的最简代码示例
- 如为C++崩溃,请附上gdb的堆栈信息(stacktrace)
- 除非确定与已存在问题完全一致,请新开一个Issue,便于团队分流和追踪
- 如为GPU相关问题,请补充以下信息:
- 操作系统版本、GPU型号、nvidia-smi命令的输出
- 可执行文件或Python版本的
_swigfaiss_gpu.so的ldd命令输出
更多关于高效报告Bug的说明,请参考这里。
请不要通过邮件或电话寻求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-dev或libopenblas0-openmp而非libopenblas-dev或libopenblas0-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,
add和search等接口在处理大规模输入时,32位/64位整数处理会出现问题。GPU上的32位整数计算速度比64位快,但这导致GPU Faiss在CPU侧也采用32位整数。此问题仍在修复计划中。理想情况下,GPU Faiss将自动处理数据分页(paging),比如你可以传递1TB大小的内存映射向量给add或search,但实际还需完善。 -
对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区提问。