Download scripts/run_all.py from bunyamineymen/rag-gate-stats-code: direct link, hf CLI and curl.
- Browser
- Download file 6.7 kB
-
https://huggingface.co/bunyamineymen/rag-gate-stats-code/resolve/main/scripts/run_all.py
- Command line
-
hf download hf://bunyamineymen/rag-gate-stats-code/scripts/run_all.py
-
curl -L -o run_all.py https://huggingface.co/bunyamineymen/rag-gate-stats-code/resolve/main/scripts/run_all.py
6.7 kB
| """End-to-end pipeline: data -> runs -> per-query metrics -> golden-set simulation. | |
| Latency is measured separately (scripts/latency.py) because it needs a fixed thread count. | |
| Usage: uv run python scripts/run_all.py [--datasets nfcorpus] [--R 200] [--out results] | |
| """ | |
| import argparse | |
| import hashlib | |
| import json | |
| import platform | |
| import sys | |
| import time | |
| from importlib import metadata | |
| from pathlib import Path | |
| import faiss | |
| import numpy as np | |
| import pandas as pd | |
| import yaml | |
| from gatestats import data, metrics, retrieve, simulate | |
| ROOT = Path(__file__).resolve().parents[1] | |
| CACHE = ROOT / "cache" | |
| def sha256(path): | |
| return hashlib.sha256(Path(path).read_bytes()).hexdigest() | |
| def cached(path, fn): | |
| path = Path(path) | |
| if path.exists(): | |
| return np.load(path) | |
| arr = fn() | |
| path.parent.mkdir(parents=True, exist_ok=True) | |
| np.save(path, arr) | |
| return arr | |
| def chunked(stem, texts, fn, size=4096): | |
| """Apply fn to texts in chunks saved as stem.partNNNN.npy, so an interrupted run resumes where it stopped.""" | |
| parts = [] | |
| for i, start in enumerate(range(0, len(texts), size)): | |
| part = stem.with_name(f"{stem.name}.part{i:04d}.npy") | |
| parts.append(cached(part, lambda: fn(texts[start:start + size]))) | |
| out = np.concatenate(parts) | |
| for p in stem.parent.glob(f"{stem.name}.part*.npy"): | |
| p.unlink() | |
| return out | |
| def environment(cfg_path): | |
| import torch | |
| try: | |
| import psutil | |
| ram = round(psutil.virtual_memory().total / 2**30, 1) | |
| except ImportError: | |
| ram = None | |
| libs = ["torch", "sentence-transformers", "transformers", "faiss-cpu", "bm25s", "datasets", "numpy", "scipy"] | |
| return { | |
| "started": time.strftime("%Y-%m-%dT%H:%M:%S%z"), | |
| "python": sys.version, | |
| "platform": platform.platform(), | |
| "processor": platform.processor(), | |
| "cpu_count": __import__("os").cpu_count(), | |
| "ram_gb": ram, | |
| "torch_threads": torch.get_num_threads(), | |
| "faiss_threads": faiss.omp_get_max_threads(), | |
| "libs": {name: metadata.version(name) for name in libs}, | |
| "prereg_sha256": sha256(ROOT / "prereg.md"), | |
| "config_sha256": sha256(cfg_path), | |
| } | |
| def build_runs(ds, cfg, ds_cache, keep_hnsw_s0): | |
| k = cfg["top_k"] | |
| runs = {"bm25": cached(ds_cache / "run_bm25.npy", lambda: retrieve.bm25_run( | |
| retrieve.bm25_index(ds.doc_texts), ds.query_texts, k))} | |
| emb = {} | |
| for key, mcfg in cfg["models"].items(): | |
| model = None | |
| def encode(texts, prefix): | |
| nonlocal model | |
| model = model or retrieve.load_model(mcfg, cfg["max_seq_length"]) | |
| return retrieve.embed(model, texts, prefix, cfg["batch_size"]) | |
| docs = cached(ds_cache / f"emb_{key}_docs.npy", lambda: chunked(ds_cache / f"emb_{key}_docs", ds.doc_texts, | |
| lambda t: encode(t, mcfg["doc_prefix"]))) | |
| queries = cached(ds_cache / f"emb_{key}_queries.npy", lambda: encode(ds.query_texts, mcfg["query_prefix"])) | |
| emb[key] = (docs, queries) | |
| runs[key] = cached(ds_cache / f"run_{key}.npy", lambda: retrieve.exact_run(docs, queries, k)) | |
| h = cfg["hnsw"] | |
| docs, queries = emb[h["model"]] | |
| for seed in h["seeds"]: | |
| paths = {ef: ds_cache / f"run_hnsw_ef{ef}_s{seed}.npy" for ef in h["ef_search"]} | |
| if not all(p.exists() for p in paths.values()): | |
| index, perm = retrieve.hnsw_index(docs, h["M"], h["ef_construction"], seed) | |
| for ef, p in paths.items(): | |
| np.save(p, retrieve.hnsw_run(index, perm, queries, ef, h["k"])) | |
| if seed == h["seeds"][0] and keep_hnsw_s0: | |
| faiss.write_index(index, str(ds_cache / "hnsw_s0.faiss")) | |
| np.save(ds_cache / "hnsw_s0_perm.npy", perm) | |
| for ef, p in paths.items(): | |
| runs[f"hnsw_ef{ef}_s{seed}"] = np.load(p) | |
| rng = np.random.default_rng([cfg["seed"], 11]) | |
| for rate in cfg["deletion_rates"]: | |
| deleted = rng.choice(len(ds.doc_ids), int(rate * len(ds.doc_ids)), replace=False) | |
| runs[f"del{round(rate * 100):02d}"] = retrieve.drop_docs(runs["bge"], deleted, 10) | |
| return runs | |
| def main(): | |
| p = argparse.ArgumentParser() | |
| p.add_argument("--config", default=str(ROOT / "configs" / "default.yaml")) | |
| p.add_argument("--datasets", nargs="*") | |
| p.add_argument("--R", type=int) | |
| p.add_argument("--out", default=str(ROOT / "results")) | |
| args = p.parse_args() | |
| cfg = yaml.safe_load(Path(args.config).read_text()) | |
| out = Path(args.out) | |
| out.mkdir(parents=True, exist_ok=True) | |
| env = environment(args.config) | |
| env["timings_s"], env["datasets"] = {}, {} | |
| per_query, rows_t, rows_p, rows_c = [], [], [], [] | |
| names = args.datasets or cfg["datasets"] | |
| for name in names: | |
| ds_i = cfg["datasets"].index(name) | |
| t0 = time.time() | |
| ds = data.load(name) | |
| runs = build_runs(ds, cfg, CACHE / name, keep_hnsw_s0=name == cfg["latency"]["dataset"]) | |
| systems = {s: metrics.per_query(run, ds.qrels) for s, run in runs.items()} | |
| systems.update(simulate.controlled(systems["bge"], cfg["controlled_deltas"], | |
| np.random.default_rng([cfg["seed"], ds_i, 7]))) | |
| env["timings_s"][f"{name}_runs"] = round(time.time() - t0, 1) | |
| env["datasets"][name] = {"queries": len(ds.query_ids), "docs": len(ds.doc_ids)} | |
| print(f"[{name}] N={len(ds.query_ids)} docs={len(ds.doc_ids)} systems={len(systems)} " | |
| f"bge recall@5={systems['bge']['recall@5'].mean():.4f}", flush=True) | |
| for s, vals in systems.items(): | |
| per_query.append(pd.DataFrame({"dataset": name, "system": s, "qid": ds.query_ids, **vals})) | |
| t0 = time.time() | |
| t, pr, c = simulate.simulate(name, ds_i, systems, cfg, R=args.R) | |
| rows_t += t | |
| rows_p += pr | |
| rows_c += c | |
| env["timings_s"][f"{name}_simulation"] = round(time.time() - t0, 1) | |
| print(f"[{name}] simulation {env['timings_s'][f'{name}_simulation']}s", flush=True) | |
| pd.concat(per_query).to_parquet(out / "per_query.parquet", index=False) | |
| pd.DataFrame(rows_t).to_parquet(out / "threshold.parquet", index=False) | |
| pd.DataFrame(rows_p).to_parquet(out / "pairs.parquet", index=False) | |
| pd.DataFrame(rows_c).to_parquet(out / "contrasts.parquet", index=False) | |
| env["R"] = args.R or cfg["simulation"]["R"] | |
| (out / "env.json").write_text(json.dumps(env, indent=2)) | |
| if __name__ == "__main__": | |
| main() | |