Faiss 用于高效相似性搜索和密集向量聚类, 常用于异常检测中的相似度评估, 库有 GPU 扩展版本, 但官方只支持 Linux. 本文讨论在 Windows 下编译 faiss-GPU 并安装到 Python.

虽然理论上我应该添加与 Windows+CUDA 相关的 Github Action, 然后合并到上游, 但是我暂时没有与之搏斗的念头.

准备工作

  1. 安装 Winget, 用于下载一些工具, 目前 Windows 应该是预装的, 但是如果你没, 可以访问getwinget或者微软官方文档
  2. VS 2019或2022, 截止当下(2025/09/23), Intel OneAPI 不支持 VS2026. 执行: winget install Microsoft.VisualStudio.2022.BuildTools, 或打开visual studio Installer选择 vs2022 构建工具
  3. CMake, winget install Kitware.CMake
  4. Ninja, 代替 MSBuild 编译会快很多, 执行: winget install Ninja-build.Ninja
  5. swig, faiss 用来生成 Python 扩展, 执行: winget install SWIG.SWIG
  6. BLAS, 根据官方建议, 如果在 Inter 平台, 选择 Intel OneAPI MKL, 其他则选择 OpenBLAS
    • Intel OneAPI, winget install Intel.OneAPI.BaseToolkit, 文件很大(~2.8G), 安装后确保你能找到一个叫setvars.bat的文件, 如果安装路径默认, 这个文件在C:\Program Files (x86)\Intel\oneAPI\setvars.bat
    • OpenBLAS? 我没有试过, 我只是走通了上面的 MKL 流程
  7. CUDA 12.x 访问https://developer.nvidia.com/cuda-toolkit-archive, 然后选一个. 我在 12.4、12.9 都测试成功
  8. [可选] Python, 如果你不需要 Python 包可以没有

安装 gflags

faiss 依赖 gflags, 只需依次执行如下命令来安装

git clone https://github.com/gflags/gflags.git
cd gflags
cmake -B build-out . -G "Ninja" -DCMAKE_INSTALL_PREFIX=C:/opt/gflags # 目录会自动创建并注册
cmake --build build-out --config Release
cmake --install build-out

[可选] 配置 Python

找一个你认为合适的目录, 新建虚拟环境然后安装三个包, 随后激活虚拟环境并进入 Faiss 代码目录

python -m venv .venv
pip install setuptools packaging numpy

激活环境

首先在开始菜单找到x64 Native Tools Command Prompt for VS 2022, 在其中执行 C:\Program Files (x86)\Intel\oneAPI\setvars.bat, 结果类似于:

**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.14.14
** Copyright (c) 2025 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools>"C:\Program Files (x86)\Intel\oneAPI\setvars.bat"
:: initializing oneAPI environment...
   Initializing Visual Studio command-line environment...
   Visual Studio version 17.14.14 environment configured.
   "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\"
   Visual Studio command-line environment initialized for: 'x64'
:  advisor -- latest
:  compiler -- latest
:  dal -- latest
:  debugger -- latest
:  dev-utilities -- latest
:  dnnl -- latest
:  dpcpp-ct -- latest
:  dpl -- latest
:  ipp -- latest
:  ippcp -- latest
:  mkl -- latest
:  ocloc -- latest
:  pti -- latest
:  tbb -- latest
:  umf -- latest
:  vtune -- latest
:: oneAPI environment initialized ::

我直接在 cmd 中执行C:\Program Files (x86)\Intel\oneAPI\setvars.bat会告诉我找不到 VS 环境

克隆代码

我对上游代码做了些修改, 在上游修补之前, 你可以克隆我的分支

git clone https://github.com/myuanz/faiss.git
cd faiss

之后默认都在 Faiss 代码目录执行.

配置

# 如果需要 Python 扩展, 执行
cmake . -B build -DFAISS_ENABLE_PYTHON=ON -G "Ninja" -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release -DFAISS_ENABLE_GPU=ON 
# 如果不需要 Python 扩展, 执行
cmake . -B build -DFAISS_ENABLE_PYTHON=OFF -G "Ninja" -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release -DFAISS_ENABLE_GPU=ON 

如果提示 SWIG 找不到, 则你需要在 PowerShell 里执行:

' -DSWIG_EXECUTABLE=' + (Get-Item (where.exe swig | Select-Object -First 1) -Force).Target

一份可能的输出是:

 -DSWIG_EXECUTABLE=C:\Users\pc\AppData\Local\Microsoft\WinGet\Packages\SWIG.SWIG_Microsoft.Winget.Source_8wekyb3d8bbwe\swigwin-4.3.1\swig.exe

把这句粘贴到之前 cmake 命令的后面

构建 C++ 部分

cmake --build build -j
cmake --install build --prefix install

我也将这个导出的install放到了 releases

构建 Python 部分

cd build/faiss/python
python setup.py install

修改 loader.py

我不确定为什么, 我需要修改 loader.py 里的

- from .swigfaiss import *
+ from swigfaiss import *

才能正常导入

检查结果正确性

我在仓库里额外提供了一个 try_import_faiss_python.py, 安装 faiss-python 之后修改 loader, 然后执行这个文件可以看到一些 GPU 信息和性能比对. 由于运行时还需要一些 dll, 该文件在开头也添加了一些路径:

import os, sys, ctypes
 
for p in (
    r'./build/faiss/python',
    r'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.9\bin',
    r'C:\Program Files (x86)\Intel\oneAPI\compiler\2025.2\bin',
    r'C:\Program Files (x86)\Intel\oneAPI\mkl\2025.2\bin'
):
    p = os.path.abspath(p)
    os.add_dll_directory(p)
    sys.path.append(p)
 
# 
 
# The below code is generated by LLM:
# GPU self-check
ngpu = faiss.get_num_gpus()
print(f"[INFO] Num GPUs detected by FAISS: {ngpu}")
if ngpu == 0:
    raise RuntimeError("Can't find GPU")
 
# %%
 
# Parameters (adjust as needed; Flat complexity ~ nb*nq*d)
d   = 64
nb  = 200_000
nq  = 40_000           # Increase batch size to avoid launch/scheduling overhead dominating
k   = 10
seed = 123
 
rs = np.random.RandomState(seed)
xb = rs.randn(nb, d).astype('float32')
xq = rs.randn(nq, d).astype('float32')
 
xb = rs.randn(nb, d).astype('float32')
# Make the vectors have a "small structure" for sanity check
xb[:100, :] += 3
xq = (rs.randn(nq, d)).astype('float32')
xq[:5, :] += 3
 
# ---- CPU baseline ----
cpu = faiss.IndexFlatL2(d)
t0 = time.perf_counter()
cpu.add(xb)
t1 = time.perf_counter()
Dcpu, Icpu = cpu.search(xq, k)
t2 = time.perf_counter()
print(f"[CPU] add {1e3*(t1-t0):.1f} ms  search {1e3*(t2-t1):.1f} ms")
 
... # 下略

执行代码会首先看到 CPU 满载, 然后 GPU 满载. 这份代码只是跑通了, 姿势不太好看, 以后有机会研究一下怎么发 whl 吧.