Un esperimento sorprendente per dimostrare che il diavolo è nei dettagli
Con il crescente numero di modelli di incorporamento disponibili, scegliere quello giusto per le tue applicazioni di machine learning può essere difficile. Fortunatamente, il Classifica MTEB fornisce una gamma completa di metriche di classificazione per varie attività di elaborazione del linguaggio naturale.
Quando visiti il sito, noterai che i primi cinque modelli di incorporamento sono i trasformatori generativi pre-addestrati (GPT). Ciò potrebbe portarti a pensare che i modelli GPT siano i migliori per gli incorporamenti. Ma è davvero così? Conduciamo un esperimento per scoprirlo.
Gli incorporamenti sono rappresentazioni tensoriali di testi, che convertono gli ID dei token di testo e li proiettano in uno spazio tensore.
Inserendo il testo in un modello di rete neurale ed eseguendo un passaggio in avanti, è possibile ottenere vettori di incorporamento. Tuttavia, il processo vero e proprio è un po’ più complesso. Analizziamolo passo dopo passo:
- Converti il testo in ID token
- Passa gli ID token in una rete neurale
- Restituisce gli output della rete neurale
Nel primo passaggio, utilizzerò un tokenizzatore per raggiungerlo. model_inputs
è la rappresentazione tensoriale del contenuto del testo, "some questions."
.
from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.1")
messages = (
{
"role": "user",
"content": "some questions.",
},
)
encodeds = tokenizer.apply_chat_template(messages, return_tensors="pt")
model_inputs = encodeds.to("cuda")
Il secondo passaggio è semplice e prevede il passaggio in avanti del file model_inputs
in una rete neurale. È possibile accedere ai logit dei token generati tramite .logits
. torch.no_grad()
significa che non voglio che i pesi del modello vengano aggiornati perché il modello è in modalità di inferenza.
import torchwith torch.no_grad():
return model(model_inputs).logits
Il terzo passaggio è un po’ complicato. I modelli GPT sono solo decodificatori e la generazione dei token è autoregressiva. In termini semplici, l'ultimo elemento di una frase completata ha visto tutti gli elementi precedenti della frase. Pertanto, l'output dell'ultimo token contiene tutti i punteggi di affinità (attenzioni) dei token precedenti.
Bingo! Sei più interessato all'ultimo token a causa del meccanismo di attenzione nei trasformatori.
La dimensione di output dei GPT implementati in Hugging Face è (dimensione del batch, dimensione del token di input, numero di vocabolario). Per ottenere l'ultimo output token di tutti i batch, posso eseguire una sezione tensore.
import torch
with torch.no_grad():
return model(model_inputs).logits(:, -1, :)
Per misurare la qualità di questi incorporamenti GPT, puoi utilizzare somiglianza del coseno. Maggiore è la somiglianza del coseno, più vicino è il significato semantico delle frasi.
import torch
def compute_cosine_similarity(vec1, vec2):
cos = torch.nn.CosineSimilarity(dim=1, eps=1e-6)
return cos(vec1, vec2)
Creiamo alcune funzioni di utilità che ci consentano di scorrere l'elenco di coppie di domande e risposte e vedere il risultato. Istruzioni Mistral 7b v0.1 per questo esperimento viene utilizzato uno dei più grandi modelli open source.
import torch
from termcolor import colored
from transformers import AutoModelForCausalLM, AutoTokenizermodel = AutoModelForCausalLM.from_pretrained(
"mistralai/Mistral-7B-Instruct-v0.1"
)
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.1")
def generate_last_token_embeddings(question, max_new_tokens=30):
messages = (
{
"role": "user",
"content": question,
},
)
encodeds = tokenizer.apply_chat_template(messages, return_tensors="pt")
model_inputs = encodeds.to("cuda")
with torch.no_grad():
return model(model_inputs).logits(:, -1, :)
def get_similarities(questions, answers):
for question in questions:
for answer in answers:
q_embedding, a_embedding = (
generate_last_token_embeddings(question),
generate_last_token_embeddings(answer),
)
similarity = compute_cosine_similarity(q_embedding, a_embedding)
print(colored(f"question: {question} and ans: {answer}", "green"))
print(colored(f"result: {similarity}", "blue"))
questions = ("Where is the headquarter of OpenAI?", "What is GPU?")
answers = (
"OpenAI is based at San Francisco.",
"A graphics processing unit (GPU) is an electronic circuit that can perform mathematical calculations quickly",
)
Per la prima coppia di domande e risposte:
- Domanda: “Qual è la sede di OpenAI?”
- Risposta: “OpenAI ha sede a San Francisco”.
- Somiglianza coseno: 0,96
Per la seconda coppia di domande e risposte:
- Domanda: “Cos'è la GPU?”
- Risposta: “Un'unità di elaborazione grafica (GPU) è un circuito elettronico in grado di eseguire rapidamente calcoli matematici”.
- Somiglianza coseno: 0,94
Per una coppia irrilevante:
- Domanda: “Dov'è la sede di OpenAI?”
- Risposta: “Un'unità di elaborazione grafica (GPU) è un circuito elettronico in grado di eseguire rapidamente calcoli matematici”.
- Somiglianza coseno: 0,90
Per la coppia peggiore:
- Domanda: “Cos'è la GPU?”
- Risposta: “OpenAI ha sede a San Francisco”.
- Somiglianza coseno: 0,93
Questi risultati suggeriscono che utilizzando i modelli GPT, in questo caso, il mistral 7b istruisce v0.1, poiché i modelli di incorporamento potrebbero non produrre grandi risultati in termini di distinzione tra coppie rilevanti e irrilevanti. Ma perché i modelli GPT sono ancora tra i primi 5 modelli di incorporamento?
tokenizer = AutoTokenizer.from_pretrained("intfloat/e5-mistral-7b-instruct")
model = AutoModelForCausalLM.from_pretrained(
"intfloat/e5-mistral-7b-instruct"
)
Ripetendo la stessa procedura di valutazione con un modello diverso, e5-mistral-7b-instruct
che è uno dei migliori modelli open source della classifica MTEB e messo a punto dall'istruzione mistral 7b, scopro che la somiglianza del coseno per la domanda e le coppie pertinenti è rispettivamente 0,88 e 0,84 per le domande OpenAI e GPU. Per le coppie domanda-risposta irrilevanti, la somiglianza scende a 0,56 e 0,67. Questo risultato suggerisce e5-mistral-7b-instruct
è un modello molto migliorato per gli incorporamenti. Cosa determina un tale miglioramento?
Approfondire il carta dietro e5-mistral-7b-instruct
la chiave è l'uso di perdita contrastiva per perfezionare ulteriormente il modello maestrale.
A differenza dei GPT che vengono addestrati o ulteriormente perfezionati utilizzando perdita di entropia incrociata dei token previsti e dei token etichettati, la perdita contrastiva mira a massimizzare la distanza tra le coppie negative e minimizzare la distanza tra le coppie positive.
Questo post sul blog tratta questo concetto in maggior dettaglio. IL sim
la funzione calcola la distanza coseno tra due vettori. Per la perdita contrastiva, i denominatori rappresentano la distanza coseno tra esempi positivi ed esempi negativi. La logica alla base della perdita contrastiva è che vogliamo che vettori simili siano il più vicino possibile a 1, poiché log(1) = 0 rappresenta la perdita ottimale.
In questo post, ho evidenziato un errore comune nell'utilizzo dei GPT come modelli di incorporamento senza messa a punto. La mia valutazione suggerisce che mettendo a punto i GPT con perdita contrastiva, gli incorporamenti possono essere più significativi e discriminativi. Comprendendo i punti di forza e i limiti dei modelli GPT e sfruttando la perdita personalizzata come la perdita contrastiva, puoi prendere decisioni più informate quando selezioni e utilizzi modelli di incorporamento per i tuoi progetti di machine learning. Spero che questo post ti aiuti a scegliere saggiamente i modelli GPT per le tue applicazioni e non vedo l'ora di sentire il tuo feedback! 🙂
Fonte: towardsdatascience.com