Ricerca di similarità, Parte 2 Quantizzazione di prodotto

Similarity Search, Part 2 Product Quantization

Impara una potente tecnica per comprimere in modo efficiente grandi dati

La ricerca di similarità è un problema dove, dato un query, l’obiettivo è trovare i documenti più simili ad esso tra tutti i documenti del database.

Introduzione

Nella scienza dei dati, la ricerca di similarità appare spesso nel dominio di NLP, motori di ricerca o sistemi di raccomandazione dove i documenti o gli elementi più pertinenti devono essere recuperati per una query. Esiste una grande varietà di modi diversi per migliorare le prestazioni di ricerca in grandi volumi di dati.

Nella prima parte di questa serie di articoli, abbiamo esaminato kNN e la struttura dell’indice di file invertito per effettuare la ricerca di similarità. Come abbiamo appreso, kNN è l’approccio più semplice mentre l’indice di file invertito agisce al suo interno suggerendo un compromesso tra l’accelerazione della velocità e l’accuratezza. Tuttavia, entrambi i metodi non utilizzano tecniche di compressione dei dati che potrebbero portare a problemi di memoria, soprattutto in caso di grandi dataset e RAM limitata. In questo articolo, cercheremo di affrontare questo problema guardando ad un altro metodo chiamato Quantizzazione di prodotto.

Ricerca di similarità, Parte 1: kNN & Indice di file invertito

La ricerca di similarità è un problema dove, dato un query Q, l’obiettivo è trovare i documenti più simili ad esso tra tutti…

towardsdatascience.com

Definizione

La quantizzazione di prodotto è il processo in cui ogni vettore del dataset viene convertito in una rappresentazione breve ed efficiente in termini di memoria (chiamata codice PQ). Invece di conservare completamente tutti i vettori, vengono memorizzate le loro rappresentazioni brevi. Allo stesso tempo, la quantizzazione di prodotto è un metodo di compressione con perdita che porta a una minore accuratezza di previsione ma, in pratica, questo algoritmo funziona molto bene.

In generale, la quantizzazione è il processo di mappare i valori infiniti in quelli discreti.

Formazione

In primo luogo, l’algoritmo divide ogni vettore in diverse parti uguali — subvettori. Ciascuna delle parti rispettive di tutti i vettori del dataset forma spazi indipendenti e viene elaborata separatamente. Quindi, viene eseguito un algoritmo di clustering per ogni sottospazio di vettori. In questo modo, vengono creati diversi centroidi in ciascun sottospazio. Ciascun subvettore viene codificato con l’ID del centroide a cui appartiene. Inoltre, le coordinate di tutti i centroidi vengono memorizzate per un uso successivo.

I centroidi del sottospazio sono anche chiamati vettori quantizzati.

Nella quantizzazione di prodotto, un ID di cluster è spesso indicato come un valore di riproduzione.

Nota. Nelle figure sottostanti, un rettangolo rappresenta un vettore contenente diversi valori mentre un quadrato indica un singolo numero.

Codifica usando la quantizzazione

Come risultato, se un vettore originale è diviso in n parti, può essere codificato da n numeri — ID dei centroidi rispettivi per ciascuno dei suoi subvettori. Tipicamente, il numero di centroidi creati k viene scelto di solito come potenza di 2 per un uso più efficiente della memoria. In questo modo, la memoria richiesta per memorizzare un vettore codificato è di n * log(k) bit.

La raccolta di tutti i centroidi all’interno di un sottospazio è chiamata catabook. L’esecuzione di n algoritmi di clustering per tutti i sottospazi produce n codebook separati.

Esempio di compressione

Immagina un vettore originale di dimensioni 1024 che memorizza float (32 bit) è stato diviso in n = 8 subvettori in cui ciascun subvettore è codificato da uno dei k = 256 cluster. Pertanto, la codifica dell’ID di un singolo cluster richiederebbe log(256) = 8 bit. Confrontiamo le dimensioni di memoria per la rappresentazione del vettore in entrambi i casi:

  • Vettore originale: 1024 * 32 bit = 4096 byte.
  • Vettore codificato: 8 * 8 bit = 8 byte.

La compressione finale è di ben 512 volte! Questo è il vero potere della quantizzazione di prodotto.

Esempio di quantizzazione. I numeri nei vettori mostrano quanti numeri vengono memorizzati.

Ecco alcune note importanti:

  • L’algoritmo può essere addestrato su un sottoinsieme di vettori (ad esempio, per creare cluster) e utilizzato su un altro: una volta che l’algoritmo è stato addestrato, viene passato un altro dataset di vettori in cui i nuovi vettori vengono codificati utilizzando i centroidi già costruiti per ogni sottospazio.
  • In genere, viene scelto k-means come algoritmo di clustering. Uno dei suoi vantaggi è che il numero di cluster k è un iperparametro che può essere definito manualmente, secondo i requisiti di utilizzo della memoria.

