🚀 Prova Zilliz Cloud, la versione completamente gestita di Milvus, gratuitamente—sperimenta prestazioni 10 volte più veloci! Prova Ora>>

milvus-logo
LFAI
  • Home
  • Blog
  • Come ottenere le giuste incorporazioni vettoriali

Come ottenere le giuste incorporazioni vettoriali

  • Engineering
December 08, 2023
Yujian Tang

Questo articolo è stato pubblicato originariamente su The New Stack e viene ripubblicato qui con l'autorizzazione.

Un'introduzione completa alle incorporazioni vettoriali e a come generarle con i più diffusi modelli open source.

Image by Денис Марчук from Pixabay Immagine di Денис Марчук da Pixabay

Le incorporazioni vettoriali sono fondamentali quando si lavora con la similarità semantica. Tuttavia, un vettore è semplicemente una serie di numeri; un embedding vettoriale è una serie di numeri che rappresentano i dati di input. Utilizzando le incorporazioni vettoriali, possiamo strutturare dati non strutturati o lavorare con qualsiasi tipo di dati convertendoli in una serie di numeri. Questo approccio ci permette di eseguire operazioni matematiche sui dati in ingresso, anziché affidarci a confronti qualitativi.

Le incorporazioni vettoriali sono influenti per molti compiti, in particolare per la ricerca semantica. Tuttavia, è fondamentale ottenere le incorporazioni vettoriali appropriate prima di utilizzarle. Ad esempio, se si utilizza un modello di immagine per vettorializzare il testo, o viceversa, probabilmente si otterranno scarsi risultati.

In questo post scopriremo cosa significano le incorporazioni vettoriali, come generare le incorporazioni vettoriali giuste per le vostre applicazioni utilizzando diversi modelli e come utilizzare al meglio le incorporazioni vettoriali con database vettoriali come Milvus e Zilliz Cloud.

Come vengono creati gli embeddings vettoriali?

Ora che abbiamo capito l'importanza degli embedding vettoriali, impariamo a capire come funzionano. Un embedding vettoriale è la rappresentazione interna dei dati di input in un modello di deep learning, noto anche come modello di embedding o rete neurale profonda. Come si estraggono queste informazioni?

Otteniamo i vettori rimuovendo l'ultimo strato e prendendo l'output del penultimo strato. L'ultimo strato di una rete neurale solitamente produce la previsione del modello, quindi prendiamo l'output del penultimo strato. L'embedding vettoriale è il dato che alimenta lo strato predittivo di una rete neurale.

La dimensionalità di un embedding vettoriale è equivalente alla dimensione del penultimo strato del modello e, pertanto, è intercambiabile con la dimensione o la lunghezza del vettore. Le dimensioni comuni dei vettori sono 384 (generate da Sentence Transformers Mini-LM), 768 (da Sentence Transformers MPNet), 1.536 (da OpenAI) e 2.048 (da ResNet-50).

Cosa significa embedding vettoriale?

Una volta qualcuno mi ha chiesto il significato di ciascuna dimensione di un embedding vettoriale. La risposta breve è: niente. Una singola dimensione in un embedding vettoriale non significa nulla, perché è troppo astratta per determinarne il significato. Tuttavia, se consideriamo tutte le dimensioni insieme, esse forniscono il significato semantico dei dati in ingresso.

Le dimensioni del vettore sono rappresentazioni astratte di alto livello di diversi attributi. Gli attributi rappresentati dipendono dai dati di addestramento e dal modello stesso. I modelli di testo e di immagine generano embeddings diversi perché sono addestrati per tipi di dati fondamentalmente diversi. Anche modelli di testo diversi generano embeddings diversi. A volte differiscono per le dimensioni, altre volte per gli attributi che rappresentano. Per esempio, un modello addestrato su dati legali imparerà cose diverse da uno addestrato su dati sanitari. Ho esplorato questo argomento nel mio post sul confronto delle incorporazioni vettoriali.

Generare le giuste incorporazioni vettoriali

Come si ottengono le giuste incorporazioni vettoriali? Tutto inizia con l'identificazione del tipo di dati che si desidera incorporare. Questa sezione tratta l'incorporazione di cinque diversi tipi di dati: immagini, testo, audio, video e dati multimodali. Tutti i modelli che presentiamo sono open source e provengono da Hugging Face o PyTorch.

Incorporazione di immagini

Il riconoscimento delle immagini è decollato nel 2012, dopo la comparsa di AlexNet. Da allora, il campo della computer vision ha visto numerosi progressi. L'ultimo modello di riconoscimento delle immagini degno di nota è ResNet-50, una rete residuale profonda a 50 strati basata sull'architettura precedente ResNet-34.

Le reti neurali residue (ResNet) risolvono il problema del gradiente che svanisce nelle reti neurali convoluzionali profonde utilizzando connessioni di tipo shortcut. Queste connessioni permettono all'output degli strati precedenti di andare direttamente agli strati successivi senza passare per tutti gli strati intermedi, evitando così il problema del gradiente che svanisce. Questo design rende ResNet meno complessa di VGGNet (Visual Geometry Group), una rete neurale convoluzionale dalle prestazioni eccellenti.

Vi propongo due implementazioni di ResNet-50 come esempi: ResNet 50 su Hugging Face e ResNet 50 su PyTorch Hub. Mentre le reti sono le stesse, il processo per ottenere le incorporazioni è diverso.

L'esempio di codice che segue mostra come utilizzare PyTorch per ottenere le incorporazioni vettoriali. Innanzitutto, si carica il modello da PyTorch Hub. Quindi, si rimuove l'ultimo strato e si chiama .eval() per istruire il modello a comportarsi come se fosse in esecuzione per l'inferenza. Quindi, la funzione embed genera l'incorporazione vettoriale.

# Load the embedding model with the last layer removed
model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet50', pretrained=True) model = torch.nn.Sequential(*(list(model.children())[:-1]))
model.eval()


def embed(data):
with torch.no_grad():
output = model(torch.stack(data[0])).squeeze()
return output

HuggingFace utilizza una configurazione leggermente diversa. Il codice seguente mostra come ottenere un embedding vettoriale da Hugging Face. Per prima cosa, abbiamo bisogno di un estrattore di caratteristiche e di un modello dalla libreria transformers. Useremo l'estrattore di caratteristiche per ottenere gli input per il modello e useremo il modello per ottenere gli output ed estrarre l'ultimo stato nascosto.

# Load model directly
from transformers import AutoFeatureExtractor, AutoModelForImageClassification


extractor = AutoFeatureExtractor.from_pretrained("microsoft/resnet-50")
model = AutoModelForImageClassification.from_pretrained("microsoft/resnet-50")


from PIL import Image


image = Image.open("<image path>")
# image = Resize(size=(256, 256))(image)


inputs = extractor(images=image, return_tensors="pt")
# print(inputs)


outputs = model(**inputs)
vector_embeddings = outputs[1][-1].squeeze()

Incorporazione del testo

Ingegneri e ricercatori hanno sperimentato il linguaggio naturale e l'IA fin dall'invenzione dell'IA. Tra i primi esperimenti ricordiamo:

  • ELIZA, il primo chatbot terapista AI.
  • La stanza cinese di John Searle, un esperimento di pensiero che esamina se la capacità di tradurre tra cinese e inglese richieda una comprensione della lingua.
  • Traduzioni basate su regole tra inglese e russo.

Il funzionamento dell'intelligenza artificiale sul linguaggio naturale si è evoluto in modo significativo rispetto alle sue incorporazioni basate su regole. Partendo dalle reti neurali primarie, abbiamo aggiunto le relazioni di ricorrenza attraverso le RNN per tenere traccia dei passaggi nel tempo. Da lì, abbiamo utilizzato i trasformatori per risolvere il problema della trasduzione delle sequenze.

I trasformatori sono costituiti da un codificatore, che codifica un ingresso in una matrice che rappresenta lo stato, una matrice di attenzione e un decodificatore. Il decodificatore decodifica lo stato e la matrice di attenzione per prevedere il token successivo corretto per terminare la sequenza in uscita. Il GPT-3, il modello linguistico più diffuso ad oggi, comprende decodificatori rigidi. Essi codificano l'input e predicono il token successivo corretto.

Ecco due modelli della libreria sentence-transformers di Hugging Face che possono essere utilizzati in aggiunta agli embeddings di OpenAI:

È possibile accedere agli embeddings di entrambi i modelli nello stesso modo.

from sentence_transformers import SentenceTransformer


model = SentenceTransformer("<model-name>")
vector_embeddings = model.encode(“<input>”)

Incorporazione multimodale

I modelli multimodali sono meno sviluppati dei modelli di immagini o di testo. Spesso mettono in relazione immagini e testo.

L'esempio open source più utile è CLIP VIT, un modello immagine-testo. È possibile accedere agli embeddings di CLIP VIT nello stesso modo in cui si accede a un modello di immagini, come mostrato nel codice sottostante.

# Load model directly
from transformers import AutoProcessor, AutoModelForZeroShotImageClassification


processor = AutoProcessor.from_pretrained("openai/clip-vit-large-patch14")
model = AutoModelForZeroShotImageClassification.from_pretrained("openai/clip-vit-large-patch14")
from PIL import Image


image = Image.open("<image path>")
# image = Resize(size=(256, 256))(image)


inputs = extractor(images=image, return_tensors="pt")
# print(inputs)


outputs = model(**inputs)
vector_embeddings = outputs[1][-1].squeeze()

Incorporazioni audio

L'intelligenza artificiale per l'audio ha ricevuto meno attenzione di quella per il testo o le immagini. Il caso d'uso più comune per l'audio è il speech-to-text per settori come i call center, la tecnologia medica e l'accessibilità. Un modello open source molto diffuso per il speech-to-text è Whisper di OpenAI. Il codice seguente mostra come ottenere le incorporazioni vettoriali dal modello speech-to-text.

import torch
from transformers import AutoFeatureExtractor, WhisperModel
from datasets import load_dataset


model = WhisperModel.from_pretrained("openai/whisper-base")
feature_extractor = AutoFeatureExtractor.from_pretrained("openai/whisper-base")
ds = load_dataset("hf-internal-testing/librispeech_asr_dummy", "clean", split="validation")
inputs = feature_extractor(ds[0]["audio"]["array"], return_tensors="pt")
input_features = inputs.input_features
decoder_input_ids = torch.tensor([[1, 1]]) * model.config.decoder_start_token_id
vector_embedding = model(input_features, decoder_input_ids=decoder_input_ids).last_hidden_state

Incorporazioni video

Le incorporazioni di video sono più complesse di quelle di audio e immagini. Un approccio multimodale è necessario quando si lavora con i video, poiché questi includono audio e immagini sincronizzate. Un modello video molto diffuso è il multimodal perceiver di DeepMind. Questo tutorial mostra come utilizzare il modello per classificare un video.

Per ottenere le incorporazioni dell'input, utilizzare outputs[1][-1].squeeze() dal codice mostrato nel notebook invece di eliminare le uscite. Evidenzio questo frammento di codice nella funzione autoencode.

def autoencode_video(images, audio):
     # only create entire video once as inputs
     inputs = {'image': torch.from_numpy(np.moveaxis(images, -1, 2)).float().to(device),
               'audio': torch.from_numpy(audio).to(device),
               'label': torch.zeros((images.shape[0], 700)).to(device)}
     nchunks = 128
     reconstruction = {}
     for chunk_idx in tqdm(range(nchunks)):
          image_chunk_size = np.prod(images.shape[1:-1]) // nchunks
          audio_chunk_size = audio.shape[1] // SAMPLES_PER_PATCH // nchunks
          subsampling = {
               'image': torch.arange(
                    image_chunk_size * chunk_idx, image_chunk_size * (chunk_idx + 1)),
               'audio': torch.arange(
                    audio_chunk_size * chunk_idx, audio_chunk_size * (chunk_idx + 1)),
               'label': None,
          }
     # forward pass
          with torch.no_grad():
               outputs = model(inputs=inputs, subsampled_output_points=subsampling)


          output = {k:v.cpu() for k,v in outputs.logits.items()}
          reconstruction['label'] = output['label']
          if 'image' not in reconstruction:
               reconstruction['image'] = output['image']
               reconstruction['audio'] = output['audio']
          else:
               reconstruction['image'] = torch.cat(
                    [reconstruction['image'], output['image']], dim=1)
               reconstruction['audio'] = torch.cat(
                    [reconstruction['audio'], output['audio']], dim=1)
          vector_embeddings = outputs[1][-1].squeeze()
# finally, reshape image and audio modalities back to original shape
     reconstruction['image'] = torch.reshape(reconstruction['image'], images.shape)
     reconstruction['audio'] = torch.reshape(reconstruction['audio'], audio.shape)
     return reconstruction


     return None

Memorizzazione, indicizzazione e ricerca delle incorporazioni vettoriali con i database vettoriali

Ora che abbiamo capito cosa sono le incorporazioni vettoriali e come generarle utilizzando vari modelli di incorporazioni potenti, la domanda successiva è come memorizzarle e sfruttarle. I database vettoriali sono la risposta.

I database vettoriali, come Milvus e Zilliz Cloud, sono costruiti appositamente per archiviare, indicizzare e ricercare tra enormi insiemi di dati non strutturati tramite embedding vettoriali. Sono anche una delle infrastrutture più critiche per vari stack di IA.

I database vettoriali di solito utilizzano l'algoritmo Approximate Nearest Neighbor (ANN) per calcolare la distanza spaziale tra il vettore interrogato e i vettori memorizzati nel database. Più i due vettori sono vicini, più sono rilevanti. L'algoritmo trova quindi i k vettori più vicini e li fornisce all'utente.

I database vettoriali sono molto diffusi in casi d'uso come la generazione aumentata di recupero LLM (RAG), i sistemi di domande e risposte, i sistemi di raccomandazione, le ricerche semantiche e le ricerche di somiglianza di immagini, video e audio.

Per saperne di più sulle incorporazioni vettoriali, sui dati non strutturati e sui database vettoriali, si consiglia di iniziare con la serie Vector Database 101.

Sintesi

I vettori sono uno strumento potente per lavorare con i dati non strutturati. Utilizzando i vettori, possiamo confrontare matematicamente diversi pezzi di dati non strutturati in base alla somiglianza semantica. La scelta del giusto modello di incorporazione vettoriale è fondamentale per costruire un motore di ricerca vettoriale per qualsiasi applicazione.

In questo post abbiamo appreso che le incorporazioni vettoriali sono la rappresentazione interna dei dati in ingresso in una rete neurale. Di conseguenza, dipendono fortemente dall'architettura della rete e dai dati utilizzati per addestrare il modello. Diversi tipi di dati (come immagini, testo e audio) richiedono modelli specifici. Fortunatamente, sono disponibili molti modelli open source preaddestrati. In questo post abbiamo trattato i modelli per i cinque tipi di dati più comuni: immagini, testo, multimodale, audio e video. Inoltre, se si desidera utilizzare al meglio le incorporazioni vettoriali, i database vettoriali sono lo strumento più diffuso.

Like the article? Spread the word

Continua a Leggere