benchmark-contamination-scan

Par mkurman · zorai

Analyse les données d'entraînement pour détecter toute contamination par les benchmarks — chevauchement de n-grammes, similarité par embedding et détection exacte de marqueurs sur 60+ jeux de données d'évaluation.

npx skills add https://github.com/mkurman/zorai --skill benchmark-contamination-scan

Scan de Contamination Benchmark

Aperçu

S'entraîner sur des benchmarks est le péché cardinal du ML. Cette skill scanne vos données d'entraînement contre une liste d'exclusion curée de 60+ benchmarks en utilisant le chevauchement d'n-grammes (rapide, haute précision) et la similarité d'embedding (lent, haute précision).

Quand l'utiliser

Obligatoire avant chaque run d'entraînement. À exécuter sur les données de pré-entraînement, les données de tuning d'instructions et les données d'alignement RL.

Liste d'Exclusion

BENCHMARKS = {
    "mmlu": {"name": "MMLU", "source": "huggingface://cais/mmlu"},
    "hellaswag": {"name": "HellaSwag", "source": "huggingface://Rowan/hellaswag"},
    "gsm8k": {"name": "GSM8K", "source": "huggingface://gsm8k"},
    "humaneval": {"name": "HumanEval", "source": "huggingface://openai_humaneval"},
    "boolq": {"name": "BoolQ", "source": "huggingface://boolq"},
    "arc": {"name": "ARC", "source": "huggingface://ai2_arc"},
    "winogrande": {"name": "Winogrande", "source": "huggingface://winogrande"},
    "piqa": {"name": "PIQA", "source": "huggingface://piqa"},
    "siqa": {"name": "Social IQA", "source": "huggingface://social_i_qa"},
    "openbookqa": {"name": "OpenBookQA", "source": "huggingface://openbookqa"},
    "squad": {"name": "SQuAD", "source": "huggingface://rajpurkar/squad"},
    "natural_questions": {"name": "Natural Questions", "source": "huggingface://natural_questions"},
    "triviaqa": {"name": "TriviaQA", "source": "huggingface://trivia_qa"},
    "medqa": {"name": "MedQA", "source": "huggingface://bigbio/med_qa"},
    "pubmedqa": {"name": "PubMedQA", "source": "huggingface://pubmed_qa"},
    # Add all evaluation datasets used in your project
}

Scan de Chevauchement d'N-grammes

from collections import defaultdict
import hashlib

class ContaminationScanner:
    def __init__(self, n=13):
        self.n = n
        self.benchmark_ngrams = {}
        self._load_benchmarks()

    def _ngrams(self, text):
        tokens = text.split()
        return set(" ".join(tokens[i:i+self.n]) for i in range(len(tokens) - self.n + 1))

    def _load_benchmarks(self):
        """Load and hash all benchmark texts."""
        for bid, bm in BENCHMARKS.items():
            try:
                ds = load_dataset(bm["source"], split="test")
                all_ngrams = set()
                for example in ds:
                    text = " ".join(str(v) for v in example.values() if isinstance(v, str))
                    all_ngrams.update(self._ngrams(text))
                self.benchmark_ngrams[bid] = {
                    "ngrams": all_ngrams,
                    "n_examples": len(ds),
                }
            except Exception as e:
                print(f"Could not load {bm['name']}: {e}")

    def scan_example(self, text):
        """Check a single training example. Returns list of [benchmark, n_matches]."""
        example_ngrams = self._ngrams(text)
        if not example_ngrams:
            return []
        hits = []
        for bid, bm_data in self.benchmark_ngrams.items():
            overlap = len(example_ngrams & bm_data["ngrams"])
            if overlap > 0:
                hits.append({"benchmark": BENCHMARKS[bid]["name"], "n_matching_ngrams": overlap})
        return hits

    def scan_dataset(self, examples, threshold=5):
        """Scan full dataset. threshold = min matching ngrams to flag."""
        contaminated = []
        for i, example in enumerate(examples):
            text = " ".join(str(v) for v in example.values() if isinstance(v, str))
            hits = self.scan_example(text)
            if any(h["n_matching_ngrams"] >= threshold for h in hits):
                contaminated.append({"index": i, "hits": hits})
        return contaminated

Scan de Similarité d'Embedding

Pour la contamination sémantique (benchmarks paraphrasés) :

from sentence_transformers import SentenceTransformer, util

model = SentenceTransformer("all-MiniLM-L6-v2")

def embedding_scan(text, benchmark_texts, threshold=0.85):
    emb_text = model.encode(text)
    emb_bench = model.encode(benchmark_texts)
    scores = util.cos_sim(emb_text, emb_bench)[0]
    hits = [(i, float(s)) for i, s in enumerate(scores) if s > threshold]
    return hits

Rapport

# Rapport de Scan de Contamination
Date: [YYYY-MM-DD]
Taille n-grammes: 13
Benchmarks scannés: [N]
Exemples d'entraînement: [N]
Exemples contaminés: [N] (X,X%)
Exclus de l'entraînement: [N]

## Par Benchmark
| Benchmark | Contaminés | Action |
|-----------|-----------|--------|
| MMLU | 142 | Supprimés |
| HellaSwag | 18 | Supprimés |

Qualité

  • Tous les benchmarks connus dans la liste d'exclusion.
  • Scan n-grammes exécuté (rapide, obligatoire).
  • Scan embedding exécuté sur un échantillon (lent, recommandé).
  • Les exemples contaminés sont SUPPRIMÉS de l'entraînement, pas seulement signalés.
  • Le scan est ré-exécuté après chaque mise à jour de données.

Skills similaires