Inferenza

Per avere una migliore comprensione, vediamo prima alcune approcci ingenui e scopriamo i loro svantaggi. Ciò ci aiuterà anche a capire perché non dovrebbero essere normalmente usati.

Approcci ingenui

Il primo approccio ingenuo consiste nella decompressione di tutti i vettori concatenando i centroidi corrispondenti di ciascun vettore. Dopo di che, la distanza L2 (o un’altra metrica) può essere calcolata da un vettore di query a tutti i vettori del dataset. Ovviamente, questo metodo funziona, ma è molto dispendioso in termini di tempo perché viene eseguita una ricerca a forza bruta e il calcolo della distanza viene effettuato su vettori decompressi ad alta dimensionalità.

Un’altra possibile soluzione è quella di dividere un vettore di query in sottovettori e calcolare una somma di distanze da ciascun sottovettore di query ai rispettivi vettori quantizzati di un vettore del database, in base al suo codice PQ. Di conseguenza, viene utilizzata nuovamente la tecnica di ricerca a forza bruta e il calcolo della distanza richiede ancora un tempo lineare della dimensionalità dei vettori originali, come nel caso precedente.

Calcolo dell'approssimazione della distanza utilizzando l'approccio ingenuo. L'esempio è mostrato per la distanza euclidea come metrica.

Un altro possibile metodo consiste nell’codificare il vettore di query in un codice PQ. Poi, questo codice PQ viene utilizzato direttamente per calcolare le distanze a tutti gli altri codici PQ. Il vettore del dataset con il corrispondente codice PQ che ha la distanza più breve viene quindi considerato come il vicino più vicino alla query. Questo approccio è più veloce dei primi due perché la distanza viene sempre calcolata tra codici PQ a bassa dimensionalità. Tuttavia, i codici PQ sono composti da ID di cluster che non hanno molto significato semantico e possono essere considerati come una variabile categorica esplicitamente utilizzata come una variabile reale. Chiaramente, questa è una pratica sbagliata e questo metodo può portare a una scarsa qualità della predizione.

Approccio ottimizzato

Un vettore di query è diviso in sottovettori. Per ciascuno dei suoi sottovettori, vengono calcolate le distanze a tutti i centroidi dello spazio corrispondente. Alla fine, queste informazioni vengono memorizzate nella tabella d .

Ottenere una tabella d che memorizza le distanze parziali tra i sottovettori di query e i centroidi

Le distanze parziali calcolate tra sottovettori e centroidi sono spesso indicate come distanze parziali.

Utilizzando questa tabella di distanze tra sottovettore e centroide d , la distanza approssimativa dalla query a qualsiasi vettore del database può essere facilmente ottenuta dai suoi codici PQ:

  1. Per ciascuno dei sottovettori di un vettore del database, viene trovato il centroide più vicino j (utilizzando i valori di mappatura dai codici PQ) e viene presa la distanza parziale d[i][j] da quel centroide al sottovettore di query i (utilizzando la matrice calcolata d ).
  2. Tutte le distanze parziali vengono elevate al quadrato e sommate. Prendendo la radice quadrata di questo valore, si ottiene la distanza euclidea approssimativa. Se si vuole sapere come ottenere risultati approssimati per altre metriche, passare alla sezione “Approssimazione di altre metriche di distanza”.
Calcolo della distanza tra una query e un vettore del database utilizzando il codice PQ e la tabella delle distanze

Utilizzare questo metodo per il calcolo delle distanze approssimate presuppone che le distanze parziali d siano molto vicine alle distanze effettive a tra la query e i sottovettori del database.

Tuttavia, questa condizione potrebbe non essere soddisfatta, specialmente quando la distanza c tra il sottovettore del database e il suo centroide è grande. In tali casi, i calcoli producono una minore precisione.

L'esempio a sinistra mostra un buon caso di approssimazione quando la distanza effettiva è molto vicina alla distanza parziale (c è piccolo). Sulla destra, possiamo osservare uno scenario negativo perché la distanza parziale è molto più lunga della distanza effettiva (c è grande).

Dopo aver ottenuto le distanze approssimate per tutte le righe del database, cerchiamo i vettori con i valori più piccoli. Quei vettori saranno i vicini più vicini alla query.

Approssimazione di altri metriche di distanza

Fino ad ora abbiamo visto come approssimare la distanza euclidea utilizzando le distanze parziali. Generalizziamo la regola anche per altre metriche.

Immaginiamo di voler calcolare una metrica di distanza tra una coppia di vettori. Se conosciamo la formula della metrica, possiamo applicarla direttamente per ottenere il risultato. Ma a volte possiamo farlo per parti nel seguente modo:

  • Entrambi i vettori sono divisi in n sottovettori.
  • Per ogni coppia di sottovettori rispettivi, viene calcolata la metrica di distanza.
  • Le n metriche calcolate vengono quindi combinate per produrre la distanza effettiva tra i vettori originali.
La figura mostra due modi di calcolare una metrica. A sinistra, la formula della metrica viene applicata direttamente ad entrambi i vettori. A destra, le distanze parziali sono calcolate per ogni coppia di sottovettori rispettivi. Quindi sono combinate utilizzando le funzioni di aggregazione h, g e f.

La distanza euclidea è un esempio di metrica che può essere calcolata per parti. Basandoci sulla figura sopra, possiamo scegliere le funzioni di aggregazione per essere h(z) = z² , g(z₀, z₁, …, zₙ) = sum(z₀, z₁, …, zₙ) e f(z) = √z .

La distanza euclidea può essere calcolata per parti

Il prodotto interno è un altro esempio di tale metrica con le funzioni di aggregazione h(z) = z, g(z₀, z₁, …, zₙ) = sum(z₀, z₁, …, zₙ) e f(z) = z .

Nel contesto della quantizzazione del prodotto, questa è una proprietà molto importante perché durante l’inferezza l’algoritmo calcola le distanze per parti. Ciò significa che sarebbe molto più problematico utilizzare metriche per la quantizzazione del prodotto che non hanno questa proprietà. La distanza coseno è un esempio di tale metrica.

Se c’è ancora la necessità di utilizzare una metrica senza questa proprietà, allora sono necessarie euristici aggiuntivi per aggregare le distanze parziali con qualche errore.

Prestazioni

Il principale vantaggio della quantizzazione del prodotto è una massiccia compressione dei vettori del database che vengono archiviati come codici PQ brevi. Per alcune applicazioni, tale tasso di compressione può essere addirittura superiore al 95%! Tuttavia, oltre ai codici PQ, deve essere archiviata la matrice d di dimensioni k x n che contiene i vettori quantizzati di ogni sottospazio.

La quantizzazione del prodotto è un metodo di compressione con perdita, quindi maggiore è la compressione, maggiore è la probabilità che la precisione delle previsioni diminuisca.

La creazione di un sistema per una rappresentazione efficiente richiede la formazione di diversi algoritmi di clustering. Oltre a questo, durante l’infusione, k * n distanze parziali devono essere calcolate in modo brutale e sommate per ciascuno dei vettori del database, il che può richiedere del tempo.

Product Quantization performance

Implementazione di Faiss

Faiss (Facebook AI Search Similarity) è una libreria Python scritta in C++ usata per la ricerca ottimizzata di similarità. Questa libreria presenta diversi tipi di indici che sono strutture dati utilizzate per memorizzare ed eseguire query in modo efficiente.

In base alle informazioni della documentazione di Faiss, vedremo come viene utilizzata la quantizzazione del prodotto.

La quantizzazione del prodotto è implementata nella classe IndexPQ. Per l’inizializzazione, dobbiamo fornire 3 parametri:

  • d : numero di dimensioni nei dati.
  • M : numero di suddivisioni per ogni vettore (lo stesso parametro n utilizzato sopra).
  • nbits : numero di bit necessari per codificare un singolo ID di cluster. Ciò significa che il numero totale di cluster in un singolo sottospazio sarà pari a k = 2^nbits .

Per la suddivisione di dimensioni di sottospazio uguali, il parametro dim deve essere divisibile per M.

Il numero totale di byte richiesti per memorizzare un singolo vettore è pari a:

Come possiamo vedere dalla formula sopra, per un uso più efficiente della memoria il valore di M * nbits dovrebbe essere divisibile per 8.

Faiss implementation of IndexPQ

Conclusione

Abbiamo esaminato un algoritmo molto popolare nei sistemi di recupero delle informazioni che comprime efficientemente grandi volumi di dati. Il suo principale svantaggio è una lenta velocità di inferenza. Nonostante questo fatto, l’algoritmo è ampiamente utilizzato nelle moderne applicazioni Big Data, specialmente in combinazione con altre tecniche di ricerca di similarità.

Nella prima parte della serie di articoli, abbiamo descritto il flusso di lavoro dell’indice del file invertito. In effetti, possiamo unire questi due algoritmi in uno più efficiente che avrà i vantaggi di entrambi! Questo è esattamente ciò che faremo nella prossima parte di questa serie.

Ricerca di similarità, Parte 3: Fusione dell’indice del file invertito e della quantizzazione del prodotto

Nelle prime due parti di questa serie abbiamo discusso due algoritmi fondamentali nel recupero delle informazioni: invertiti…

Nisoo.com

Risorse

  • Quantizzazione del prodotto per la ricerca del vicino più vicino
  • Documentazione di Faiss
  • Repository di Faiss
  • Riepilogo degli indici di Faiss

Tutte le immagini, a meno che non sia diversamente indicato, sono dell’autore.