Hugging Face Evaluate: Métricas de ML

Hugging Face Evaluate: Métricas de ML Hugging Face Evaluate: Métricas de ML

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 conjunto de datos.

Cargalink image 3

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

	
< > Input
Python
import evaluate
accuracy = evaluate.load("accuracy")
accuracy
Copied
>_ Output
			
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
&gt;&gt;&gt; accuracy_metric = evaluate.load("accuracy")
&gt;&gt;&gt; results = accuracy_metric.compute(references=[0, 1, 2, 0, 1, 2], predictions=[0, 1, 1, 2, 1, 0])
&gt;&gt;&gt; print(results)
{'accuracy': 0.5}
Example 2-The same as Example 1, except with `normalize` set to `False`.
&gt;&gt;&gt; accuracy_metric = evaluate.load("accuracy")
&gt;&gt;&gt; results = accuracy_metric.compute(references=[0, 1, 2, 0, 1, 2], predictions=[0, 1, 1, 2, 1, 0], normalize=False)
&gt;&gt;&gt; print(results)
{'accuracy': 3.0}
Example 3-The same as Example 1, except with `sample_weight` set.
&gt;&gt;&gt; accuracy_metric = evaluate.load("accuracy")
&gt;&gt;&gt; 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])
&gt;&gt;&gt; print(results)
{'accuracy': 0.8778625954198473}
""", stored examples: 0)

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

	
< > Input
Python
import evaluate
accuracy = evaluate.load("accuracy", module_type="metric")
word_length = evaluate.load("word_length", module_type="measurement")
Copied
>_ Output
			
[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 alguien al hub de Hugging Face

	
< > Input
Python
element_count = evaluate.load("lvwerra/element_count", module_type="measurement")
Copied

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 él podemos poner filtros de búsqueda.

	
< > Input
Python
evaluate.list_evaluation_modules(
module_type="comparison",
include_community=True,
with_details=True)
Copied
>_ Output
			
[{'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

	
< > Input
Python
accuracy = evaluate.load("accuracy")
Copied
	
< > Input
Python
print(f"description: {accuracy.description}")
print(f" citation: {accuracy.citation}")
print(f" features: {accuracy.features}")
print(f" inputs_description: {accuracy.inputs_description}")
print(f" homepage: {accuracy.homepage}")
print(f" license: {accuracy.license}")
print(f" codebase_urls: {accuracy.codebase_urls}")
print(f" reference_urls: {accuracy.reference_urls}")
Copied
>_ Output
			
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
&gt;&gt;&gt; accuracy_metric = evaluate.load("accuracy")
&gt;&gt;&gt; results = accuracy_metric.compute(references=[0, 1, 2, 0, 1, 2], predictions=[0, 1, 1, 2, 1, 0])
&gt;&gt;&gt; print(results)
{'accuracy': 0.5}
Example 2-The same as Example 1, except with `normalize` set to `False`.
&gt;&gt;&gt; accuracy_metric = evaluate.load("accuracy")
&gt;&gt;&gt; results = accuracy_metric.compute(references=[0, 1, 2, 0, 1, 2], predictions=[0, 1, 1, 2, 1, 0], normalize=False)
&gt;&gt;&gt; print(results)
{'accuracy': 3.0}
Example 3-The same as Example 1, except with `sample_weight` set.
&gt;&gt;&gt; accuracy_metric = evaluate.load("accuracy")
&gt;&gt;&gt; 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])
&gt;&gt;&gt; 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()

	
< > Input
Python
accuracy = evaluate.load("accuracy")
Copied
	
< > Input
Python
predictions = [1, 0, 0, 1]
targets = [0, 1, 0, 1]
accuracy_value = accuracy.compute(predictions=predictions, references=targets)
accuracy_value
Copied
>_ Output
			
{'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()

	
< > Input
Python
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
Copied
>_ Output
			
{'accuracy': 0.5}

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

	
< > Input
Python
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
Copied
>_ Output
			
{'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

	
< > Input
Python
clasification_metrics = evaluate.combine(["accuracy", "f1", "precision", "recall"])
Copied
	
< > Input
Python
predictions=[0, 1, 0]
targets=[0, 1, 1]
clasification_metrics.compute(predictions=predictions, references=targets)
Copied
>_ Output
			
{'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 del experimento

	
< > Input
Python
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)
Copied
>_ Output
			
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

	
< > Input
Python
import pathlib
path = pathlib.Path("./results/")
files = list(path.glob("*"))
files
Copied
>_ Output
			
[PosixPath('results/result-2024_04_25-17_45_41.json')]
	
< > Input
Python
import json
result_file = files[0]
result_json = pathlib.Path(result_file).read_text()
result_dict = json.loads(result_json)
result_dict
Copied
>_ Output
			
{'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 hacerlo todo por nosotros

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

	
< > Input
Python
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")
Copied

Ahora le pasamos todo a evaluator()

	
< > Input
Python
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
Copied
>_ Output
			
{'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 distintas 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
	
< > Input
Python
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()
Copied
>_ Output
			
/tmp/ipykernel_10271/263559674.py:14: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
plot.show()
>_ Output
			
&lt;Figure size 640x480 with 5 Axes&gt;

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

	
< > Input
Python
from datasets import load_dataset_builder
imdb = load_dataset_builder("imdb")
imdb.info.features
Copied
>_ Output
			
{'text': Value(dtype='string', id=None),
'label': ClassLabel(names=['neg', 'pos'], id=None)}
	
< > Input
Python
from datasets import load_dataset_builder
sst2 = load_dataset_builder("sst2")
sst2.info.features
Copied
>_ Output
			
{'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

	
< > Input
Python
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
}
}
)
]
Copied

Se puede ver en split="test[:1]", que solo cogemos 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

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

Seguir leyendo

Últimos posts -->

¿Has visto estos proyectos?

Gymnasia

Gymnasia Gymnasia
React Native
Expo
TypeScript
FastAPI
Next.js
OpenAI
Anthropic

Aplicación móvil de entrenamiento personal con asistente de IA, biblioteca de ejercicios, seguimiento de rutinas, dieta y medidas corporales

Horeca chatbot

Horeca chatbot Horeca chatbot
Python
LangChain
PostgreSQL
PGVector
React
Kubernetes
Docker
GitHub Actions

Chatbot conversacional para cocineros de hoteles y restaurantes. Un cocinero, jefe de cocina o camaeror de un hotel o restaurante puede hablar con el chatbot para obtener información de recetas y menús. Pero además implementa agentes, con los cuales puede editar o crear nuevas recetas o menús

Naviground

Naviground Naviground
Ver todos los proyectos -->
>_ Disponible para proyectos

¿Tienes un proyecto con IA?

Hablemos.

maximofn@gmail.com

Especialista en Machine Learning e Inteligencia Artificial. Desarrollo soluciones con IA generativa, agentes inteligentes y modelos personalizados.

¿Quieres ver alguna charla?

Últimas charlas -->

¿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.

Flow edit

Flow edit Flow edit

Edita imágenes con este modelo de Flow. Basándose en SD3 o FLUX puedes editar cualquier imagen y generar nuevas

FLUX.1-RealismLora

FLUX.1-RealismLora FLUX.1-RealismLora
Ver todos los contenedores -->
>_ Disponible para proyectos

¿Tienes un proyecto con IA?

Hablemos.

maximofn@gmail.com

Especialista en Machine Learning e Inteligencia Artificial. Desarrollo soluciones con IA generativa, agentes inteligentes y modelos personalizados.

¿Quieres entrenar tu modelo con estos datasets?

short-jokes-dataset

HuggingFace

Dataset de chistes en inglés

Uso: Fine-tuning de modelos de generación de texto humorístico

231K filas 2 columnas 45 MB
Ver en HuggingFace →

opus100

HuggingFace

Dataset con traducciones de inglés a español

Uso: Entrenamiento de modelos de traducción inglés-español

1M filas 2 columnas 210 MB
Ver en HuggingFace →

netflix_titles

HuggingFace

Dataset con películas y series de Netflix

Uso: Análisis de catálogo de Netflix y sistemas de recomendación

8.8K filas 12 columnas 3.5 MB
Ver en HuggingFace →
Ver más datasets -->