Dopo l'introduzione teorica sull'embedding è il momento di vedere questo meccanismo al lavoro. Come già illustrato, la sua finalità consiste nella vettorializzazione dei testi in modo da posizionarli in uno spazio geometrico (dall'altissimo numero di dimensioni) per poter valutare la distanza tra i concetti espressi. Tali vettori andranno inseriti in database di uno specifico tipo, detti database vettoriali, sui quali applicheremo delle query per ottenere i valori più prossimi possibile.
In questa lezione, non ci occuperemo di database vettoriali che studieremo separatamente più avanti ma applicheremo algoritmi al solo scopo di valutare la vicinanza tra espressioni.
Scegliere il modello per l'embedding
Il primo passaggio consiste nello scegliere un modello da utilizzare. I fattori coinvolti nella scelta sono molti e, in questo caso, approcceremo il problema scegliendo qualcosa di già piuttosto avanzato. Si tratta di un modello di embedding di OpenAI, multilingua (in grado di comprendere e confrontare lingue diverse), disponibile on line (quindi non lo dovremo scaricare in locale), dotato di ottime prestazioni a buon prezzo.
Il modello da noi scelto è solo una delle innumerevoli possibilità. Per esercizio ci si potrà però divertire a sperimentarne di altri grandi provider online o installando dei modelli in locale.
Oltre al modello, avremo bisogno di una funzione per il calcolo della similarità. Ci rivolgeremo quindi a quella basata sul coseno offerta dalla libreria sklearn: cosine_similarity.
Iniziamo a predisporre l'esempio partendo da semplici frasi da confrontare.
Il codice
L'esempio può essere affrontato in qualsiasi ambiente in cui potremo installare librerie Python infatti usando un modello remoto non dovremo disporre di grandi risorse locali per installarlo. Iniziamo con l'installazione degli strumenti. Anche in questo caso ci serviremo di Langchain.
pip install -U langchain_openai scikit-learn
Importiamo ora il provider di modelli di embeddinge la funzione di similarità:
from langchain_openai import OpenAIEmbeddings
from sklearn.metrics.pairwise import cosine_similarity
embedding_model = OpenAIEmbeddings(model="text-embedding-3-small",
api_key="...")
Per sperimentare svolgeremo due passaggi:
- faremo l'embedding dei documenti che nei nostri casi di studio saranno semplici frasi (nella realtà saranno documenti o loro chunk frutto di splitting);
- calcoleremo la matrice di similarità con la funzione coseno che restituirà una sorta di incrocio di similarità tra tutti id documenti importati
Proviamo questo codice:
vettori = embedding_model.embed_documents([
"Il mio gatto ama giocare con una pallina di lana",
"I felini sono gli animali più agili del mondo"
])
matrice_similarita = cosine_similarity(vettori)
La matrice di similarità che otteniamo (tecnicamente, un array NumPy) è la seguente:
array([[1. , 0.43148239],
[0.43148239, 1. ]])
Ogni cella della matrice indica il risultato della comparazione tra due frasi. Sulla diagonale troviamo solo il valore 1 in quanto rappresenta sempre l'incrocio di una frase con sé stessa. In questo caso, trattandosi di sole due frasi la dimensione della struttura è 2X2 inoltre la matrice è simmetrica in quanto riporta gli stessi valori sopra e sotto la diagonale e ci mostra che l'incrocio tra le due frasi ha una similarità pari a 0.43. Due frasi uguali hanno similarità uguale a 1 ovvero il coseno dell'angolo nullo che si forma tra due vettori sovrapposti.
Le posizioni dei valori sono date dal fatto che sia le righe che le colonne in una data posizione corrispondono a quelle delle frasi nel vettore fornito dell'embedding (conteggiato a partire da zero, come sempre). In pratica, la posizione 0-1 (prima riga e seconda colonna) indica l'incrocio tra la frase in posizione 0 ("Il mio gatto...") e quella in posizione 1 ("I felini..."). Nella posizione 1-0, per forza di cose, ci sarà il corrispondente valore.
Possiamo da qui fare vari esperimenti aggiungendo altre frasi o sostituendole. Ad esempio con:
vettori = embedding_model.embed_documents([
"Il mio gatto ama giocare con una pallina di lana",
"le scimmie sono gli animali più agili del mondo",
"I felini amano gli oggetti che rotolano"
])
matrice_similarita = cosine_similarity(vettori)
otteniamo
array([[1. , 0.33196856, 0.61316845],
[0.33196856, 1. , 0.45858474],
[0.61316845, 0.45858474, 1. ]])
Notiamo le modifiche apportate:
- la frase 1 ("le scimmie sono gli...") non parla più di felini ed infatti registra ora i valori più bassi sia con la numero 0 ("Il mio gatto...") sia con la nuova frase, la numero 2, ("I felini amano...");
- il valore più alto, 0.61, è il frutto dell'incrocio tra la frase 0 e la 2 che parlano entrambe sia di felini sia di oggetti rotondi.
Se provassimo ad aggiungere un'ulteriore frase tipo "Un telefono ha dieci tasti" come quarta frase (in posizione 3 quindi) otterremmo questa matrice:
array([[1. , 0.33190673, 0.61321363, 0.23599981],
[0.33190673, 1. , 0.45844426, 0.21174693],
[0.61321363, 0.45844426, 1. , 0.22961431],
[0.23599981, 0.21174693, 0.22961431, 1. ]])
Notiamo subito che la quarta frase (volutamente scollegata dalle altre) registra i valori più bassi in assoluto che possiamo leggere sia nella quarta colonna sia nella quarta riga.
Come procedere?
Con questa sperimentazione pratica abbiamo visto che per fare l'embedding i provider mettono già a disposizione qualsiasi strumento, non dovremo far altro che integrare il tutto in un procedimento che raccolga i documenti, li riduca in chunk, li vettorizzi e li inserisca in un database vettoriale come vedremo tra pochissimo.
Per comprendere bene l'embedding conviene continuare a sperimentare, aggiungendo frasi (anche più estese di queste), cambiando modelli di embedding e notare i range di valori che si ottengono come risultati. Dalle nostre prove abbiamo visto che già 0.2 rappresenta concetti piuttosto lontani mentre oltre lo 0.7 si può parlare di discreta somiglianza.
Questi valori in realtà non sarà compito nostro valutarli ma è bene prenderci confidenza in quanto saranno i parametri che i database vettoriali considereranno per la restituzione di frasi simili alle richieste degli utenti.
Se vuoi aggiornamenti su Embedding al lavoro inserisci la tua email nel box qui sotto: