Iniziare con gli Embeddings

'Embeddings una buona introduzione'

Guarda questo tutorial con il Notebook Companion:

Comprensione degli embedding

Un embedding è una rappresentazione numerica di un pezzo di informazione, ad esempio, testo, documenti, immagini, audio, ecc. La rappresentazione cattura il significato semantico di ciò che viene incorporato, rendendolo robusto per molte applicazioni industriali.

Dato il testo “Qual è il principale vantaggio del voto?”, un embedding della frase potrebbe essere rappresentato in uno spazio vettoriale, ad esempio, con una lista di 384 numeri (ad esempio, [0,84, 0,42, …, 0,02]). Poiché questa lista cattura il significato, possiamo fare cose interessanti, come calcolare la distanza tra diversi embedding per determinare quanto bene il significato di due frasi corrisponde.

Gli embedding non sono limitati al testo! Puoi anche creare un embedding di un’immagine (ad esempio, una lista di 384 numeri) e confrontarlo con un embedding di testo per determinare se una frase descrive l’immagine. Questo concetto è alla base di potenti sistemi per la ricerca, la classificazione, la descrizione delle immagini e altro ancora!

Come vengono generati gli embedding? La libreria open-source chiamata Sentence Transformers ti consente di creare embedding di ultima generazione da immagini e testo gratuitamente. Questo blog mostra un esempio con questa libreria.

A cosa servono gli embedding?

“[…] una volta che capisci questo multitool di apprendimento automatico (embedding), sarai in grado di costruire tutto, dai motori di ricerca ai sistemi di raccomandazione, ai chatbot e molto altro ancora. Non devi essere un data scientist con competenze di apprendimento automatico per usarli, né hai bisogno di un enorme dataset etichettato.” – Dale Markowitz, Google Cloud.

Una volta che un pezzo di informazione (una frase, un documento, un’immagine) viene incorporato, la creatività inizia; diverse interessanti applicazioni industriali utilizzano gli embedding. Ad esempio, Google Search utilizza gli embedding per abbinare testo a testo e testo a immagini; Snapchat li utilizza per “servire l’annuncio giusto all’utente giusto al momento giusto”; e Meta (Facebook) li utilizza per la loro ricerca sociale.

Prima di poter ottenere intelligenza dagli embedding, queste aziende dovevano incorporare i loro pezzi di informazione. Un dataset incorporato consente agli algoritmi di cercare rapidamente, ordinare, raggruppare e altro ancora. Tuttavia, può essere costoso e tecnicamente complicato. In questo post, utilizziamo semplici strumenti open-source per mostrare quanto possa essere facile incorporare e analizzare un dataset.

Iniziare con gli embedding

Crea un piccolo motore di domande frequenti (FAQ): ricevi una richiesta da un utente e identifica quale FAQ è la più simile. Utilizzeremo le FAQ del Social Security Medicare degli Stati Uniti.

Ma prima, dobbiamo incorporare il nostro dataset (altri testi utilizzano i termini codifica e incorporamento in modo interscambiabile). L’API di inferenza Hugging Face ci consente di incorporare un dataset con una semplice chiamata POST.

Poiché gli embedding catturano il significato semantico delle domande, è possibile confrontare diversi embedding e vedere quanto siano diversi o simili. Grazie a questo, è possibile ottenere l’embedding più simile a una query, che equivale a trovare la FAQ più simile. Dai un’occhiata al nostro tutorial sulla ricerca semantica per una spiegazione più dettagliata di come funziona questo meccanismo.

In poche parole, faremo quanto segue:

  1. Incorporare le FAQ di Medicare utilizzando l’API di inferenza.
  2. Caricare le domande incorporate nell’Hub per l’hosting gratuito.
  3. Confrontare la query di un cliente con il dataset incorporato per identificare qual è la FAQ più simile.

1. Incorporare un dataset

Il primo passo è selezionare un modello pre-allenato esistente per creare gli embedding. Possiamo scegliere un modello dalla libreria Sentence Transformers. In questo caso, utilizziamo il modello “sentence-transformers/all-MiniLM-L6-v2” perché è un modello piccolo ma potente. In un futuro post, esamineremo altri modelli e i loro compromessi.

Accedi all’Hub. Devi creare un token di scrittura nelle Impostazioni del tuo Account. Memorizzeremo il token di scrittura in hf_token.

model_id = "sentence-transformers/all-MiniLM-L6-v2"
hf_token = "ottieni il tuo token su http://hf.co/settings/tokens"

Per generare gli embedding puoi utilizzare l’endpoint https://api-inference.huggingface.co/pipeline/feature-extraction/{model_id} con gli header {"Authorization": f"Bearer {hf_token}"}. Ecco una funzione che riceve un dizionario con i testi e restituisce una lista di embedding.

import requests

api_url = f"https://api-inference.huggingface.co/pipeline/feature-extraction/{model_id}"
headers = {"Authorization": f"Bearer {hf_token}"}

La prima volta che si generano gli embeddings, potrebbe richiedere del tempo (circa 20 secondi) affinché l’API li restituisca. Utilizziamo il decoratore retry (installare con pip install retry) in modo che se al primo tentativo output = query(dict(inputs = texts)) non funziona, si attendano 10 secondi e si riprovi tre volte ancora. Questo accade perché, alla prima richiesta, il modello deve essere scaricato e installato sul server, ma le chiamate successive sono molto più veloci.

def query(texts):
    response = requests.post(api_url, headers=headers, json={"inputs": texts, "options":{"wait_for_model":True}})
    return response.json()

L’API attuale non impone limiti di velocità rigorosi. Invece, Hugging Face bilancia il carico in modo uniforme tra tutte le risorse disponibili e favorisce flussi costanti di richieste. Se è necessario incorporare diversi testi o immagini, l’API di Inference Accelerato di Hugging Face velocizzerà l’inference e ti permetterà di scegliere tra l’utilizzo di una CPU o di una GPU.

texts = ["Come posso ottenere una sostituzione della mia carta Medicare?",
        "Qual è il premio mensile per la Parte B di Medicare?",
        "Come posso interrompere la mia Parte B di Medicare (assicurazione medica)?",
        "Come posso iscrivermi a Medicare?",
        "Posso iscrivermi alla Parte B di Medicare se lavoro e ho un'assicurazione sanitaria tramite un datore di lavoro?",
        "Come posso iscrivermi alla Parte B di Medicare se ho già la Parte A?",
        "Quali sono le penalità di iscrizione tardiva a Medicare?",
        "Cos'è Medicare e chi può ottenerlo?",
        "Come posso ottenere aiuto con i premi della mia Parte A e Parte B di Medicare?",
        "Quali sono le diverse parti di Medicare?",
        "I miei premi Medicare saranno più alti a causa del mio reddito più alto?",
        "Cos'è TRICARE?",
        "Dovrei iscrivermi alla Parte B di Medicare se ho dei benefici per i veterani?"]

output = query(texts)

Come risposta, riceverai una lista di liste. Ogni lista contiene l’embedding di una domanda frequentemente fatta (FAQ). Il modello, “sentence-transformers/all-MiniLM-L6-v2”, codifica le domande di input in 13 embeddings di dimensione 384 ciascuno. Convertiamo la lista in un DataFrame di Pandas con forma (13×384).

import pandas as pd
embeddings = pd.DataFrame(output)

Assomiglia a questa matrice:

[[-0.02388945  0.05525852 -0.01165488 ...  0.00577787  0.03409787  -0.0068891 ]
 [-0.0126876   0.04687412 -0.01050217 ... -0.02310316 -0.00278466   0.01047371]
 [ 0.00049438  0.11941205  0.00522949 ...  0.01687654 -0.02386115   0.00526433]
 ...
 [-0.03900796 -0.01060951 -0.00738271 ... -0.08390449  0.03768405   0.00231361]
 [-0.09598278 -0.06301168 -0.11690582 ...  0.00549841  0.1528919   0.02472013]
 [-0.01162949  0.05961934  0.01650903 ... -0.02821241 -0.00116556   0.0010672 ]]

2. Ospitare gli embeddings gratuitamente su Hugging Face Hub

🤗 Datasets è una libreria per accedere e condividere rapidamente i dataset. Ospitiamo il dataset degli embeddings nell’Hub utilizzando l’interfaccia utente (UI). Successivamente, chiunque potrà caricarlo con una sola riga di codice. Puoi anche utilizzare il terminale per condividere i dataset; consulta la documentazione per i passaggi. Nella versione notebook di questa guida, sarai in grado di utilizzare il terminale per condividere il dataset. Se desideri saltare questa sezione, consulta il repository ITESM/embedded_faqs_medicare con le FAQ integrate.

Innanzitutto, esportiamo i nostri embeddings da un DataFrame di Pandas in un file CSV. Puoi salvare il tuo dataset nel modo che preferisci, ad esempio in formato zip o pickle; non è necessario utilizzare Pandas o CSV. Poiché il nostro file di embeddings non è grande, possiamo salvarlo in un CSV, che viene facilmente riconosciuto dalla funzione datasets.load_dataset() che utilizzeremo nella sezione successiva (consultare la documentazione di Datasets), cioè non è necessario creare uno script di caricamento. Salveremo gli embeddings con il nome embeddings.csv.

embeddings.to_csv("embeddings.csv", index=False)

Segui i passaggi successivi per ospitare embeddings.csv nell’Hub.

  • Fai clic sul tuo utente nell’angolo in alto a destra dell’interfaccia utente di Hub.
  • Crea un dataset con “Nuovo dataset”.

  • Scegli il Proprietario (organizzazione o individuo), il nome e la licenza del dataset. Seleziona se desideri che sia privato o pubblico. Crea il dataset.

  • Vai alla scheda “Files” (screenshot qui sotto) e fai clic su “Aggiungi file” e “Carica file”.

  • Infine, trascina o carica il dataset e conferma le modifiche.

