Skip to content

Instantly share code, notes, and snippets.

@jlmelville
Last active January 12, 2025 02:38
Show Gist options
  • Save jlmelville/9b4f0d91ede13bff18d26759140709f9 to your computer and use it in GitHub Desktop.
Save jlmelville/9b4f0d91ede13bff18d26759140709f9 to your computer and use it in GitHub Desktop.
Building FAISS GPU for my laptop 1080 on Ubuntu WSL

January 11 2025 I recently upgraded to Ubuntu 12.10 (oracular) and tried all this again. Some settings needed to be changed:

  1. We're up to CUDA 12.5 now, but we also get GCC 14 with the latest ubuntu (I haven't tried any of this with clang). nvcc doesn't want anything above version 13, so you will want to sudo apt-get install g++-13 and then make sure nvcc and cmake know about it. Also, my attempts to adjust the C++ compiler did not affect the C compiler and it was still reporting version 14. I don't know if that would work, but I tried to also make it use version 13 also.

  2. I also wanted to use a version of python set by pyenv, but unsurprisingly I also had to specifically set where to look for python and numpy libs.

  3. Weirdly, I had to edit /usr/share/cmake-3.30/Modules/FindOpenMP.cmake. If your line 628 says something like:

            if(CMAKE_${LANG}_COMPILER_ID STREQUAL "Fujitsu"
          OR CMAKE_${LANG}_COMPILER_ID STREQUAL "IntelLLVM")

    you are fine, but mine had some extra dollar quoting after the OR which was upsetting to cmake.

  4. New since last time, I needed to sudo apt-get install libgflags-dev.

  5. After all this, I got a lot of linker errors when building some testing or perf benchmarks, so I switched from the main branch to the last release, v1.9.0 (which I should have done in the first place). I still got a ton of linker errors, so I didn't bother to run any tests and went straight to running the Python bindings, which worked.

  6. AVX CPU things were still a bit fiddly. Once again, I needed to sudo apt-get install libomp-dev and then run LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libmkl_def.so:/usr/lib/x86_64-linux-gnu/libmkl_avx2.so:/usr/lib/x86_64-linux-gnu/libmkl_core.so:/usr/lib/x86_64-linux-gnu/libmkl_intel_lp64.so:/usr/lib/x86_64-linux-gnu/libmkl_intel_thread.so:/usr/lib/x86_64-linux-gnu/libiomp5.so python to avoid the INTEL MKL ERROR: /lib/x86_64-linux-gnu/libmkl_avx2.so: undefined symbol: mkl_sparse_optimize_bsr_trsm_i8. Intel MKL FATAL ERROR: Cannot load libmkl_avx2.so or libmkl_def.so. error. I don't think this is unusual, I think most of that is supposed to go in your ~/.bashrc to use MKL anyway. I've had nothing but trouble trying to keep MKL working with both R and Python at once, so I am not that bothered about the CPU use any more. I would probably recommend building without MKL support at this point.

So the settings that worked for me lately are:

PYTHON_INCLUDE_DIR=$(python3 -c "import sysconfig; print(sysconfig.get_paths()['include'])")
PYTHON_LIBRARIES=$(python3 -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
NUMPY_INCLUDE_DIR=$(python3 -c "import numpy; print(numpy.get_include())")

cmake . -B build \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_POLICY_DEFAULT_CMP0135=NEW \
    -DFAISS_ENABLE_GPU=ON \
    -DFAISS_OPT_LEVEL=avx2 \
    -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc \
    -DCMAKE_CUDA_ARCHITECTURES="native" \
    -DBUILD_TESTING=ON \
    -DFAISS_ENABLE_PYTHON=ON \
    -DPython_INCLUDE_DIRS=$PYTHON_INCLUDE_DIR \
    -DPython_LIBRARIES=$PYTHON_LIBRARIES \
    -DPython_NumPy_INCLUDE_DIRS=$NUMPY_INCLUDE_DIR \
    -DCMAKE_C_COMPILER=/usr/bin/gcc-13 \
    -DCMAKE_CXX_COMPILER=/usr/bin/g++-13 \
    -DCMAKE_CUDA_HOST_COMPILER=/usr/bin/g++-13

June 28 2023 O frabjous day! After much fruitless occasional faffing around with cmake settings over the course of several months, new CUDA update for WSL Ubuntu means that I am now able to build the nearest neighbors library Faiss with GPU support for my 1080 laptop graphics card. Here is the setup that worked for me.

Why would you want to build your own Faiss? Well, if you are using pip to install faiss-gpu, you can't get anything more recent than version 1.7.2. Also, with recent dependency management changes with newer Pythons (particularly Python 3.11), some packages are going to be playing catch-up with getting up to parity, so it may be useful to build from source. I don't remember how bad it was trying to install faiss-gpu on Python 3.11 with pip, but it must have been fairly un-fun, because I gave up and scuttled back to the relatively welcoming environs of Python 3.10 pretty quickly after briefly dipping my toes in its waters. I think I saw this issue. Additionally, you may want to use e.g. Intel OMP or MKL or AVX2 support.

First you will need to carefully install CUDA for Ubuntu on WSL2: https://gist.github.com/jlmelville/d236b6eafb3067bfdac304274dc5cf83. This put cuda in /usr/local/cuda. Hopefully this is not a problem for anyone any more but until CUDA 12.2 hit nvidia's wsl-ubuntu repos, building Faiss successfully eluded me. I could build Faiss without errors, but many tests would fail. The python bindings would also build and run but trying to get exact Euclidean nearest neighbors via IndexFlatL2 would return all zeros for the distances (and unsurprisingly the actual IDs of the neighbors were also wrong).

Hopefully those days are in the past. If you run /usr/local/cuda/bin/nvcc --version and get:

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2023 NVIDIA Corporation
Built on Tue_Jun_13_19:16:58_PDT_2023
Cuda compilation tools, release 12.2, V12.2.91
Build cuda_12.2.r12.2/compiler.32965470_0

you should be ok.

Also to get the SWIG python bindings working, I installed the python3-dev and python3-numpy packages for the system python.

You probably also want the Intel MKL libraries installed, which made a much bigger difference for me (versus e.g. OpenBLAS) than having AVX2 on or not. However getting MKL and AVX2 to work together was a bit of work. If you have trouble with symbol lookup error: /lib/x86_64-linux-gnu/libmkl_intel_thread.so: undefined symbol: omp_get_num_procs the installing libomp-dev may help (https://www.yodiw.com/setup-numpy-with-oneapi-mkl-in-ubuntu/) and then I got some other issues about missing symbols, which took me to https://bugs.launchpad.net/ubuntu/+source/intel-mkl/+bug/1947626 and ended up doing things like:

export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libmkl_def.so:/usr/lib/x86_64-linux-gnu/libmkl_avx2.so:/usr/lib/x86_64-linux-gnu/libmkl_core.so:/usr/lib/x86_64-linux-gnu/libmkl_intel_lp64.so:/usr/lib/x86_64-linux-gnu/libmkl_intel_thread.so:/usr/lib/x86_64-linux-gnu/libiomp5.so

But it's also possible that I just really messed something up along the way and you won't run into that (or you just care about GPU support).

I then futzed about reading https://github.com/facebookresearch/faiss/blob/main/INSTALL.md, the CI settings and also https://github.com/kyamagu/faiss-wheels/blob/main/scripts/build_Linux.sh to find the right settings.

From CMake 3.18 it seems like you need to specify the CUDA architecture. I looked at https://arnon.dk/matching-sm-architectures-arch-and-gencode-for-various-nvidia-cards/ and https://developer.nvidia.com/cuda-gpus to find the right numbers for my GPU (which is a 1080). However, recently I found that setting CMAKE_CUDA_ARCHITECTURES="native" did the right thing. See also: https://gitlab.kitware.com/cmake/cmake/-/issues/22375.

cmake . -B build \
    -DFAISS_ENABLE_GPU=ON \
    -DFAISS_OPT_LEVEL=avx2 \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc \
    -DCMAKE_CUDA_ARCHITECTURES="native" \
    -DBUILD_TESTING=ON \
    -DFAISS_ENABLE_PYTHON=ON \
    -DCMAKE_POLICY_DEFAULT_CMP0135=NEW

You don't need to have the testing on if you are sure everything is working, but everything was definitely not working on WSL for the past few months, so I recommend you keep it. Also, you don't need the CMAKE_POLICY_DEFAULT_CMP0135 either, it just shuts up a warning that is intended for the Faiss developers (which may have been fixed by now but of course I wouldn't know).

Then to build and run tests:

cmake --build build --config Release -j4 && make -C build test

A couple of tests still fail (51 - MEM_LEAK.ivfflat and 165 - TestGpuMemoryException.AddException) but that's still a lot better than the 33 tests that failed before the CUDA update.

Next, build the SWIG bindings:

make -C build -j swigfaiss

And then, after activating the virtual environment I wanted to install Faiss into:

# or wherever you install faiss
cd ~/dev/faiss/build/faiss/python/
python setup.py install

I was then able to confirm that unlike the faiss-gpu wheel, I had version 1.7.4:

import faiss
faiss.__version__

and I got a log message Successfully loaded faiss with AVX2 support. whereas before I got Could not load library with AVX2 support due to: ModuleNotFoundError("No module named 'faiss.swigfaiss_avx2'"). Admittedly, most of the time I want the GPU usage rather than AVX2 and in the tests I ran I didn't see much difference in the AVX2 vs non-AVX2 case, but it's the principle of the thing.

Here's a basic CPU test, which I definitely took from the Faiss docs somewhere:

import faiss
import numpy as np

# Generate random data for indexing
d = 64  # Dimensionality of the vectors
nb = 1000  # Number of vectors
np.random.seed(0)
data = np.random.random((nb, d)).astype(np.float32)
index = faiss.IndexFlatL2(d)  # L2 distance metric
index.add(data)
index.search(data, 5)

And here is the equivalent GPU test:

import faiss
import numpy as np

# Generate random data for indexing
d = 64  # Dimensionality of the vectors
nb = 1000  # Number of vectors
np.random.seed(0)
data = np.random.random((nb, d)).astype(np.float32)
res = faiss.StandardGpuResources()  # Create GPU resources object
index = faiss.IndexFlatL2(d)  # L2 distance metric
gpu_index = faiss.index_cpu_to_gpu(res, 0, index)  # Move index to GPU
gpu_index.add(data)
distances_gpu, indices_gpu = gpu_index.search(data, 5)
distances = distances_gpu.copy()
indices = indices_gpu.copy()
distances, indices

You should get the same results as with the CPU version. If not, something has gone horribly wrong. As noted above, in my case it was a problem with CUDA for WSL itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment