Vector Databases

FAISS sur GPU : Optimisation de l'indexation et de la latence de recherche pour les grands clusters d'embeddings

À mesure que le volume de données non structurées augmente, la complexité de la recherche de similarité vectorielle s'accroît. Pour de nombreux développeurs, la migration depuis des implémentations basées sur le CPU vers des solutions accélérées par GPU comme Facebook AI Similarity Search (FAISS) est l'étape décisive pour faire évoluer les bases de données vectorielles. Cependant, se contenter de déplacer les données sur un GPU ne suffit pas ; sans une configuration soignée des stratégies d'indexation et de la gestion de la mémoire, vous risquez de rencontrer des goulets d'étranglement qui annulent les avantages matériels.

Dans ce guide, nous allons explorer comment optimiser FAISS sur GPU, tant pour la vitesse d'indexation que pour la latence de recherche, en ciblant spécifiquement les grands clusters d'embeddings contenant des millions de vecteurs.

Comprendre la structure d'index accélérée par GPU

FAISS propose plusieurs types d'index optimisés pour différentes contraintes matérielles. Sur le GPU, les structures les plus courantes sont IndexFlatGPU pour la recherche exacte par force brute et IndexIVFPQ (Fichier inversé avec quantification de produit) pour la recherche de plus proches voisins approximatifs (ANN). Bien que la recherche exacte garantisse la précision, elle évolue linéairement avec la taille du jeu de données, ce qui la rend impraticable pour des millions de vecteurs. Les index ANN, en revanche, sacrifient une petite partie du rappel au profit de gains significatifs en latence et en efficacité mémoire.

Configuration des ressources GPU

Avant de créer un index, vous devez allouer explicitement les ressources GPU. Cela garantit que FAISS a accès au contexte CUDA correct et aux limites de mémoire.


import faiss
import numpy as np

# Initialiser le gestionnaire de ressources GPU
res = faiss.StandardGpuResources()

# Jeu de données d'exemple : 1 million de vecteurs de dimension 384
d = 384
n = 1_000_000
np.random.seed(1234)
xb = np.random.random((n, d)).astype('float32')
faiss.normalize_L2(xb) # Normaliser les vecteurs pour la similarité cosinus

Optimisation de la création de l'index

Lors de la construction d'un index IVFPQ sur le GPU, le nombre de clusters (nlist) est un hyperparamètre critique. Une règle empirique courante consiste à définir nlist approximativement à la racine carrée du nombre de vecteurs, bien que cela doive être ajusté en fonction de vos exigences spécifiques de rappel.


# Créer un index IVFPQ
nlist = 1024
pq = faiss.ProductQuantizer(d, 64, 8) # 64 sous-vecteurs, 8 bits chacun
index = faiss.IndexIVFPQ(res, d, nlist, pq)

# Ajouter les données d'entraînement pour construire le regroupement
index.train(xb)
index.add(xb)

# Copier l'index sur le GPU
index_gpu = faiss.index_cpu_to_gpu(res, 0, index)

Réglage de la latence de recherche

Une fois l'index sur le GPU, les performances de recherche sont fortement influencées par le nombre de sondes (nprobe). Augmenter nprobe améliore le rappel mais augmente la latence. Pour les environnements de production, vous devez profiler ce paramètre pour trouver le point optimal où votre SLA (Service Level Agreement) de latence est respecté avec un rappel acceptable.


# Définir le nombre de sondes pour la recherche
index_gpu.nprobe = 32

# Effectuer une recherche des 10 plus proches voisins pour 100 requêtes
xq = np.random.random((100, d)).astype('float32')
faiss.normalize_L2(xq)

D, I = index_gpu.search(xq, 10)
print(f"Recherche terminée. Premier voisin pour la requête 0 : {I[0]}")

Meilleures pratiques pour les grands clusters

  • Batching : Traitez toujours les vecteurs par lots pour éviter le débordement de mémoire. FAISS sur GPU est le plus efficace lorsque les lots sont assez grands pour exploiter le parallélisme du GPU, mais assez petits pour tenir dans la VRAM.
  • Memory Mapping : Pour les index trop volumineux pour la mémoire GPU, envisagez d'utiliser les fonctionnalités hybrides CPU-GPU de FAISS ou de décharger les données non critiques vers la RAM CPU avec IndexIVFScalarQuantizer.
  • Précision : Assurez-vous que vos données d'entrée sont en précision float32. La conversion entre float64 et float32 ajoute une surcharge inutile lors de la phase de recherche.

Conclusion

L'exploitation de FAISS sur GPU peut transformer votre infrastructure de recherche vectorielle d'un goulet d'étranglement en un moteur haute performance. En sélectionnant soigneusement le type d'index approprié, en ajustant les paramètres de cluster et en gérant les ressources mémoire, vous pouvez atteindre des latences inférieures à la milliseconde même avec des jeux de données massifs. À mesure que la recherche vectorielle devient centrale dans les applications d'IA, la maîtrise de ces optimisations est essentielle pour construire des systèmes évolutifs et réactifs.

Share: