Ricerca efficiente della similarità vettoriale nei flussi di lavoro dei sistemi di raccomandazione utilizzando Milvus con NVIDIA Merlin
Questo post è stato pubblicato per la prima volta sul canale Medium di NVIDIA Merlin, modificato e ripubblicato qui con autorizzazione. È stato scritto congiuntamente da Burcin Bozkaya e William Hicks di NVIDIA e da Filip Haltmayer e Li Liu di Zilliz.
Introduzione
I moderni sistemi di raccomandazione (Recsys) consistono in pipeline di training/inferenza che coinvolgono più fasi di acquisizione dei dati, preelaborazione dei dati, training del modello e ottimizzazione degli iperparametri per il recupero, il filtraggio, il ranking e l’assegnazione di punteggi agli elementi pertinenti. Un componente essenziale di una pipeline di un sistema di raccomandazione è il recupero o la scoperta degli elementi più pertinenti per un utente, in particolare in presenza di grandi cataloghi di articoli. Questo passaggio in genere comporta una ricerca approximate nearest neighbor (ANN) su un database indicizzato di rappresentazioni vettoriali a bassa dimensionalità (cioè embedding) degli attributi di prodotti e utenti creati da modelli di deep learning che si addestrano sulle interazioni tra utenti e prodotti/servizi.
NVIDIA Merlin, un framework open-source sviluppato per addestrare modelli end-to-end per fornire raccomandazioni a qualsiasi scala, si integra con un framework efficiente di indicizzazione e ricerca per database vettoriali. Uno di questi framework che ha recentemente attirato molta attenzione è Milvus, un database vettoriale open-source creato da Zilliz. Offre capacità rapide di indicizzazione e query. Milvus ha recentemente aggiunto il supporto all’accelerazione GPU, che utilizza GPU NVIDIA per sostenere i workflow di AI. Il supporto all’accelerazione GPU è un’ottima notizia perché una libreria di ricerca vettoriale accelerata rende possibili query concorrenti rapide, con un impatto positivo sui requisiti di latenza nei sistemi di raccomandazione odierni, dove gli sviluppatori si aspettano molte richieste concorrenti. Milvus ha oltre 5M di pull Docker, ~23k stelle su GitHub (a settembre 2023), oltre 5.000 clienti Enterprise ed è un componente fondamentale di molte applicazioni (vedi casi d’uso).
Questo blog dimostra come Milvus funzioni con il framework Recsys Merlin in fase di training e di inferenza. Mostriamo come Milvus integri Merlin nella fase di recupero degli elementi con una ricerca top-k altamente efficiente degli embedding vettoriali e come possa essere utilizzato con NVIDIA Triton Inference Server (TIS) in fase di inferenza (vedi Figura 1). I nostri risultati di benchmark mostrano un impressionante speedup da 37x a 91x con Milvus accelerato da GPU, che utilizza NVIDIA RAFT con gli embedding vettoriali generati da Merlin Models. Il codice che utilizziamo per mostrare l’integrazione Merlin-Milvus e i risultati dettagliati del benchmark, insieme alla libreria che ha facilitato il nostro studio di benchmark, sono disponibili qui.
Figura 1. Sistema di raccomandazione multistadio con il framework Milvus che contribuisce alla fase di recupero. Fonte della figura multistadio originale: questo post del blog.
Le sfide che i sistemi di raccomandazione devono affrontare
Data la natura multistadio dei sistemi di raccomandazione e la disponibilità di vari componenti e librerie che integrano, una sfida significativa è integrare tutti i componenti in modo fluido in una pipeline end-to-end. Vogliamo mostrare che l’integrazione può essere realizzata con meno sforzo nei nostri notebook di esempio.
Un’altra sfida dei workflow dei sistemi di raccomandazione è accelerare determinate parti della pipeline. Sebbene siano note per svolgere un ruolo enorme nell’addestramento di grandi reti neurali, le GPU sono aggiunte solo recenti ai database vettoriali e alla ricerca ANN. Con l’aumento delle dimensioni degli inventari di prodotti e-commerce o dei database di media in streaming e del numero di utenti che utilizzano questi servizi, le CPU devono fornire le prestazioni richieste per servire milioni di utenti in workflow Recsys performanti. L’accelerazione GPU in altre parti della pipeline è diventata necessaria per affrontare questa sfida. La soluzione in questo blog affronta questa sfida mostrando che la ricerca ANN è efficiente quando si utilizzano le GPU.
Stack tecnologici per la soluzione
Iniziamo esaminando prima alcuni dei fondamenti necessari per svolgere il nostro lavoro.
NVIDIA Merlin: una libreria open-source con API di alto livello che accelerano i sistemi di raccomandazione su GPU NVIDIA.
NVTabular: per il pre-processing dei dati tabulari di input e il feature engineering.
Merlin Models: per l’addestramento di modelli di deep learning e per apprendere, in questo caso, vettori di embedding di utenti e item dai dati di interazione degli utenti.
Merlin Systems: per combinare un modello di raccomandazione basato su TensorFlow con altri elementi (ad es., feature store, ricerca ANN con Milvus) da servire con TIS.
Triton Inference Server: per la fase di inferenza in cui viene passato un vettore di feature dell’utente e vengono generate raccomandazioni di prodotti.
Containerizzazione: tutto quanto sopra è disponibile tramite container forniti da NVIDIA nel catalogo NGC. Abbiamo utilizzato il container Merlin TensorFlow 23.06.
Milvus 2.3: per condurre indicizzazione vettoriale e interrogazioni accelerate da GPU.
Milvus 2.2.11: come sopra, ma per farlo su CPU.
Pymilvus SDK: per connettersi al server Milvus, creare indici di database vettoriali ed eseguire query tramite un’interfaccia Python.
Feast: per salvare e recuperare attributi di utenti e item in un feature store (open source) come parte della nostra pipeline RecSys end-to-end.
Diverse librerie e framework sottostanti vengono utilizzati anche sotto il cofano. Ad esempio, Merlin si basa su altre librerie NVIDIA, come cuDF e Dask, entrambe disponibili in RAPIDS cuDF. Allo stesso modo, Milvus si basa su NVIDIA RAFT per primitive sull’accelerazione GPU e su librerie modificate come HNSW e FAISS per la ricerca.
Comprendere i database vettoriali e Milvus
Approximate nearest neighbor (ANN) è una funzionalità che i database relazionali non possono gestire. I DB relazionali sono progettati per gestire dati tabulari con strutture predefinite e valori direttamente confrontabili. Gli indici dei database relazionali si basano su questo per confrontare i dati e creare strutture che sfruttano la possibilità di sapere se ciascun valore è minore o maggiore dell’altro. I vettori di embedding non possono essere confrontati direttamente tra loro in questo modo, poiché dobbiamo sapere che cosa rappresenta ciascun valore nel vettore. Non possono dire se un vettore sia necessariamente minore dell’altro. L’unica cosa che possiamo fare è calcolare la distanza tra i due vettori. Se la distanza tra due vettori è piccola, possiamo presumere che le caratteristiche che rappresentano siano simili, e se è grande, possiamo presumere che i dati che rappresentano siano più diversi. Tuttavia, questi indici efficienti hanno un costo; calcolare la distanza tra due vettori è computazionalmente costoso e gli indici vettoriali non sono facilmente adattabili e talvolta non modificabili. A causa di queste due limitazioni, integrare questi indici è più complesso nei database relazionali, motivo per cui sono necessari database vettoriali appositamente progettati.
Milvus è stato creato per risolvere i problemi che i database relazionali incontrano con i vettori ed è stato progettato da zero per gestire questi vettori di embedding e i loro indici su larga scala. Per soddisfare il distintivo cloud-native, Milvus separa elaborazione e archiviazione e diversi compiti di elaborazione — interrogazione, data wrangling e indicizzazione. Gli utenti possono scalare ciascuna parte del database per gestire altri casi d’uso, che siano caratterizzati da molte operazioni di inserimento dati o da molte ricerche. Se c’è un grande afflusso di richieste di inserimento, l’utente può scalare temporaneamente i nodi di indicizzazione orizzontalmente e verticalmente per gestire l’ingestione. Allo stesso modo, se non vengono ingeriti dati, ma ci sono molte ricerche, l’utente può ridurre i nodi di indicizzazione e scalare invece i nodi di query per una maggiore capacità di elaborazione. Questa progettazione del sistema (vedi Figura 2) ci ha richiesto di pensare con una mentalità di calcolo parallelo, dando vita a un sistema ottimizzato per il calcolo con molte possibilità aperte per ulteriori ottimizzazioni.
Figura 2. Progettazione del sistema Milvus
Milvus utilizza anche molte librerie di indicizzazione all’avanguardia per offrire agli utenti la massima personalizzazione possibile del proprio sistema. Le migliora aggiungendo la capacità di gestire operazioni CRUD, dati in streaming e filtraggio. Più avanti, discuteremo in che modo questi indici differiscono e quali sono i pro e i contro di ciascuno.
Soluzione di esempio: integrazione di Milvus e Merlin
La soluzione di esempio che presentiamo qui dimostra l’integrazione di Milvus con Merlin nella fase di recupero degli elementi (quando i k elementi più rilevanti vengono recuperati tramite una ricerca ANN). Utilizziamo un dataset reale tratto da una sfida RecSys, descritto di seguito. Addestriamo un modello di deep learning Two-Tower che apprende embedding vettoriali per utenti ed elementi. Questa sezione fornisce anche il progetto del nostro lavoro di benchmarking, incluse le metriche che raccogliamo e l’intervallo di parametri che utilizziamo.
Il nostro approccio prevede:
Ingestione e preprocessing dei dati
Addestramento di un modello di deep learning Two-Tower
Costruzione dell’indice Milvus
Ricerca di similarità Milvus
Descriviamo brevemente ogni passaggio e rimandiamo il lettore ai nostri notebook per i dettagli.
Dataset
YOOCHOOSE GmbH fornisce il dataset che utilizziamo in questa integrazione e studio di benchmark per la sfida RecSys 2015 ed è disponibile su Kaggle. Contiene eventi di clic/acquisto degli utenti da un rivenditore online europeo con attributi come ID di sessione, timestamp, ID dell'articolo associato al clic/acquisto e categoria dell'articolo, disponibili nel file yoochoose-clicks.dat. Le sessioni sono indipendenti e non vi è alcun indizio di utenti di ritorno, quindi trattiamo ciascuna sessione come appartenente a un utente distinto. Il dataset ha 9.249.729 sessioni uniche (utenti) e 52.739 articoli unici.
Acquisizione e preelaborazione dei dati
Lo strumento che utilizziamo per la preelaborazione dei dati è NVTabular, un componente di ingegnerizzazione e preelaborazione delle feature di Merlin accelerato da GPU e altamente scalabile. Utilizziamo NVTabular per leggere i dati nella memoria della GPU, riorganizzare le feature secondo necessità, esportare in file parquet e creare una suddivisione train-validation per l'addestramento. Questo porta a 7.305.761 utenti unici e 49.008 articoli unici su cui eseguire l'addestramento. Inoltre categorizziamo ciascuna colonna e i suoi valori in valori interi. Il dataset è ora pronto per l'addestramento con il modello Two-Tower.
Addestramento del modello
Utilizziamo il modello di deep learning Two-Tower per addestrare e generare embedding di utenti e articoli, utilizzati successivamente nell'indicizzazione vettoriale e nelle query. Dopo l'addestramento del modello, possiamo estrarre gli embedding di utenti e articoli.
I due passaggi seguenti sono opzionali: un modello DLRM addestrato per ordinare gli articoli recuperati per la raccomandazione e un feature store utilizzato (in questo caso, Feast) per archiviare e recuperare le feature di utenti e articoli. Li includiamo per completezza del workflow multi-stage.
Infine, esportiamo gli embedding di utenti e articoli in file parquet, che possono essere successivamente ricaricati per creare un indice vettoriale Milvus.
Creazione e interrogazione dell'indice Milvus
Milvus facilita l'indicizzazione vettoriale e la ricerca per similarità tramite un “server” avviato sulla macchina di inferenza. Nel nostro notebook #2, lo configuriamo installando tramite pip il server Milvus e Pymilvus, quindi avviando il server con la sua porta di ascolto predefinita. Successivamente, dimostriamo la creazione di un indice semplice (IVF_FLAT) e l'interrogazione su di esso utilizzando rispettivamente le funzioni setup_milvus e query_milvus.
Benchmarking
Abbiamo progettato due benchmark per dimostrare il motivo per cui utilizzare una libreria di indicizzazione/ricerca vettoriale veloce ed efficiente come Milvus.
Utilizzo di Milvus per creare indici vettoriali con i due set di embedding che abbiamo generato: 1) embedding degli utenti per 7,3M utenti unici, suddivisi in 85% train set (per l'indicizzazione) e 15% test set (per le query), e 2) embedding degli articoli per 49K prodotti (con una suddivisione train-test 50–50). Questo benchmark viene eseguito indipendentemente per ciascun dataset vettoriale e i risultati sono riportati separatamente.
Utilizzo di Milvus per creare un indice vettoriale per il dataset di embedding dei 49K articoli e interrogazione dei 7,3M utenti unici rispetto a questo indice per la ricerca per similarità.
In questi benchmark, abbiamo utilizzato gli algoritmi di indicizzazione IVFPQ e HNSW eseguiti su GPU e CPU, insieme a varie combinazioni di parametri. I dettagli sono disponibili sulla nostra pagina GitHub.
Il compromesso qualità-throughput della ricerca è un'importante considerazione sulle prestazioni, specialmente in un ambiente di produzione. Milvus consente il controllo completo sui parametri di indicizzazione per esplorare questo compromesso per un determinato caso d'uso al fine di ottenere risultati di ricerca migliori con ground truth. Questo può significare un aumento del costo computazionale sotto forma di una riduzione del throughput o delle query al secondo (QPS). Misuriamo la qualità della ricerca ANN con una metrica di recall e forniamo curve QPS-recall che dimostrano il compromesso. Si può quindi decidere un livello accettabile di qualità della ricerca dati le risorse di calcolo o i requisiti di latenza/throughput del caso di business.
Inoltre, si noti la dimensione del batch di query (nq) utilizzata nei nostri benchmark. Questo è utile nei workflow in cui più richieste simultanee vengono inviate all'inferenza (ad es., raccomandazioni offline richieste e inviate a un elenco di destinatari email o raccomandazioni online create raggruppando richieste concorrenti in arrivo ed elaborandole tutte insieme). A seconda del caso d'uso, TIS può anche aiutare a elaborare queste richieste in batch.
Risultati
Ora riportiamo i risultati per i tre set di benchmark sia su CPU che su GPU, utilizzando i tipi di indice HNSW (solo CPU) e IVF_PQ (CPU e GPU) implementati da Milvus.
Ricerca di similarità vettoriale Items vs. Items
Con questo dataset più piccolo, ogni esecuzione per una determinata combinazione di parametri prende il 50% dei vettori degli item come vettori di query e interroga i primi 100 vettori simili dal resto. HNSW e IVF_PQ producono una recall elevata con le impostazioni dei parametri testate, rispettivamente nell'intervallo 0,958–1,0 e 0,665–0,997. Questo risultato suggerisce che HNSW offre prestazioni migliori rispetto alla recall, ma IVF_PQ con impostazioni nlist piccole produce una recall altamente comparabile. Dovremmo inoltre notare che i valori di recall possono variare notevolmente a seconda dei parametri di indicizzazione e interrogazione. I valori che riportiamo sono stati ottenuti dopo una sperimentazione preliminare con intervalli generali di parametri e un'ulteriore focalizzazione su un sottoinsieme selezionato.
Il tempo totale per eseguire tutte le query su CPU con HNSW per una determinata combinazione di parametri varia tra 5,22 e 5,33 sec.s (più veloce all'aumentare di m, relativamente invariato con ef) e con IVF_PQ tra 13,67 e 14,67 sec.s (più lento all'aumentare di nlist e nprobe). L'accelerazione GPU ha effettivamente un effetto evidente, come mostrato nella Figura 3.
La Figura 3 mostra il compromesso recall-throughput su tutte le esecuzioni completate su CPU e GPU con questo piccolo dataset utilizzando IVF_PQ. Abbiamo rilevato che la GPU fornisce uno speedup da 4x a 15x in tutte le combinazioni di parametri testate (speedup maggiore all'aumentare di nprobe). Questo viene calcolato prendendo il rapporto tra QPS dalle esecuzioni su GPU e QPS dalle esecuzioni su CPU per ciascuna combinazione di parametri. Nel complesso, questo set rappresenta una sfida ridotta per CPU o GPU e mostra prospettive di ulteriore speedup con dataset più grandi, come discusso di seguito.
Figura 3. Speedup GPU con algoritmo Milvus IVF_PQ in esecuzione su GPU NVIDIA A100 (ricerca di similarità item-item)
Ricerca di similarità vettoriale Users vs. Users
Con il secondo dataset molto più grande (7,3M utenti), abbiamo messo da parte l'85% (~6,2M) dei vettori come “train” (l'insieme di vettori da indicizzare) e il restante 15% (~1,1M) come set di vettori “test” o di query. HNSW e IVF_PQ offrono prestazioni eccezionalmente buone in questo caso, con valori di recall rispettivamente di 0,884–1,0 e 0,922–0,999. Sono tuttavia molto più esigenti dal punto di vista computazionale, specialmente con IVF_PQ sulla CPU. Il tempo totale per eseguire tutte le query su CPU con HNSW varia da 279,89 a 295,56 sec.s e con IVF_PQ da 3082,67 a 10932,33 sec.s. Si noti che questi tempi di query sono cumulativi per 1,1M vettori interrogati, quindi si può dire che una singola query sull'indice è comunque molto veloce.
Tuttavia, l'interrogazione basata su CPU potrebbe non essere praticabile se il server di inferenza prevede molte migliaia di richieste concorrenti per eseguire query su un inventario di milioni di item.
La GPU A100 offre un’accelerazione straordinaria da 37x a 91x (con una media di 76,1x) in tutte le combinazioni di parametri con IVF_PQ in termini di throughput (QPS), come mostrato nella Figura 4. Questo è coerente con quanto osservato con il dataset piccolo, il che suggerisce che le prestazioni della GPU scalino ragionevolmente bene usando Milvus con milioni di vettori di embedding.
Figura 4. Accelerazione GPU con l’algoritmo Milvus IVF_PQ in esecuzione su GPU NVIDIA A100 (ricerca di similarità utente-utente)
La seguente Figura 5 dettagliata mostra il compromesso recall-QPS per tutte le combinazioni di parametri testate su CPU e GPU con IVF_PQ. Ogni insieme di punti (in alto per la GPU, in basso per la CPU) in questo grafico rappresenta il compromesso affrontato quando si modificano i parametri di indicizzazione/query dei vettori per ottenere un recall più elevato a scapito di un throughput inferiore. Si noti la considerevole perdita di QPS nel caso della GPU quando si cerca di raggiungere livelli di recall più elevati.
Figura 5. Compromesso recall-throughput per tutte le combinazioni di parametri testate su CPU e GPU con IVF_PQ (utenti vs. utenti)
Ricerca di similarità vettoriale utenti vs. elementi
Infine, consideriamo un altro caso d’uso realistico in cui i vettori utente vengono interrogati rispetto ai vettori degli elementi (come dimostrato nel Notebook 01 sopra). In questo caso, vengono indicizzati 49K vettori di elementi e 7,3M vettori utente vengono ciascuno interrogati per i primi 100 elementi più simili.
È qui che le cose si fanno interessanti, perché interrogare 7,3M in batch da 1000 rispetto a un indice di 49K elementi appare dispendioso in termini di tempo sulla CPU sia per HNSW sia per IVF_PQ. La GPU sembra gestire meglio questo caso (vedi Figura 6). I livelli di accuratezza più elevati di IVF_PQ su CPU quando nlist = 100 vengono calcolati in circa 86 minuti in media, ma variano significativamente all’aumentare del valore di nprobe (51 min. quando nprobe = 5 vs. 128 min. quando nprobe = 20). La GPU NVIDIA A100 accelera considerevolmente le prestazioni di un fattore da 4x a 17x (accelerazioni maggiori man mano che nprobe aumenta). Ricorda che l’algoritmo IVF_PQ, tramite la sua tecnica di quantizzazione, riduce anche l’impronta di memoria e fornisce una soluzione di ricerca ANN computazionalmente sostenibile combinata con l’accelerazione GPU.
Figura 6. Accelerazione GPU con l’algoritmo Milvus IVF_PQ in esecuzione su GPU NVIDIA A100 (ricerca di similarità utente-elemento)
Analogamente alla Figura 5, il compromesso recall-throughput è mostrato nella Figura 7 per tutte le combinazioni di parametri testate con IVF_PQ. Qui si può ancora vedere come possa essere necessario rinunciare leggermente a una parte dell’accuratezza nella ricerca ANN a favore di un throughput maggiore, sebbene le differenze siano molto meno evidenti, specialmente nel caso delle esecuzioni su GPU. Questo suggerisce che ci si possa aspettare livelli relativamente costantemente elevati di prestazioni computazionali con la GPU, pur ottenendo un recall elevato.
Figura 7. Compromesso recall-throughput per tutte le combinazioni di parametri testate su CPU e GPU con IVF_PQ (utenti vs. elementi)
Conclusione
Saremmo lieti di condividere alcune osservazioni conclusive se siete arrivati fin qui. Vogliamo ricordarvi che la complessità e la natura multi-stage dei moderni sistemi Recsys richiedono prestazioni ed efficienza in ogni fase. Speriamo che questo blog vi abbia fornito motivi convincenti per considerare l’utilizzo di due funzionalità critiche nelle vostre pipeline RecSys:
La libreria Merlin Systems di NVIDIA Merlin consente di integrare facilmente Milvus, un efficiente motore di ricerca vettoriale accelerato da GPU.
Utilizzate la GPU per accelerare i calcoli per l’indicizzazione dei database vettoriali e la ricerca ANN con tecnologie come RAPIDS RAFT.
Questi risultati suggeriscono che l’integrazione Merlin-Milvus presentata è altamente performante e molto meno complessa rispetto ad altre opzioni per l’addestramento e l’inferenza. Inoltre, entrambi i framework sono sviluppati attivamente e molte nuove funzionalità (ad esempio, nuovi indici di database vettoriali accelerati da GPU da parte di Milvus) vengono aggiunte a ogni release. Il fatto che la ricerca di similarità vettoriale sia una componente cruciale in vari workflow, come la visione artificiale, la modellazione di grandi linguaggi e i sistemi di raccomandazione, rende questo sforzo ancora più prezioso.
In conclusione, vorremmo ringraziare tutti coloro dei team Zilliz/Milvus, Merlin e RAFT che hanno contribuito allo sforzo di produrre questo lavoro e il post sul blog. Non vediamo l’ora di ricevere vostre notizie, qualora abbiate l’opportunità di implementare Merlin e Milvus nel vostro recsys o in altri workflow.
Continua a leggere

Zilliz Cloud BYOC Now Available Across AWS, GCP, and Azure
Zilliz Cloud BYOC is now generally available on all three major clouds. Deploy fully managed vector search in your own AWS, GCP, or Azure account — your data never leaves your VPC.

Optimizing Embedding Model Selection with TDA Clustering: A Strategic Guide for Vector Databases
Discover how Topological Data Analysis (TDA) reveals hidden embedding model weaknesses and helps optimize vector database performance.

DeepSeek Always Busy? Deploy It Locally with Milvus in Just 10 Minutes—No More Waiting!
Learn how to set up DeepSeek-R1 on your local machine using Ollama, AnythingLLM, and Milvus in just 10 minutes. Bypass busy servers and enhance AI responses with custom data.



