Ho creato metriche personalizzate molto spesso per i miei casi d'uso, ma mi sono imbattuto ripetutamente in queste metriche integrate per gli strumenti AI in LangChain prima di iniziare a utilizzare RAGAS e/o DeepEval per la valutazione RAG, quindi alla fine ero curioso su come vengono create queste metriche e ho eseguito una rapida analisi (con tutti i pregiudizi intrinseci ovviamente).

TLDR proviene dalla matrice di correlazione seguente:

  • Utilità e coerenza (correlazione 0,46): Questa forte correlazione suggerisce che il LLM (e, per procura, gli utenti) potrebbero trovare più utili risposte coerenti, sottolineando l'importanza della strutturazione logica nelle risposte. È solo correlazione, ma questa relazione apre la possibilità di questo risultato.
  • Controversiità e criminalità (correlazione 0,44): Ciò indica che anche i contenuti controversi potrebbero essere considerati criminali e viceversa, forse riflettendo una preferenza dell'utente per materiale coinvolgente e stimolante.
  • Coerenza vs. Profondità: Nonostante la coerenza sia correlata alla disponibilità, la profondità no. Ciò potrebbe suggerire che gli utenti (ancora una volta, presupponendo che le preferenze degli utenti siano inerenti al risultato del LLM – questa sola è una presunzione e un pregiudizio di cui è importante essere consapevoli) potrebbero preferire risposte chiare e concise rispetto a quelle dettagliate, in particolare in contesti in cui le soluzioni rapide sono apprezzate rispetto a quelle globali.

Le metriche integrate si trovano qui (rimuovendone una che si riferisce alla verità fondamentale e gestita meglio altrove):

# Listing Criteria / LangChain's built-in metrics
from langchain.evaluation import Criteria
new_criteria_list = (item for i, item in enumerate(Criteria) if i != 2)
new_criteria_list

Le metriche:

  • Concisione
  • Dettaglio
  • Rilevanza
  • Coerenza
  • Pericolosità
  • Insensibilità
  • Utilità
  • Controversietà
  • Criminalità
  • Profondità
  • Creatività

Innanzitutto, cosa significano e perché sono stati creati?

Le ipotesi:

  • Questi sono stati creati nel tentativo di definire metriche che potessero spiegare l'output in relazione agli obiettivi teorici dei casi d'uso e qualsiasi correlazione potrebbe essere accidentale ma generalmente è stata evitata ove possibile.

Ho questa ipotesi dopo aver visto questo codice sorgente qui.

In secondo luogo, alcuni di questi sembrano simili e/o vaghi: quindi in cosa differiscono?

Ho utilizzato un set di dati SQuAD standard come base per valutare le differenze (se presenti) tra l'output del modello GPT-3-Turbo di OpenAI e la verità fondamentale in questo set di dati e confrontare.

# Import a standard SQUAD dataset from HuggingFace (ran in colab)
from google.colab import userdata
HF_TOKEN = userdata.get('HF_TOKEN')

dataset = load_dataset("rajpurkar/squad")
print(type(dataset))

Ho ottenuto un insieme casuale di righe per la valutazione (non potevo permettermi il tempo e il calcolo per l'intera faccenda), quindi questo potrebbe essere un punto di ingresso per più rumore e/o distorsione.

# Slice dataset to randomized selection of 100 rows
validation_data = dataset('validation')
validation_df = validation_data.to_pandas()
sample_df = validation_df.sample(n=100, replace=False)

Ho definito un llm utilizzando ChatGPT 3.5 Turbo (per risparmiare sui costi qui, è veloce).

import os

# Import OAI API key
OPENAI_API_KEY = userdata.get('OPENAI_API_KEY')
os.environ('OPENAI_API_KEY') = userdata.get('OPENAI_API_KEY')
# Define llm
llm = ChatOpenAI(model_name='gpt-3.5-turbo', openai_api_key=OPENAI_API_KEY)

Quindi ho ripetuto le righe campionate per ottenere un confronto: c'erano soglie sconosciute che LangChain utilizzava per il “punteggio” nei criteri di valutazione, ma il presupposto è che siano definite allo stesso modo per tutti i parametri.

# Loop through each question in random sample
for index, row in sample_df.iterrows():
try:
prediction = " ".join(row('answers')('text'))
input_text = row('question')

# Loop through each criteria\
for m in new_criteria_list:
evaluator = load_evaluator("criteria", llm=llm, criteria=m)

eval_result = evaluator.evaluate_strings(
prediction=prediction,
input=input_text,
reference=None,
other_kwarg="value" # adding more in future for compare
)
score = eval_result('score')
if m not in results:
results(m) = ()
results(m).append(score)
except KeyError as e:
print(f"KeyError: {e} in row {index}")
except TypeError as e:
print(f"TypeError: {e} in row {index}")

Quindi ho calcolato le medie e l'IC con intervalli di confidenza al 95%.

# Calculate means and confidence intervals at 95%
mean_scores = {}
confidence_intervals = {}

for m, scores in results.items():
mean_score = np.mean(scores)
mean_scores(m) = mean_score
# Standard error of the mean * t-value for 95% confidence
ci = sem(scores) * t.ppf((1 + 0.95) / 2., len(scores)-1)
confidence_intervals(m) = (mean_score - ci, mean_score + ci)

E tracciato i risultati.

# Plotting results by metric
fig, ax = plt.subplots()
m_labels = list(mean_scores.keys())
means = list(mean_scores.values())
cis = (confidence_intervals(m) for m in m_labels)
error = ((mean - ci(0), ci(1) - mean) for mean, ci in zip(means, cis)))

ax.bar(m_labels, means, yerr=np.array(error).T, capsize=5, color='lightblue', label='Mean Scores with 95% CI')
ax.set_xlabel('Criteria')
ax.set_ylabel('Average Score')
ax.set_title('Evaluation Scores by Criteria')
plt.xticks(rotation=90)
plt.legend()
plt.show()

È forse intuitivo che la “Rilevanza” sia molto più alta delle altre, ma è interessante notare che nel complesso sono così basse (forse grazie a GPT 3.5!), e che la “Utilità” è il successivo parametro più alto (forse riflettendo tecniche e ottimizzazioni RL).

Per rispondere alla mia domanda sulla correlazione, avevo calcolato una semplice matrice di correlazione con il dataframe di confronto grezzo.

# Convert results to dataframe
min_length = min(len(v) for v in results.values())
dfdata = {k.name: v(:min_length) for k, v in results.items()}
df = pd.DataFrame(dfdata)

# Filtering out null values
filtered_df = df.drop(columns=(col for col in df.columns if 'MALICIOUSNESS' in col or 'MISOGYNY' in col))

# Create corr matrix
correlation_matrix = filtered_df.corr()

Quindi tracciati i risultati (vengono creati i valori p più in basso nel mio codice ed erano tutti sotto .05)

# Plot corr matrix
mask = np.triu(np.ones_like(correlation_matrix, dtype=bool))
plt.figure(figsize=(10, 8))
sns.heatmap(correlation_matrix, mask=mask, annot=True, fmt=".2f", cmap='coolwarm',
cbar_kws={"shrink": .8})
plt.title('Correlation Matrix - Built-in Metrics from LangChain')
plt.xticks(rotation=90)
plt.yticks(rotation=0)
plt.show()

È stato sorprendente che la maggior parte non sia correlata, data la natura delle descrizioni nella base di codice LangChain: questo porta a qualcosa di un po' più pensato e sono felice che siano integrate per l'uso.

Dalla matrice di correlazione emergono relazioni notevoli:

  • Utilità e coerenza (correlazione 0,46): Questa forte correlazione suggerisce che il LLM (poiché è un proxy per gli utenti) potrebbe trovare più utili risposte coerenti, sottolineando l'importanza della strutturazione logica nelle risposte. Anche se si tratta di correlazione, questa relazione apre la strada a ciò.
  • Controversiità e criminalità (correlazione 0,44): Ciò indica che anche i contenuti controversi potrebbero essere considerati criminali e viceversa, forse riflettendo una preferenza dell’utente per materiale coinvolgente e stimolante. Ancora una volta, questa è solo correlazione.

Asporto:

  1. Coerenza vs. Profondità nell’Utilità: Nonostante la coerenza sia correlata alla disponibilità, la profondità no. Ciò potrebbe suggerire che gli utenti potrebbero preferire risposte chiare e concise rispetto a quelle dettagliate, in particolare in contesti in cui le soluzioni rapide sono apprezzate rispetto a quelle complete.
  2. Sfruttare la controversia: La correlazione positiva tra controverità e criminalità pone una domanda interessante: è possibile discutere argomenti controversi in un modo che non sia criminale? Ciò potrebbe potenzialmente aumentare il coinvolgimento degli utenti senza compromettere la qualità dei contenuti.
  3. Impatto della distorsione e della scelta del modello: L'uso di GPT-3.5 Turbo e i pregiudizi intrinseci nella progettazione metrica potrebbero influenzare queste correlazioni. Riconoscere questi pregiudizi è essenziale per un’interpretazione e un’applicazione accurate di questi parametri.

Se non diversamente specificato, tutte le immagini in questo articolo sono state create dall'autore.

Fonte: towardsdatascience.com

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *