Skip to main content

Detect benchmark contamination in large language models

Project description

benchleak 🔍

Did this model train on the test set? Find out in one command.

When a model scores 90% on GSM8K or MATH, was it genuinely capable or did it memorise the benchmark during training? Benchleak answers that with a mathematical membership-inference test on the model's own token probabilities. No LLM judges, no API calls, runs locally on any HuggingFace causal LM.

Status

🚧 Early alpha. The pre-training detector (Min-K% Prob) is implemented and runnable end to end. The SFT and RL-post-training detectors are planned but not yet built, so don't expect them yet.

Install

pip install benchleak

This pulls in torch, transformers, and datasets. To work from a clone instead, run pip install -e . in the repo root.

Usage

benchleak --model Qwen/Qwen2.5-0.5B --benchmark gsm8k

The model can be any HuggingFace-format causal LM, given as a Hub id or a local checkpoint directory. GGUF, llama.cpp, and Ollama formats are not supported.

Private or gated models

For a repository that requires authentication, provide a HuggingFace token. Any of these work:

huggingface-cli login                  # cached credential, picked up automatically
export HF_TOKEN=hf_xxx                  # environment variable
benchleak --model my/private-model --benchmark gsm8k --hf-token hf_xxx

Speed

Scoring runs one forward pass per sample. On a CPU-only machine the default --limit 200 can take many minutes; use a smaller --limit for a quick look, or --device cuda / --device mps to use a GPU.

benchleak: pre-training contamination report
====================================================
Model:       Qwen/Qwen2.5-0.5B
Benchmark:   gsm8k
Detector:    min-k% prob
Samples:     200 benchmark vs 200 reference

Separation (AUC):   0.71   [HIGH]
Significance (p):   3.2e-08
Flag thresholds:    AUC >= 0.6, p < 0.05

Verdict: LIKELY CONTAMINATED

Known benchmarks (gsm8k, math, arc-challenge, truthfulqa) work by name. For any other Hub dataset, pass the path plus its text column(s):

benchleak --model my/model --benchmark some/dataset --field question --field answer

Your own benchmark from a local file

Point --benchmark at a local file instead of a Hub id. Supported formats:

  • .txt: one passage per line (no --field needed)
  • .jsonl / .json / .csv: name the text column(s) with --field
benchleak --model my/model --benchmark ./my_benchmark.jsonl --field question --field answer

Local files are read with the standard library, so this path needs neither a network connection nor the datasets package.

How it works

The benchmark is scored against a reference set of text the model is not expected to have memorised. Min-K% Prob assigns each text the mean log-probability of its least-likely k% of tokens. Memorised text has fewer surprising tokens and scores higher. The tool then measures how strongly the benchmark's scores separate from the reference's, reported as an AUC (U / nm from a Mann-Whitney test) with a significance p-value. AUC ≈ 0.5 means the benchmark looks like fresh data; AUC well above 0.5 is the memorisation signature of contamination.

A small reference set ships with the tool so it runs out of the box. For the cleanest signal, supply your own domain-matched reference data with --reference my_reference.txt (one passage per line).

For the full reasoning (why a reference set is needed, the choice of test, and where the method can mislead), see docs/how-it-works.md.

Phase Method Status
Pre-training Min-K% probability (Shi et al. 2024) ✅ implemented
SFT Self-prompt calibration (Fu et al. 2024) ⏳ planned
RL post-training Self-Critique entropy (Tao et al. 2025) ⏳ planned

Caveats

  • A verdict needs ≥ 5 samples per side; the significance test cannot reach p < 0.05 below that.
  • The bundled reference is general-domain prose. Comparing it against a narrow-domain benchmark (e.g. math) can confound domain with memorisation; prefer a domain-matched --reference for results you intend to publish.

Troubleshooting

ModuleNotFoundError: No module named '_lzma' when loading a benchmark. The datasets library needs Python's lzma module, which is absent from some Python builds (commonly pyenv on macOS compiled without the xz library). Install xz and rebuild Python:

brew install xz
LDFLAGS="-L$(brew --prefix xz)/lib" CPPFLAGS="-I$(brew --prefix xz)/include" \
  pyenv install -f <your-python-version>

Then reuse or recreate your virtual environment. benchleak detects this case and prints the same guidance.

Citation

Implements methods from:

  • Shi et al., 2024. Detecting Pretraining Data from Large Language Models (arXiv:2310.16789)
  • Fu et al., 2024. Membership Inference via Self-Prompt Calibration
  • Tao et al., 2025. Detecting Data Contamination from RL Post-training (arXiv:2510.09259)

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

benchleak-0.1.1.tar.gz (24.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

benchleak-0.1.1-py3-none-any.whl (18.2 kB view details)

Uploaded Python 3

File details

Details for the file benchleak-0.1.1.tar.gz.

File metadata

  • Download URL: benchleak-0.1.1.tar.gz
  • Upload date:
  • Size: 24.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.11

File hashes

Hashes for benchleak-0.1.1.tar.gz
Algorithm Hash digest
SHA256 d3805b554c52c74c3f1491f00d7017f119ae0f3188e45dea1143a5c3522cdc3f
MD5 67218f3b81468eac0b7847babf793e2b
BLAKE2b-256 6925f870911e2ad296056fa39d7aead67155ef0672a11a8e3c7aa55542abf922

See more details on using hashes here.

File details

Details for the file benchleak-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: benchleak-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 18.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.11

File hashes

Hashes for benchleak-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4832f0163e78fb5017183f3b7456886aff5745b1d3e9dd0f0985a03042a742ac
MD5 e57d9b9f98dc65af0af9a69b9048e2e7
BLAKE2b-256 c056d19db0e70f73c390b85a1bf0cd9c62ccd33e7b0ec36589dcaa5f7852ff43

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page