Ora il dataset è ospitato gratuitamente nell’Hub. Tu (o chiunque tu voglia condividere gli embeddings) puoi caricarli rapidamente. Vediamo come.

3. Trova le domande frequenti più simili a una query

Supponiamo che un cliente Medicare chieda: “Come può Medicare aiutarmi?”. Troveremo quale delle nostre domande frequenti potrebbe rispondere meglio alla nostra query dell’utente. Creeremo un embedding della query che possa rappresentare il suo significato semantico. Poi lo confrontiamo con ogni embedding nel nostro dataset di domande frequenti per identificare quale è più vicino alla query nello spazio vettoriale.

Installa la libreria 🤗 Datasets con pip install datasets. Successivamente, carica il dataset embedded dall’Hub e convertilo in un PyTorch FloatTensor. Nota che questa non è l’unica modalità per lavorare su un Dataset; ad esempio, potresti utilizzare NumPy, Tensorflow o SciPy (fare riferimento alla Documentazione). Se vuoi esercitarti con un dataset reale, il repository ITESM/embedded_faqs_medicare contiene le domande frequenti embeddate, oppure puoi utilizzare il quaderno complementare a questo blog.

import torch
from datasets import load_dataset

faqs_embeddings = load_dataset('namespace/repo_name')
dataset_embeddings = torch.from_numpy(faqs_embeddings["train"].to_pandas().to_numpy()).to(torch.float)

Utilizziamo la funzione di query definita in precedenza per incorporare la domanda del cliente e convertirla in un PyTorch FloatTensor per operare su di essa in modo efficiente. Nota che una volta caricato il dataset incorporato, potremmo utilizzare i metodi add_faiss_index e search di un Dataset per identificare la domanda frequenti più vicina a una query incorporata utilizzando la libreria faiss. Ecco un bel tutorial sull’alternativa.

question = ["Come può Medicare aiutarmi?"]
output = query(question)

query_embeddings = torch.FloatTensor(output)

Puoi utilizzare la funzione util.semantic_search della libreria Sentence Transformers per identificare quali delle domande frequenti sono più vicine (più simili) alla query dell’utente. Questa funzione utilizza la similarità coseno come funzione predefinita per determinare la vicinanza degli embeddings. Tuttavia, potresti anche utilizzare altre funzioni che misurano la distanza tra due punti in uno spazio vettoriale, ad esempio il prodotto scalare.

Installa sentence-transformers con pip install -U sentence-transformers e cerca le cinque domande frequenti più simili alla query.

from sentence_transformers.util import semantic_search

hits = semantic_search(query_embeddings, dataset_embeddings, top_k=5)

util.semantic_search identifica quanto sono vicine ciascuna delle 13 domande frequenti alla query del cliente e restituisce una lista di dizionari con le prime top_k domande frequenti. hits ha questo aspetto:

[{'corpus_id': 8, 'score': 0.75653076171875},
 {'corpus_id': 7, 'score': 0.7418993711471558},
 {'corpus_id': 3, 'score': 0.7252674102783203},
 {'corpus_id': 9, 'score': 0.6735571622848511},
 {'corpus_id': 10, 'score': 0.6505177617073059}]

I valori in corpus_id ci permettono di indicizzare la lista di testi che abbiamo definito nella prima sezione e ottenere le cinque FAQ più simili:

print([testi[hits[0][i]['corpus_id']] for i in range(len(hits[0]))])

Ecco le 5 FAQ che si avvicinano di più alla query del cliente:

['Come posso ottenere aiuto con i premi del mio Medicare Parte A e Parte B?',
 'Cos'è il Medicare e chi può ottenerlo?',
 'Come faccio a iscrivermi al Medicare?',
 'Quali sono le diverse parti del Medicare?',
 'I miei premi del Medicare saranno più alti a causa del mio reddito più alto?']

Questa lista rappresenta le 5 FAQ più vicine alla query del cliente. Ottimo! Qui abbiamo utilizzato PyTorch e Sentence Transformers come principali strumenti numerici. Tuttavia, avremmo potuto definire le funzioni di similarità coseno e di ranking da soli utilizzando strumenti come NumPy e SciPy.

Risorse addizionali per continuare ad apprendere

Se vuoi saperne di più sulla libreria Sentence Transformers:

  • L’organizzazione Hub per tutti i nuovi modelli e le istruzioni su come scaricare i modelli.
  • Il tweet di Nils Reimers che confronta i modelli di Sentence Transformer con gli embeddings di GPT-3. Spoiler: i Sentence Transformers sono fantastici!
  • La documentazione di Sentence Transformers,
  • Il thread di Nima sulla ricerca recente.

Grazie per la lettura!