demo / backend /tests /test_yourbench_results.py
tfrere's picture
first commit
970eef1
raw
history blame
17.7 kB
#!/usr/bin/env python3
"""
Script pour tester les résultats de Yourbench et vérifier les datasets sur le Hub Hugging Face.
"""
import os
import sys
import json
import argparse
import requests
import tempfile
from datetime import datetime
from typing import Dict, List, Any, Optional, Tuple
# Vérifier si les bibliothèques nécessaires sont installées
try:
from dotenv import load_dotenv
from huggingface_hub import HfApi, DatasetInfo, ModelInfo
from loguru import logger
import pandas as pd
except ImportError:
print("Installation des dépendances...")
import subprocess
subprocess.run(["pip", "install", "python-dotenv", "huggingface_hub", "loguru", "pandas", "pyarrow"], check=True)
from dotenv import load_dotenv
from huggingface_hub import HfApi, DatasetInfo, ModelInfo
from loguru import logger
import pandas as pd
# Charger les variables d'environnement depuis .env
load_dotenv()
# Configuration de la journalisation
logger.remove()
logger.add(sys.stderr, format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <level>{message}</level>")
logger.add("yourbench_tests.log", rotation="10 MB", retention="1 week")
def configure_argument_parser() -> argparse.ArgumentParser:
"""Configure le parser d'arguments."""
parser = argparse.ArgumentParser(description="Tester les résultats de Yourbench et vérifier les datasets")
parser.add_argument("--dataset", type=str, help="Nom du dataset à vérifier (sans le nom de l'organisation)")
parser.add_argument("--org", type=str, default=os.environ.get("HF_ORGANIZATION", "yourbench"),
help="Organisation Hugging Face (défaut: valeur de HF_ORGANIZATION dans .env ou 'yourbench')")
parser.add_argument("--verbose", "-v", action="store_true", help="Afficher des informations détaillées")
return parser
class YourbenchTester:
"""Classe pour tester les résultats et datasets de Yourbench."""
def __init__(self, organization: str, verbose: bool = False):
"""Initialise le testeur Yourbench.
Args:
organization: Nom de l'organisation sur Hugging Face
verbose: Afficher des informations détaillées
"""
self.organization = organization
self.verbose = verbose
self.hf_token = os.environ.get("HF_TOKEN")
if not self.hf_token:
logger.error("Variable d'environnement HF_TOKEN non trouvée dans le fichier .env")
sys.exit(1)
self.api = HfApi(token=self.hf_token)
logger.info(f"Initialisation du testeur pour l'organisation: {organization}")
def test_dataset_exists(self, dataset_name: str) -> Optional[DatasetInfo]:
"""Vérifie si un dataset existe sur le Hub.
Args:
dataset_name: Nom du dataset à vérifier
Returns:
Informations sur le dataset s'il existe, None sinon
"""
full_dataset_name = f"{self.organization}/{dataset_name}"
logger.info(f"Vérification de l'existence du dataset: {full_dataset_name}")
try:
dataset_info = self.api.dataset_info(full_dataset_name)
logger.success(f"Dataset {full_dataset_name} trouvé!")
if self.verbose:
logger.info(f"ID: {dataset_info.id}")
logger.info(f"Dernière modification: {dataset_info.lastModified}")
logger.info(f"SHA: {dataset_info.sha}")
return dataset_info
except Exception as e:
logger.error(f"Impossible de trouver le dataset {full_dataset_name}: {str(e)}")
return None
def analyze_dataset_content(self, dataset_name: str) -> Tuple[bool, Dict[str, Any]]:
"""Analyse le contenu d'un dataset.
Args:
dataset_name: Nom du dataset à analyser
Returns:
Tuple contenant un booléen indiquant si l'analyse a réussi et un dictionnaire de statistiques
"""
full_dataset_name = f"{self.organization}/{dataset_name}"
logger.info(f"Analyse du contenu du dataset: {full_dataset_name}")
stats = {
"fichiers": 0,
"taille_totale": 0,
"fichiers_json": 0,
"fichiers_parquet": 0,
"a_questions": False,
"nb_questions": 0,
"structure_parquet": {},
"types_documents": set()
}
try:
# Lister les fichiers dans le dataset
files = self.api.list_repo_files(full_dataset_name, repo_type="dataset")
stats["fichiers"] = len(files)
if self.verbose:
logger.info(f"Fichiers trouvés dans le dataset: {len(files)}")
for file in files[:10]: # Limiter à 10 fichiers pour éviter un affichage trop verbeux
logger.info(f" - {file}")
if len(files) > 10:
logger.info(f" ... et {len(files) - 10} fichiers supplémentaires")
# Vérifier la présence de fichiers questions
question_files = [f for f in files if "question" in f.lower() and f.endswith(".json")]
stats["fichiers_json"] = len([f for f in files if f.endswith(".json")])
# Vérifier les fichiers Parquet qui sont utilisés par Yourbench
parquet_files = [f for f in files if f.endswith(".parquet")]
stats["fichiers_parquet"] = len(parquet_files)
if parquet_files:
logger.info(f"Fichiers Parquet trouvés: {len(parquet_files)}")
# Analyser un échantillon de fichiers Parquet
for parquet_file in parquet_files[:3]: # Limiter à 3 fichiers pour l'analyse
category = parquet_file.split('/')[0] if '/' in parquet_file else "unknown"
logger.info(f"Analyse du fichier Parquet: {parquet_file} (catégorie: {category})")
try:
# Télécharger le fichier Parquet
temp_file = self.api.hf_hub_download(
repo_id=full_dataset_name,
filename=parquet_file,
repo_type="dataset"
)
# Lire le fichier Parquet avec pandas
df = pd.read_parquet(temp_file)
# Ajouter des statistiques
stats["structure_parquet"][category] = {
"colonnes": list(df.columns),
"nb_lignes": len(df),
"exemple": df.iloc[0].to_dict() if len(df) > 0 else {}
}
# Vérifier si ce fichier contient des questions
if any(col for col in df.columns if "question" in col.lower()):
stats["a_questions"] = True
question_col = next(col for col in df.columns if "question" in col.lower())
stats["nb_questions"] = len(df)
# Récupérer un exemple de question
if len(df) > 0 and question_col in df.columns:
logger.info(f"Exemple de question: {df[question_col].iloc[0][:100]}...")
# Identifier les types de documents si disponible
if "doc_type" in df.columns and len(df) > 0:
doc_types = df["doc_type"].unique()
stats["types_documents"].update(doc_types)
except Exception as e:
logger.warning(f"Erreur lors de l'analyse du fichier {parquet_file}: {str(e)}")
# Convertir le set en liste pour la sérialisation JSON
stats["types_documents"] = list(stats["types_documents"])
if question_files:
stats["a_questions"] = True
# Analyser un fichier de questions pour comprendre sa structure
sample_file = question_files[0]
content = self.api.hf_hub_download(
repo_id=full_dataset_name,
filename=sample_file,
repo_type="dataset"
)
with open(content, 'r') as f:
data = json.load(f)
if isinstance(data, list):
stats["nb_questions"] = len(data)
elif isinstance(data, dict) and "questions" in data:
stats["nb_questions"] = len(data["questions"])
logger.success(f"Fichiers de questions trouvés: {len(question_files)}")
logger.info(f"Exemple de fichier analysé: {sample_file}")
logger.info(f"Nombre de questions trouvées: {stats['nb_questions']}")
return True, stats
except Exception as e:
logger.error(f"Erreur lors de l'analyse du dataset {full_dataset_name}: {str(e)}")
return False, stats
def check_evaluation_results(self, dataset_name: str) -> bool:
"""Vérifie s'il existe des résultats d'évaluation pour ce dataset.
Args:
dataset_name: Nom du dataset à vérifier
Returns:
True si des résultats d'évaluation existent, False sinon
"""
logger.info(f"Recherche de résultats d'évaluation pour le dataset: {dataset_name}")
try:
# Lister tous les datasets de l'organisation
datasets = self.api.list_datasets(author=self.organization)
# Chercher les datasets d'évaluation
eval_datasets = [ds for ds in datasets if ds.id.startswith(f"{self.organization}/evaluation-")]
if self.verbose:
logger.info(f"Datasets d'évaluation trouvés: {len(eval_datasets)}")
for ds in eval_datasets[:5]:
logger.info(f" - {ds.id}")
# Vérifier si le dataset spécifié est mentionné dans les évaluations
for eval_ds in eval_datasets:
try:
# Télécharger le README pour voir si le dataset est mentionné
readme_path = self.api.hf_hub_download(
repo_id=eval_ds.id,
filename="README.md",
repo_type="dataset"
)
with open(readme_path, 'r') as f:
readme_content = f.read()
if dataset_name in readme_content:
logger.success(f"Résultats d'évaluation trouvés dans: {eval_ds.id}")
return True
except:
continue
logger.warning(f"Aucun résultat d'évaluation trouvé pour le dataset: {dataset_name}")
return False
except Exception as e:
logger.error(f"Erreur lors de la recherche de résultats d'évaluation: {str(e)}")
return False
def check_model_performances(self, dataset_name: str) -> Dict[str, float]:
"""Vérifie les performances des modèles sur le dataset spécifié.
Args:
dataset_name: Nom du dataset à vérifier
Returns:
Dictionnaire des performances des modèles (model_name -> score)
"""
logger.info(f"Vérification des performances des modèles sur le dataset: {dataset_name}")
performances = {}
try:
# Cette partie est spéculative car nous ne connaissons pas la structure exacte
# des résultats. Une approche possible serait de chercher des fichiers JSON
# contenant des métriques dans les datasets d'évaluation.
# Chercher les datasets d'évaluation
datasets = self.api.list_datasets(author=self.organization)
eval_datasets = [ds for ds in datasets if ds.id.startswith(f"{self.organization}/evaluation-")]
for eval_ds in eval_datasets:
try:
files = self.api.list_repo_files(eval_ds.id, repo_type="dataset")
result_files = [f for f in files if "result" in f.lower() and f.endswith(".json")]
for result_file in result_files:
file_path = self.api.hf_hub_download(
repo_id=eval_ds.id,
filename=result_file,
repo_type="dataset"
)
with open(file_path, 'r') as f:
results = json.load(f)
# Analyse basique des résultats (à adapter selon la structure réelle)
if "model_name" in results and "metrics" in results:
model_name = results["model_name"]
metrics = results["metrics"]
# Prendre la première métrique trouvée comme score
if metrics and isinstance(metrics, dict):
first_metric = list(metrics.keys())[0]
performances[model_name] = metrics[first_metric]
except:
continue
if performances:
logger.success(f"Performances trouvées pour {len(performances)} modèles")
for model, score in performances.items():
logger.info(f" - {model}: {score}")
else:
logger.warning("Aucune performance de modèle trouvée")
return performances
except Exception as e:
logger.error(f"Erreur lors de la vérification des performances: {str(e)}")
return {}
def main():
"""Fonction principale."""
parser = configure_argument_parser()
args = parser.parse_args()
if not args.dataset:
logger.error("Veuillez spécifier un dataset avec --dataset")
parser.print_help()
return
# Créer le testeur
tester = YourbenchTester(args.org, args.verbose)
# 1. Vérifier l'existence du dataset
dataset_info = tester.test_dataset_exists(args.dataset)
if not dataset_info:
logger.error(f"Le dataset {args.org}/{args.dataset} n'existe pas ou n'est pas accessible")
return
# 2. Analyser le contenu du dataset
success, stats = tester.analyze_dataset_content(args.dataset)
if success:
logger.info("\n=== Statistiques du dataset ===")
logger.info(f"Nombre de fichiers: {stats['fichiers']}")
logger.info(f"Fichiers JSON: {stats['fichiers_json']}")
logger.info(f"Fichiers Parquet: {stats['fichiers_parquet']}")
logger.info(f"Contient des questions: {'Oui' if stats['a_questions'] else 'Non'}")
if stats['a_questions']:
logger.info(f"Nombre de questions: {stats['nb_questions']}")
if 'types_documents' in stats and stats['types_documents']:
logger.info(f"Types de documents: {', '.join(stats['types_documents'])}")
# Afficher la structure des fichiers Parquet
if 'structure_parquet' in stats and stats['structure_parquet']:
logger.info("\n=== Structure des fichiers Parquet ===")
for category, info in stats['structure_parquet'].items():
logger.info(f"\nCatégorie: {category}")
logger.info(f"Nombre de lignes: {info['nb_lignes']}")
logger.info(f"Colonnes: {', '.join(info['colonnes'])}")
if args.verbose and 'exemple' in info and info['exemple']:
logger.info("\nExemple de ligne:")
for key, value in info['exemple'].items():
# Tronquer les valeurs trop longues
if isinstance(value, str) and len(value) > 100:
value = value[:100] + "..."
logger.info(f" {key}: {value}")
# 3. Vérifier s'il existe des résultats d'évaluation
has_evaluations = tester.check_evaluation_results(args.dataset)
if has_evaluations:
# 4. Vérifier les performances des modèles
performances = tester.check_model_performances(args.dataset)
if performances:
logger.info("\n=== Classement des modèles ===")
# Trier les modèles par score (du plus élevé au plus bas)
sorted_models = sorted(performances.items(), key=lambda x: x[1], reverse=True)
for i, (model, score) in enumerate(sorted_models, 1):
logger.info(f"{i}. {model}: {score:.4f}")
logger.success("Test terminé !")
if __name__ == "__main__":
main()