Hugging Face Evaluate

Hugging Face Evaluate Hugging Face Evaluate

Hugging Face evaluatelink image 0

La librería Evaluate de Hugging Face es una librería para evaluar fácilmente modelos y datasets.

Con una sola línea de código, se tiene acceso a docenas de métodos de evaluación para diferentes dominios (NLP, computer vision, reinforcement learning y más). Ya sea en tu máquina local, o en una configuración de entrenamiento distribuida, puedes evaluar modelos de manera consistente y reproducible

En la página de evaluate en Hugging Face se puede obtener una lista completa de las métricas disponibles. Cada métrica tiene un Space de Hugging Face dedicado con una demostración interactiva sobre cómo usar la métrica y una tarjeta de documentación que detalla las limitaciones y el uso de las métricas.

Instalaciónlink image 1

Para instalar la librería es necesario hacer

pip install evaluate
      

Tipo de evaluacioneslink image 2

Hay varios tipos de evaluaciones disponibles

  • metric: Una métrica se utiliza para evaluar el rendimiento de un modelo y, por lo general, incluye las predicciones del modelo y las etiquetas ground truth.
  • comparison: Se utiliza para comparar dos modelos. Esto se puede hacer, por ejemplo, comparando sus predicciones con etiquetas ground truth.
  • measurement: El dataset es tan importante como el modelo entrenado en él. Con las mediciones se pueden investigar las propiedades de un dataset.

Cargalink image 3

Cada metric, comparison o measurement se puede cargar con el método load

	
import evaluate
accuracy = evaluate.load("accuracy")
accuracy
Copy
	
EvaluationModule(name: "accuracy", module_type: "metric", features: {'predictions': Value(dtype='int32', id=None), 'references': Value(dtype='int32', id=None)}, usage: """
Args:
predictions (`list` of `int`): Predicted labels.
references (`list` of `int`): Ground truth labels.
normalize (`boolean`): If set to False, returns the number of correctly classified samples. Otherwise, returns the fraction of correctly classified samples. Defaults to True.
sample_weight (`list` of `float`): Sample weights Defaults to None.
Returns:
accuracy (`float` or `int`): Accuracy score. Minimum possible value is 0. Maximum possible value is 1.0, or the number of examples input, if `normalize` is set to `True`.. A higher score means higher accuracy.
Examples:
Example 1-A simple example
>>> accuracy_metric = evaluate.load("accuracy")
>>> results = accuracy_metric.compute(references=[0, 1, 2, 0, 1, 2], predictions=[0, 1, 1, 2, 1, 0])
>>> print(results)
{'accuracy': 0.5}
Example 2-The same as Example 1, except with `normalize` set to `False`.
>>> accuracy_metric = evaluate.load("accuracy")
>>> results = accuracy_metric.compute(references=[0, 1, 2, 0, 1, 2], predictions=[0, 1, 1, 2, 1, 0], normalize=False)
>>> print(results)
{'accuracy': 3.0}
Example 3-The same as Example 1, except with `sample_weight` set.
>>> accuracy_metric = evaluate.load("accuracy")
>>> results = accuracy_metric.compute(references=[0, 1, 2, 0, 1, 2], predictions=[0, 1, 1, 2, 1, 0], sample_weight=[0.5, 2, 0.7, 0.5, 9, 0.4])
>>> print(results)
{'accuracy': 0.8778625954198473}
""", stored examples: 0)

Si quieres estar seguro de cargar el tipo de métrica que deseas, si tipo metric, comparison o measurement, puedes hacerlo añadiendo el parámetro module_type

	
import evaluate
accuracy = evaluate.load("accuracy", module_type="metric")
word_length = evaluate.load("word_length", module_type="measurement")
Copy
	
[nltk_data] Downloading package punkt to
[nltk_data] /home/maximo.fernandez/nltk_data...
[nltk_data] Package punkt is already up-to-date!

Carga de módulos de la comunidadlink image 4

A parte de los propios módulos que ofrece la librería, también puedes cargar modelos que haya subido alguién al hub de Hugging Face

	
element_count = evaluate.load("lvwerra/element_count", module_type="measurement")
Copy

Lista de módulos disponibleslink image 5

Si queremos obtener una lista de todos los módulos disponibles tenemos que usar el método list_evaluation_modules, en el podemos poner filtros de búsqueda

	
element_count = evaluate.load("lvwerra/element_count", module_type="measurement")
evaluate.list_evaluation_modules(
module_type="comparison",
include_community=True,
with_details=True)
Copy
	
[{'name': 'ncoop57/levenshtein_distance',
'type': 'comparison',
'community': True,
'likes': 0},
{'name': 'kaleidophon/almost_stochastic_order',
'type': 'comparison',
'community': True,
'likes': 1}]

Atributos del módulolink image 6

Todos los módulos de evaluación vienen con una variedad de atributos útiles que ayudan a utilizar el módulo, estos atributos son

Atributo Descripción
description Una breve descripción del módulo de evaluación.
citation Una cadena BibTex para citar cuando esté disponible.
features Un objeto Features que define el formato de entrada.
inputs_description Esto es equivalente a la cadena de documentación de los módulos.
homepage La página de inicio del módulo.
license La licencia del módulo.
codebase_urls Enlace al código detrás del módulo.
reference_urls URL de referencia adicionales.

Veamos algunos

	
accuracy = evaluate.load("accuracy")
Copy
	
accuracy = evaluate.load("accuracy")
print(f"description: {accuracy.description}")
print(f"\ncitation: {accuracy.citation}")
print(f"\nfeatures: {accuracy.features}")
print(f"\ninputs_description: {accuracy.inputs_description}")
print(f"\nhomepage: {accuracy.homepage}")
print(f"\nlicense: {accuracy.license}")
print(f"\ncodebase_urls: {accuracy.codebase_urls}")
print(f"\nreference_urls: {accuracy.reference_urls}")
Copy
	
description:
Accuracy is the proportion of correct predictions among the total number of cases processed. It can be computed with:
Accuracy = (TP + TN) / (TP + TN + FP + FN)
Where:
TP: True positive
TN: True negative
FP: False positive
FN: False negative
citation:
@article{scikit-learn,
title={Scikit-learn: Machine Learning in {P}ython},
author={Pedregosa, F. and Varoquaux, G. and Gramfort, A. and Michel, V.
and Thirion, B. and Grisel, O. and Blondel, M. and Prettenhofer, P.
and Weiss, R. and Dubourg, V. and Vanderplas, J. and Passos, A. and
Cournapeau, D. and Brucher, M. and Perrot, M. and Duchesnay, E.},
journal={Journal of Machine Learning Research},
volume={12},
pages={2825--2830},
year={2011}
}
features: {'predictions': Value(dtype='int32', id=None), 'references': Value(dtype='int32', id=None)}
inputs_description:
Args:
predictions (`list` of `int`): Predicted labels.
references (`list` of `int`): Ground truth labels.
normalize (`boolean`): If set to False, returns the number of correctly classified samples. Otherwise, returns the fraction of correctly classified samples. Defaults to True.
sample_weight (`list` of `float`): Sample weights Defaults to None.
Returns:
accuracy (`float` or `int`): Accuracy score. Minimum possible value is 0. Maximum possible value is 1.0, or the number of examples input, if `normalize` is set to `True`.. A higher score means higher accuracy.
Examples:
Example 1-A simple example
>>> accuracy_metric = evaluate.load("accuracy")
>>> results = accuracy_metric.compute(references=[0, 1, 2, 0, 1, 2], predictions=[0, 1, 1, 2, 1, 0])
>>> print(results)
{'accuracy': 0.5}
Example 2-The same as Example 1, except with `normalize` set to `False`.
>>> accuracy_metric = evaluate.load("accuracy")
>>> results = accuracy_metric.compute(references=[0, 1, 2, 0, 1, 2], predictions=[0, 1, 1, 2, 1, 0], normalize=False)
>>> print(results)
{'accuracy': 3.0}
Example 3-The same as Example 1, except with `sample_weight` set.
>>> accuracy_metric = evaluate.load("accuracy")
>>> results = accuracy_metric.compute(references=[0, 1, 2, 0, 1, 2], predictions=[0, 1, 1, 2, 1, 0], sample_weight=[0.5, 2, 0.7, 0.5, 9, 0.4])
>>> print(results)
{'accuracy': 0.8778625954198473}
homepage:
license:
codebase_urls: []
reference_urls: ['https://scikit-learn.org/stable/modules/generated/sklearn.metrics.accuracy_score.html']

Ejecuciónlink image 7

Ahora que sabemos cómo funciona el módulo de evaluación y qué debe contener, vamos a usarlo. Cuando se trata de calcular la evaluación, hay dos formas principales de hacerlo:

  • Todo en uno
  • Incremental

En el enfoque incremental, las entradas necesarias se agregan al módulo con EvaluationModule.add() o EvaluationModule.add_batch() y la puntuación se calcula al final con EvaluationModule.compute(). Alternativamente, se pueden pasar todas las entradas a la vez a compute().

Veamos estos dos enfoques.

Todo en unolink image 8

Una vez tenemos todas las predicciones y ground truth podemos calcular la métrica. Una vez que tenemos un módulo definido, le pasamos las predicciones y los ground truth mediante el método compute()

	
accuracy = evaluate.load("accuracy")
Copy
	
accuracy = evaluate.load("accuracy")
predictions = [1, 0, 0, 1]
targets = [0, 1, 0, 1]
accuracy_value = accuracy.compute(predictions=predictions, references=targets)
accuracy_value
Copy
	
{'accuracy': 0.5}

Incrementallink image 9

En muchos procesos de evaluación, las predicciones se construyen de forma iterativa, como en un bucle for. En ese caso, podrías almacenar las predicciones y ground truth en una lista y al final pasarlas a compute().

Sin embargo con los métodos add() y add_batch() puedes evitar el paso de almacenar las predicciones.

Si tienes todas las predicciones de un solo batch hay que usar el método add()

	
for ref, pred in zip([0,1,0,1], [1,0,0,1]):
accuracy.add(references=ref, predictions=pred)
accuracy_value = accuracy.compute()
accuracy_value
Copy
	
{'accuracy': 0.5}

Sin embargo, cuando se tienen predicciones de varios batches se tiene que usar el método add_batch()

	
for refs, preds in zip([[0,1],[0,1]], [[1,0],[0,1]]):
accuracy.add_batch(references=refs, predictions=preds)
accuracy_value = accuracy.compute()
accuracy_value
Copy
	
{'accuracy': 0.5}

Combinación de varias evaluacioneslink image 10

A menudo, uno quiere no solo evaluar una única métrica, sino también una variedad de métricas diferentes que capturan diferentes aspectos de un modelo. Por ejemplo, para la clasificación suele ser una buena idea calcular el F1, el recall y la precisión además del accuracy para obtener una mejor imagen del rendimiento del modelo. Evaluate permite cargar un montón de métricas y llamarlas secuencialmente. Sin embargo, la forma más conveniente es usar la función combine() para agruparlas

	
clasification_metrics = evaluate.combine(["accuracy", "f1", "precision", "recall"])
Copy
	
clasification_metrics = evaluate.combine(["accuracy", "f1", "precision", "recall"])
predictions=[0, 1, 0]
targets=[0, 1, 1]
clasification_metrics.compute(predictions=predictions, references=targets)
Copy
	
{'accuracy': 0.6666666666666666,
'f1': 0.6666666666666666,
'precision': 1.0,
'recall': 0.5}

Guardar los resultadoslink image 11

Podemos guardar los resultados de la evaluación en un archivo con el método save(), para ello le pasamos un nombre de archivo. Podemos pasarle parámetros como el número de experimento

	
references=[0,1,0,1]
targets=[1,0,0,1]
result = accuracy.compute(references=references, predictions=targets)
hyperparams = {"model": "bert-base-uncased"}
evaluate.save("./results/", experiment="run 42", **result, **hyperparams)
Copy
	
PosixPath('results/result-2024_04_25-17_45_41.json')

Como vemos hemos tenido que crear una variable hyperparams para pasársela al método save(). Esto normalmente no hará falta porque ya tendremos los del modelo que estemos entrenando

Esto creará un json con toda la información

	
import pathlib
path = pathlib.Path("./results/")
files = list(path.glob("*"))
files
Copy
	
[PosixPath('results/result-2024_04_25-17_45_41.json')]
	
import json
result_file = files[0]
result_json = pathlib.Path(result_file).read_text()
result_dict = json.loads(result_json)
result_dict
Copy
	
{'experiment': 'run 42',
'accuracy': 0.5,
'model': 'bert-base-uncased',
'_timestamp': '2024-04-25T17:45:41.218287',
'_git_commit_hash': '8725338b6bf9c97274685df41b2ee6e11319a735',
'_evaluate_version': '0.4.1',
'_python_version': '3.11.7 (main, Dec 15 2023, 18:12:31) [GCC 11.2.0]',
'_interpreter_path': '/home/maximo.fernandez/miniconda3/envs/nlp/bin/python'}

Subir los resultados al hublink image 12

En caso de estar entrenando un modelo, podemos subir a la model card del modelo los resultados de la evaluación con el método push_to_hub(). De esta manera aparecerán en la página del modelo

Evaluadorlink image 13

Si tenemos un modelo, un dataset y una métrica, podemos hacer inferencia por todo el dataset y pasarle al evaluador las predicciones y las etiquetas reales para que nos devuelva la métrica y así obtener las métricas del modelo.

O podemos darle todo a la librería y que haga el trabajo por nosotros. Mediante el método evaluator(), le pasamos el modelo, el dataset y la métrica y el método se encarga de hacer todo por nosotros

Primero definimos el modelos, el dataset y la métrica

	
from transformers import pipeline
from datasets import load_dataset
from evaluate import evaluator
import evaluate
model_pipeline = pipeline("text-classification", model="lvwerra/distilbert-imdb", device=0)
dataset = load_dataset("imdb", split="test").shuffle().select(range(1000))
metric = evaluate.load("accuracy")
Copy

Ahora le pasamos todo a evaluator()

	
from transformers import pipeline
from datasets import load_dataset
from evaluate import evaluator
import evaluate
model_pipeline = pipeline("text-classification", model="lvwerra/distilbert-imdb", device=0)
dataset = load_dataset("imdb", split="test").shuffle().select(range(1000))
metric = evaluate.load("accuracy")
task_evaluator = evaluator("text-classification")
results = task_evaluator.compute(model_or_pipeline=model_pipeline, data=dataset, metric=metric,
label_mapping={"NEGATIVE": 0, "POSITIVE": 1},)
results
Copy
	
{'accuracy': 0.933,
'total_time_in_seconds': 29.43192940400013,
'samples_per_second': 33.97670557962431,
'latency_in_seconds': 0.02943192940400013}

Gracias al evaluador hemos podido obtener las métricas del modelo sin tener que hacer nosotros la inferencia

Visualizaciónlink image 14

A veces obtenemos distíntas métricas para diferentes modelos, lo que hace que no sea fácil poder compararlos, por lo que mediante gráficos se hace más fácil.

La librería Evaluate ofrece diferentes visualizaciones mediante el método visualization(). Tenemos que pasarle los datos como una lista de diccionarios, donde cada diccionario tiene que tener las mismas claves

Para poder usar esta función es necesario tener instalada la librería matplotlib

pip install matplotlib
      
import evaluate
      from evaluate.visualization import radar_plot
      
      data = [
         {"accuracy": 0.99, "precision": 0.8, "f1": 0.95, "latency_in_seconds": 33.6},
         {"accuracy": 0.98, "precision": 0.87, "f1": 0.91, "latency_in_seconds": 11.2},
         {"accuracy": 0.98, "precision": 0.78, "f1": 0.88, "latency_in_seconds": 87.6}, 
         {"accuracy": 0.88, "precision": 0.78, "f1": 0.81, "latency_in_seconds": 101.6}
         ]
      
      model_names = ["Model 1", "Model 2", "Model 3", "Model 4"]
      
      plot = radar_plot(data=data, model_names=model_names)
      plot.show()
      
/tmp/ipykernel_10271/263559674.py:14: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
        plot.show()
      
image hugging-face-evaluate 1

Ahora podemos comparar visualmente los 4 modelos y elegir el óptimo, en función de una o varias métricas

Evaluar el modelo en un conjunto de tareaslink image 15

Podemos evaluar un modelo, por ejemplo, para diferentes datasets. Para ello podemos usar el método evaluation_suite. Por ejmplo vamos a crear un evaluador que evalua un modelo en los conjuntos de datos imdb y sst2. Vamos a ver estos conjuntos de datos, para eso usamos el método load_dataset_builder para no tener que descargar el dataset completo

	
import evaluate
from evaluate.visualization import radar_plot
data = [
{"accuracy": 0.99, "precision": 0.8, "f1": 0.95, "latency_in_seconds": 33.6},
{"accuracy": 0.98, "precision": 0.87, "f1": 0.91, "latency_in_seconds": 11.2},
{"accuracy": 0.98, "precision": 0.78, "f1": 0.88, "latency_in_seconds": 87.6},
{"accuracy": 0.88, "precision": 0.78, "f1": 0.81, "latency_in_seconds": 101.6}
]
model_names = ["Model 1", "Model 2", "Model 3", "Model 4"]
plot = radar_plot(data=data, model_names=model_names)
plot.show()
from datasets import load_dataset_builder
imdb = load_dataset_builder("imdb")
imdb.info.features
Copy
	
/tmp/ipykernel_10271/263559674.py:14: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
plot.show()
{'text': Value(dtype='string', id=None),
'label': ClassLabel(names=['neg', 'pos'], id=None)}
	
from datasets import load_dataset_builder
sst2 = load_dataset_builder("sst2")
sst2.info.features
Copy
	
{'idx': Value(dtype='int32', id=None),
'sentence': Value(dtype='string', id=None),
'label': ClassLabel(names=['negative', 'positive'], id=None)}

Como podemos ver, con el dataset imdb necesitamos coger la columna text para obtener el texto y la columna label para obtener el target. Con el dataset sst2 necesitamos coger la columna sentence para obtener el texto y la columna label para obtener el target

Creamos el evaluador para los dos datasets

	
import evaluate
from evaluate.evaluation_suite import SubTask
class Suite(evaluate.EvaluationSuite):
def __init__(self, name):
super().__init__(name)
self.suite = [
SubTask(
task_type="text-classification",
data="imdb",
split="test[:1]",
args_for_task={
"metric": "accuracy",
"input_column": "text",
"label_column": "label",
"label_mapping": {
"LABEL_0": 0.0,
"LABEL_1": 1.0
}
}
),
SubTask(
task_type="text-classification",
data="sst2",
split="test[:1]",
args_for_task={
"metric": "accuracy",
"input_column": "sentence",
"label_column": "label",
"label_mapping": {
"LABEL_0": 0.0,
"LABEL_1": 1.0
}
}
)
]
Copy

Se puede ver en split="test[:1]", que solo cojemos un ejemplo del subconjunto de test para este notebook y que la ejecución no lleve mucho tiempo

Ahora evaluamos con el modelo huggingface/prunebert-base-uncased-6-finepruned-w-distil-mnli

from evaluate import EvaluationSuite
      suite = EvaluationSuite.load('mathemakitten/sentiment-evaluation-suite')
      results = suite.run("huggingface/prunebert-base-uncased-6-finepruned-w-distil-mnli")
      results
      
`data` is a preloaded Dataset! Ignoring `subset` and `split`.
      `data` is a preloaded Dataset! Ignoring `subset` and `split`.
      
Out[4]:
[{'accuracy': 0.3,
        'total_time_in_seconds': 1.4153412349987775,
        'samples_per_second': 7.06543394110088,
        'latency_in_seconds': 0.14153412349987776,
        'task_name': 'imdb',
        'data_preprocessor': '<function Suite.__init__.<locals>.<lambda> at 0x7f3ff27a5080>'},
       {'accuracy': 0.0,
        'total_time_in_seconds': 0.1323430729971733,
        'samples_per_second': 75.56118936586572,
        'latency_in_seconds': 0.013234307299717328,
        'task_name': 'sst2',
        'data_preprocessor': '<function Suite.__init__.<locals>.<lambda> at 0x7f3f2a9cc720>'}]

Seguir leyendo

DoLa – Decoding by Contrasting Layers Improves Factuality in Large Language Models

DoLa – Decoding by Contrasting Layers Improves Factuality in Large Language Models

¿Alguna vez has hablado con un LLM y te ha respondido algo que suena como si hubiera estado bebiendo café de máquina durante toda la noche? 😂 ¡Eso es lo que llamamos una alucinación en el mundo de los LLMs! Pero no te preocupes, porque no es que tu modelo de lenguaje esté loco (aunque a veces puede parecerlo 🤪). La verdad es que los LLMs pueden ser un poco... creativos cuando se trata de generar texto. Pero gracias a DoLa, un método que utiliza capas de contraste para mejorar la factibilidad de los LLMs, podemos evitar que nuestros modelos de lenguaje se conviertan en escritores de ciencia ficción 😂. En este post, te explicaré cómo funciona DoLa y te mostraré un ejemplo de código para que puedas entender mejor cómo hacer que tus LLMs sean más fiables y menos propensos a inventar historias. ¡Vamos a salvar a nuestros LLMs de la locura y hacer que sean más útiles! 🚀

Últimos posts -->

¿Has visto estos proyectos?

Subtify

Subtify Subtify

Generador de subtítulos para videos en el idioma que desees. Además a cada persona le pone su subtítulo de un color

Ver todos los proyectos -->

¿Quieres aplicar la IA en tu proyecto? Contactame!

¿Quieres mejorar con estos tips?

Últimos tips -->

Usa esto en local

Los espacios de Hugging Face nos permite ejecutar modelos con demos muy sencillas, pero ¿qué pasa si la demo se rompe? O si el usuario la elimina? Por ello he creado contenedores docker con algunos espacios interesantes, para poder usarlos de manera local, pase lo que pase. De hecho, es posible que si pinchas en alún botón de ver proyecto te lleve a un espacio que no funciona.

Ver todos los contenedores -->

¿Quieres aplicar la IA en tu proyecto? Contactame!

¿Quieres entrenar tu modelo con estos datasets?

short-jokes-dataset

Dataset de chistes en inglés

opus100

Dataset con traducciones de inglés a español

netflix_titles

Dataset con películas y series de Netflix

Ver más datasets -->