Recherche efficace de similarité vectorielle dans les workflows de recommandation avec Milvus et NVIDIA Merlin
Cet article a été publié pour la première fois sur la chaîne Medium de NVIDIA Merlin, puis modifié et republié ici avec autorisation. Il a été rédigé conjointement par Burcin Bozkaya et William Hicks de NVIDIA, ainsi que par Filip Haltmayer et Li Liu de Zilliz.
Introduction
Les systèmes de recommandation modernes (Recsys) se composent de pipelines d’entraînement/inférence impliquant plusieurs étapes d’ingestion des données, de prétraitement des données, d’entraînement de modèles et d’optimisation des hyperparamètres pour la récupération, le filtrage, le classement et la notation des éléments pertinents. Un composant essentiel d’un pipeline de système de recommandation est la récupération ou la découverte des éléments les plus pertinents pour un utilisateur, en particulier en présence de vastes catalogues d’articles. Cette étape implique généralement une recherche de plus proche voisin approximatif (ANN) dans une base de données indexée de représentations vectorielles de faible dimension (c.-à-d. des embeddings) des attributs des produits et des utilisateurs, créées à partir de modèles d’apprentissage profond entraînés sur les interactions entre les utilisateurs et les produits/services.
NVIDIA Merlin, un framework open source développé pour entraîner des modèles de bout en bout afin de produire des recommandations à n’importe quelle échelle, s’intègre à un framework efficace d’indexation et de recherche de base de données vectorielle. L’un de ces frameworks qui a récemment suscité beaucoup d’attention est Milvus, une base de données vectorielle open source créée par Zilliz. Elle offre des capacités rapides d’indexation et de requête. Milvus a récemment ajouté une prise en charge de l’accélération GPU qui utilise les GPU NVIDIA pour soutenir les workflows d’IA. La prise en charge de l’accélération GPU est une excellente nouvelle, car une bibliothèque de recherche vectorielle accélérée rend possibles des requêtes simultanées rapides, ce qui a un impact positif sur les exigences de latence des systèmes de recommandation actuels, où les développeurs s’attendent à de nombreuses requêtes concurrentes. Milvus compte plus de 5 millions de téléchargements Docker, environ 23 000 étoiles sur GitHub (en septembre 2023), plus de 5 000 clients Entreprise, et constitue un composant central de nombreuses applications (voir les cas d’utilisation).
Ce blog montre comment Milvus fonctionne avec le framework Merlin Recsys lors de l’entraînement et de l’inférence. Nous montrons comment Milvus complète Merlin à l’étape de récupération des éléments grâce à une recherche très efficace des top-k embeddings vectoriels, et comment il peut être utilisé avec NVIDIA Triton Inference Server (TIS) au moment de l’inférence (voir Figure 1). Nos résultats de benchmark montrent une accélération impressionnante de 37x à 91x avec Milvus accéléré par GPU, qui utilise NVIDIA RAFT avec les embeddings vectoriels générés par Merlin Models. Le code que nous utilisons pour montrer l’intégration Merlin-Milvus et les résultats détaillés des benchmarks, ainsi que la bibliothèque qui a facilité notre étude de benchmark, sont disponibles ici.
Figure 1. Système de recommandation multi-étapes avec le framework Milvus contribuant à l’étape de récupération. Source de la figure multi-étapes originale : cet article de blog.
Les défis auxquels sont confrontés les systèmes de recommandation
Compte tenu de la nature multiétape des systèmes de recommandation et de la disponibilité des divers composants et bibliothèques qu’ils intègrent, un défi majeur consiste à intégrer tous les composants de manière fluide dans un pipeline de bout en bout. Nous souhaitons montrer que l’intégration peut être réalisée avec moins d’efforts dans nos notebooks d’exemple.
Un autre défi des workflows de recommandation consiste à accélérer certaines parties du pipeline. Bien qu’ils soient connus pour jouer un rôle majeur dans l’entraînement de grands réseaux neuronaux, les GPU ne sont que récemment apparus dans les bases de données vectorielles et la recherche ANN. Avec l’augmentation de la taille des catalogues de produits e-commerce ou des bases de données de médias en streaming et du nombre d’utilisateurs de ces services, les CPU doivent fournir les performances nécessaires pour servir des millions d’utilisateurs dans des workflows Recsys performants. L’accélération GPU dans d’autres parties du pipeline est devenue nécessaire pour relever ce défi. La solution présentée dans ce blog répond à ce défi en montrant que la recherche ANN est efficace lorsqu’on utilise des GPU.
Piles technologiques pour la solution
Commençons par examiner certains des fondamentaux nécessaires à la réalisation de notre travail.
NVIDIA Merlin : une bibliothèque open source avec des API de haut niveau accélérant les systèmes de recommandation sur les GPU NVIDIA.
NVTabular : pour le prétraitement des données tabulaires d’entrée et l’ingénierie des caractéristiques.
Merlin Models : pour l’entraînement de modèles de deep learning et pour apprendre, dans ce cas, les vecteurs d’embedding utilisateur et article à partir des données d’interaction utilisateur.
Merlin Systems : pour combiner un modèle de recommandation basé sur TensorFlow avec d’autres éléments (p. ex., feature store, recherche ANN avec Milvus) afin d’être servi avec TIS.
Triton Inference Server : pour l’étape d’inférence où un vecteur de caractéristiques utilisateur est transmis et où des recommandations de produits sont générées.
Conteneurisation : tout ce qui précède est disponible via le ou les conteneurs fournis par NVIDIA dans le catalogue NGC. Nous avons utilisé le conteneur Merlin TensorFlow 23.06.
Milvus 2.3 : pour effectuer l’indexation et l’interrogation vectorielles accélérées par GPU.
Milvus 2.2.11 : identique à ce qui précède, mais pour le faire sur CPU.
Pymilvus SDK : pour se connecter au serveur Milvus, créer des index de base de données vectorielle et exécuter des requêtes via une interface Python.
Feast : pour enregistrer et récupérer les attributs utilisateur et article dans un feature store (open source) dans le cadre de notre pipeline RecSys de bout en bout.
Plusieurs bibliothèques et frameworks sous-jacents sont également utilisés en coulisses. Par exemple, Merlin s’appuie sur d’autres bibliothèques NVIDIA, telles que cuDF et Dask, toutes deux disponibles dans RAPIDS cuDF. De même, Milvus s’appuie sur NVIDIA RAFT pour les primitives d’accélération GPU et sur des bibliothèques modifiées telles que HNSW et FAISS pour la recherche.
Comprendre les bases de données vectorielles et Milvus
La recherche approximative du plus proche voisin (ANN) est une fonctionnalité que les bases de données relationnelles ne peuvent pas gérer. Les bases de données relationnelles sont conçues pour gérer des données tabulaires avec des structures prédéfinies et des valeurs directement comparables. Les index des bases de données relationnelles s’appuient sur cela pour comparer les données et créer des structures qui tirent parti du fait de savoir si chaque valeur est inférieure ou supérieure à l’autre. Les vecteurs d’embedding ne peuvent pas être directement comparés entre eux de cette manière, car nous devons savoir ce que représente chaque valeur du vecteur. Ils ne peuvent pas indiquer si un vecteur est nécessairement inférieur à l’autre. La seule chose que nous pouvons faire est de calculer la distance entre les deux vecteurs. Si la distance entre deux vecteurs est faible, nous pouvons supposer que les caractéristiques qu’ils représentent sont similaires, et si elle est grande, nous pouvons supposer que les données qu’ils représentent sont plus différentes. Cependant, ces index efficaces ont un coût ; calculer la distance entre deux vecteurs est coûteux en calcul, et les index vectoriels ne sont pas facilement adaptables et parfois non modifiables. En raison de ces deux limitations, l’intégration de ces index est plus complexe dans les bases de données relationnelles, c’est pourquoi des bases de données vectorielles conçues à cet effet sont nécessaires.
Milvus a été créé pour résoudre les problèmes que les bases de données relationnelles rencontrent avec les vecteurs et a été conçu dès le départ pour gérer ces vecteurs d’embedding et leurs index à grande échelle. Pour satisfaire au qualificatif cloud-native, Milvus sépare le calcul et le stockage ainsi que les différentes tâches de calcul — interrogation, préparation des données et indexation. Les utilisateurs peuvent faire évoluer chaque partie de la base de données pour gérer d’autres cas d’utilisation, qu’il s’agisse de charges fortement axées sur l’insertion de données ou sur la recherche. S’il y a un afflux important de requêtes d’insertion, l’utilisateur peut temporairement faire évoluer les nœuds d’index horizontalement et verticalement pour gérer l’ingestion. De même, si aucune donnée n’est ingérée, mais qu’il y a de nombreuses recherches, l’utilisateur peut réduire les nœuds d’index et, à la place, augmenter les nœuds de requête pour obtenir un débit plus élevé. Cette conception du système (voir Figure 2) nous a obligés à adopter une approche de calcul parallèle, ce qui a donné lieu à un système optimisé pour le calcul, avec de nombreuses possibilités d’optimisations supplémentaires.
Figure 2. Conception du système Milvus
Milvus utilise également de nombreuses bibliothèques d’indexation de pointe afin d’offrir aux utilisateurs le plus de personnalisation possible pour leur système. Il les améliore en ajoutant la capacité de gérer les opérations CRUD, les données en streaming et le filtrage. Plus loin, nous discuterons de la manière dont ces index diffèrent ainsi que des avantages et inconvénients de chacun.
Exemple de solution : intégration de Milvus et Merlin
L’exemple de solution que nous présentons ici démontre l’intégration de Milvus avec Merlin à l’étape de récupération des items (lorsque les k items les plus pertinents sont récupérés au moyen d’une recherche ANN). Nous utilisons un jeu de données réel issu d’un défi RecSys, décrit ci-dessous. Nous entraînons un modèle d’apprentissage profond Two-Tower qui apprend des embeddings vectoriels pour les utilisateurs et les items. Cette section fournit également le plan de notre travail de benchmarking, y compris les métriques que nous collectons et la plage de paramètres que nous utilisons.
Notre approche comprend :
Ingestion et prétraitement des données
Entraînement d’un modèle d’apprentissage profond Two-Tower
Construction d’index Milvus
Recherche de similarité Milvus
Nous décrivons brièvement chaque étape et renvoyons le lecteur à nos notebooks pour plus de détails.
Jeu de données
YOOCHOOSE GmbH fournit le jeu de données que nous utilisons dans cette étude d’intégration et de benchmark pour le défi RecSys 2015 et qui est disponible sur Kaggle. Il contient des événements de clic/achat d’utilisateurs provenant d’un détaillant en ligne européen, avec des attributs tels qu’un ID de session, un horodatage, l’ID de l’article associé au clic/achat et la catégorie de l’article, disponibles dans le fichier yoochoose-clicks.dat. Les sessions sont indépendantes, et rien n’indique que des utilisateurs reviennent, nous considérons donc chaque session comme appartenant à un utilisateur distinct. Le jeu de données compte 9,249,729 sessions uniques (utilisateurs) et 52,739 articles uniques.
Ingestion et prétraitement des données
L’outil que nous utilisons pour le prétraitement des données est NVTabular, un composant d’ingénierie des caractéristiques et de prétraitement de Merlin, accéléré par GPU et hautement évolutif. Nous utilisons NVTabular pour lire les données dans la mémoire GPU, réorganiser les caractéristiques si nécessaire, exporter vers des fichiers parquet et créer une séparation entraînement-validation pour l’entraînement. Cela donne 7,305,761 utilisateurs uniques et 49,008 articles uniques pour l’entraînement. Nous catégorisons également chaque colonne et ses valeurs en valeurs entières. Le jeu de données est maintenant prêt pour l’entraînement avec le modèle Two-Tower.
Entraînement du modèle
Nous utilisons le modèle d’apprentissage profond Two-Tower pour entraîner et générer des embeddings d’utilisateurs et d’articles, utilisés ensuite pour l’indexation et l’interrogation vectorielles. Après l’entraînement du modèle, nous pouvons extraire les embeddings d’utilisateurs et d’articles.
Les deux étapes suivantes sont facultatives : un modèle DLRM entraîné pour classer les articles récupérés à des fins de recommandation et un feature store utilisé (dans ce cas, Feast) pour stocker et récupérer les caractéristiques des utilisateurs et des articles. Nous les incluons pour l’exhaustivité du flux de travail multi-étapes.
Enfin, nous exportons les embeddings d’utilisateurs et d’articles vers des fichiers parquet, qui peuvent ensuite être rechargés pour créer un index vectoriel Milvus.
Création et interrogation de l’index Milvus
Milvus facilite l’indexation vectorielle et la recherche de similarité via un « serveur » lancé sur la machine d’inférence. Dans notre notebook #2, nous le configurons en installant via pip le serveur Milvus et Pymilvus, puis en démarrant le serveur avec son port d’écoute par défaut. Ensuite, nous démontrons la création d’un index simple (IVF_FLAT) et son interrogation à l’aide des fonctions setup_milvus et query_milvus, respectivement.
Benchmarking
Nous avons conçu deux benchmarks pour démontrer l’intérêt d’utiliser une bibliothèque d’indexation/recherche vectorielle rapide et efficace telle que Milvus.
Utiliser Milvus pour créer des index vectoriels avec les deux ensembles d’embeddings que nous avons générés : 1) embeddings d’utilisateurs pour 7.3M utilisateurs uniques, divisés en 85 % ensemble d’entraînement (pour l’indexation) et 15 % ensemble de test (pour l’interrogation), et 2) embeddings d’articles pour 49K produits (avec une répartition entraînement-test 50–50). Ce benchmark est réalisé indépendamment pour chaque jeu de données vectoriel, et les résultats sont rapportés séparément.
Utiliser Milvus pour créer un index vectoriel pour le jeu de données des embeddings des 49K articles et interroger les 7.3M utilisateurs uniques par rapport à cet index pour une recherche de similarité.
Dans ces benchmarks, nous avons utilisé les algorithmes d’indexation IVFPQ et HNSW exécutés sur GPU et CPU, avec diverses combinaisons de paramètres. Les détails sont disponibles sur notre page GitHub.
Le compromis entre qualité de recherche et débit est une considération importante en matière de performance, en particulier dans un environnement de production. Milvus permet un contrôle complet des paramètres d’indexation afin d’explorer ce compromis pour un cas d’utilisation donné et d’obtenir de meilleurs résultats de recherche avec la vérité terrain. Cela peut signifier une augmentation du coût de calcul sous la forme d’un débit réduit ou de requêtes par seconde (QPS). Nous mesurons la qualité de la recherche ANN avec une métrique de rappel et fournissons des courbes QPS-rappel qui démontrent le compromis. On peut alors décider d’un niveau acceptable de qualité de recherche compte tenu des ressources de calcul ou des exigences de latence/débit du cas métier.
Notez également la taille du lot de requêtes (nq) utilisée dans nos benchmarks. Cela est utile dans les workflows où plusieurs requêtes simultanées sont envoyées à l’inférence (par exemple, des recommandations hors ligne demandées et envoyées à une liste de destinataires d’e-mails ou des recommandations en ligne créées en regroupant des requêtes concurrentes arrivant et en les traitant toutes en même temps). Selon le cas d’utilisation, TIS peut également aider à traiter ces requêtes par lots.
Résultats
Nous présentons maintenant les résultats des trois ensembles de benchmarks sur CPU et GPU, en utilisant les types d’index HNSW (CPU uniquement) et IVF_PQ (CPU et GPU) implémentés par Milvus.
Recherche de similarité vectorielle Articles vs. Articles
Avec ce plus petit jeu de données, chaque exécution pour une combinaison de paramètres donnée prend 50 % des vecteurs d’articles comme vecteurs de requête et interroge les 100 vecteurs les plus similaires parmi le reste. HNSW et IVF_PQ produisent un rappel élevé avec les paramètres testés, dans les plages 0,958–1,0 et 0,665–0,997, respectivement. Ce résultat suggère que HNSW est plus performant en termes de rappel, mais qu’IVF_PQ avec de faibles paramètres nlist produit un rappel très comparable. Nous devons également noter que les valeurs de rappel peuvent varier considérablement en fonction des paramètres d’indexation et d’interrogation. Les valeurs que nous rapportons ont été obtenues après une expérimentation préliminaire avec des plages de paramètres générales et un zoom supplémentaire sur un sous-ensemble sélectionné.
Le temps total d’exécution de toutes les requêtes sur CPU avec HNSW pour une combinaison de paramètres donnée varie entre 5,22 et 5,33 s (plus rapide lorsque m augmente, relativement inchangé avec ef) et avec IVF_PQ entre 13,67 et 14,67 s (plus lent lorsque nlist et nprobe augmentent). L’accélération GPU a effectivement un effet notable, comme le montre la Figure 3.
La Figure 3 montre le compromis rappel-débit sur toutes les exécutions réalisées sur CPU et GPU avec ce petit jeu de données en utilisant IVF_PQ. Nous constatons que le GPU offre une accélération de 4x à 15x sur toutes les combinaisons de paramètres testées (accélération plus importante lorsque nprobe augmente). Cela est calculé en prenant le ratio du QPS des exécutions GPU sur le QPS des exécutions CPU pour chaque combinaison de paramètres. Globalement, cet ensemble présente peu de défi pour le CPU ou le GPU et montre des perspectives d’accélération supplémentaire avec les jeux de données plus volumineux, comme indiqué ci-dessous.
Figure 3. Accélération GPU avec l’algorithme Milvus IVF_PQ exécuté sur GPU NVIDIA A100 (recherche de similarité article-article)
Recherche de similarité vectorielle Utilisateurs vs. Utilisateurs
Avec le deuxième jeu de données beaucoup plus volumineux (7,3 M d’utilisateurs), nous mettons de côté 85 % (~6,2 M) des vecteurs comme “train” (l’ensemble de vecteurs à indexer), et les 15 % restants (~1,1 M) comme ensemble de vecteurs “test” ou de requête. HNSW et IVF_PQ fonctionnent exceptionnellement bien dans ce cas, avec des valeurs de rappel de 0,884–1,0 et 0,922–0,999, respectivement. Ils sont toutefois beaucoup plus exigeants en calcul, en particulier avec IVF_PQ sur le CPU. Le temps total d’exécution de toutes les requêtes sur CPU avec HNSW varie de 279,89 à 295,56 s et avec IVF_PQ de 3082,67 à 10932,33 s. Notez que ces temps de requête sont cumulatifs pour 1,1 M de vecteurs interrogés, on peut donc dire qu’une seule requête sur l’index reste très rapide.
Cependant, l’interrogation basée sur CPU peut ne pas être viable si le serveur d’inférence s’attend à ce que plusieurs milliers de requêtes concurrentes exécutent des requêtes sur un inventaire de millions d’articles.
Le GPU A100 offre une accélération fulgurante de 37x à 91x (76,1x en moyenne) pour toutes les combinaisons de paramètres avec IVF_PQ en termes de débit (QPS), comme le montre la Figure 4. Cela correspond à ce que nous avons observé avec le petit jeu de données, ce qui suggère que les performances du GPU évoluent raisonnablement bien avec Milvus et des millions de vecteurs d’embedding.
Figure 4. Accélération GPU avec l’algorithme Milvus IVF_PQ s’exécutant sur un GPU NVIDIA A100 (recherche de similarité utilisateur-utilisateur)
La Figure 5 détaillée suivante montre le compromis rappel-QPS pour toutes les combinaisons de paramètres testées sur CPU et GPU avec IVF_PQ. Chaque ensemble de points (en haut pour le GPU, en bas pour le CPU) sur ce graphique illustre le compromis auquel on est confronté lorsque l’on modifie les paramètres d’indexation/requête vectoriels afin d’atteindre un rappel plus élevé au prix d’un débit plus faible. Notez la perte considérable de QPS dans le cas du GPU lorsque l’on tente d’atteindre des niveaux de rappel plus élevés.
Figure 5. Compromis rappel-débit pour toutes les combinaisons de paramètres testées sur CPU et GPU avec IVF_PQ (utilisateurs vs. utilisateurs)
Recherche de similarité vectorielle utilisateurs vs. articles
Enfin, nous examinons un autre cas d’utilisation réaliste où les vecteurs utilisateurs sont interrogés par rapport aux vecteurs articles (comme démontré dans le Notebook 01 ci-dessus). Dans ce cas, 49K vecteurs d’articles sont indexés, et 7,3M vecteurs utilisateurs sont chacun interrogés pour obtenir les 100 articles les plus similaires.
C’est là que les choses deviennent intéressantes, car interroger 7,3M en lots de 1000 par rapport à un index de 49K articles semble chronophage sur CPU, tant pour HNSW que pour IVF_PQ. Le GPU semble mieux gérer ce cas (voir Figure 6). Les niveaux de précision les plus élevés obtenus par IVF_PQ sur CPU lorsque nlist = 100 sont calculés en environ 86 minutes en moyenne, mais varient considérablement à mesure que la valeur de nprobe augmente (51 min. lorsque nprobe = 5 contre 128 min. lorsque nprobe = 20). Le GPU NVIDIA A100 accélère considérablement les performances d’un facteur 4x à 17x (accélérations plus élevées à mesure que nprobe augmente). N’oubliez pas que l’algorithme IVF_PQ, grâce à sa technique de quantification, réduit également l’empreinte mémoire et fournit une solution de recherche ANN viable sur le plan computationnel lorsqu’elle est combinée à l’accélération GPU.
Figure 6. Accélération GPU avec l’algorithme Milvus IVF_PQ s’exécutant sur un GPU NVIDIA A100 (recherche de similarité utilisateur-article)
Comme pour la Figure 5, le compromis rappel-débit est présenté dans la Figure 7 pour toutes les combinaisons de paramètres testées avec IVF_PQ. Ici, on peut encore voir qu’il peut être nécessaire de sacrifier légèrement une certaine précision de la recherche ANN au profit d’un débit accru, bien que les différences soient beaucoup moins perceptibles, en particulier dans le cas des exécutions sur GPU. Cela suggère que l’on peut s’attendre à des niveaux de performances computationnelles relativement élevés et constants avec le GPU, tout en atteignant un rappel élevé.
Figure 7. Compromis rappel-débit pour toutes les combinaisons de paramètres testées sur CPU et GPU avec IVF_PQ (utilisateurs vs. articles)
Conclusion
Nous serions heureux de partager quelques remarques finales si vous êtes arrivé jusqu’ici. Nous voulons vous rappeler que la complexité et la nature multi-étapes des Recsys modernes nécessitent performance et efficacité à chaque étape. Nous espérons que ce blog vous a donné des raisons convaincantes d’envisager l’utilisation de deux fonctionnalités essentielles dans vos pipelines RecSys :
La bibliothèque Merlin Systems de NVIDIA Merlin vous permet d’intégrer facilement Milvus, un moteur de recherche vectorielle efficace accéléré par GPU.
Utilisez le GPU pour accélérer les calculs liés à l’indexation des bases de données vectorielles et à la recherche ANN avec une technologie telle que RAPIDS RAFT.
Ces résultats suggèrent que l’intégration Merlin-Milvus présentée est très performante et bien moins complexe que d’autres options pour l’entraînement et l’inférence. De plus, les deux frameworks sont activement développés, et de nombreuses nouvelles fonctionnalités (par exemple, de nouveaux index de bases de données vectorielles accélérés par GPU par Milvus) sont ajoutées à chaque version. Le fait que la recherche de similarité vectorielle soit un composant crucial dans divers workflows, tels que la vision par ordinateur, la modélisation de grands modèles de langage et les systèmes de recommandation, rend cet effort d’autant plus précieux.
Pour conclure, nous tenons à remercier toutes les personnes de Zilliz/Milvus, de Merlin et des équipes RAFT qui ont contribué à l’effort ayant permis de produire ce travail et cet article de blog. Nous avons hâte d’avoir de vos nouvelles, si vous avez l’occasion d’implémenter Merlin et Milvus dans vos recsys ou autres workflows.
Continuer à lire
Stop Building AI Data Infra for the Wrong Stage
Learn how AI data infrastructure should evolve from prototype to enterprise scale, and when Vector Lakebase becomes the right architecture for AI apps.

Why Teams Are Migrating from Weaviate to Zilliz Cloud — and How to Do It Seamlessly
Explore how Milvus scales for large datasets and complex queries with advanced features, and discover how to migrate from Weaviate to Zilliz Cloud.

Announcing the General Availability of Single Sign-On (SSO) on Zilliz Cloud
SSO is GA on Zilliz Cloud, delivering the enterprise-grade identity management capabilities your teams need to deploy vectorDB with confidence.



