Download scripts/analyze_scale_parser_failures.py from Dhruv1000/tracegrpo: direct link, hf CLI and curl.
- Browser
- Download file 3.55 kB
-
https://huggingface.co/Dhruv1000/tracegrpo/resolve/main/scripts/analyze_scale_parser_failures.py
- Command line
-
hf download hf://Dhruv1000/tracegrpo/scripts/analyze_scale_parser_failures.py
-
curl -L -o analyze_scale_parser_failures.py https://huggingface.co/Dhruv1000/tracegrpo/resolve/main/scripts/analyze_scale_parser_failures.py
3.55 kB
| """Read-only prompt-cluster audit of a stopped scale run's parser failures.""" | |
| from __future__ import annotations | |
| from collections import Counter | |
| import json | |
| from pathlib import Path | |
| import sys | |
| import numpy as np | |
| import torch | |
| def audit(run_dir: Path, *, seed: int = 42, draws: int = 20_000) -> dict: | |
| manifest = json.loads((run_dir / "run_manifest.json").read_text()) | |
| completed = json.loads((run_dir / "curves.json").read_text()) | |
| pending = json.loads((run_dir / "pending_step.json").read_text()) | |
| steps = len(completed) + 1 | |
| assert pending["optimizer_step"] == steps | |
| selection = manifest["train_selection"] | |
| order = torch.randperm(len(selection), generator=torch.Generator().manual_seed( | |
| manifest["seed"])).tolist()[:steps * 64] | |
| chosen = [selection[i] for i in order] | |
| assert len(chosen) == steps * 64 | |
| labels = {row["prompt_id"]: int(row["target"]) for row in chosen} | |
| assert len(labels) == len(chosen), "a prompt recurred during the first epoch" | |
| failures = [json.loads(line) for line in (run_dir / "rollout_failures.jsonl").open()] | |
| assert all(row["prompt_id"] in labels for row in failures) | |
| assert len(failures) == sum(row["verifier_failures"] for row in completed) + pending["verifier_failures"] | |
| by_prompt = Counter(row["prompt_id"] for row in failures) | |
| counts = np.asarray([by_prompt[row["prompt_id"]] for row in chosen]) | |
| classes = np.asarray([int(row["target"]) for row in chosen]) | |
| rates = {name: float(counts[classes == label].sum() / (8 * (classes == label).sum())) | |
| for name, label in (("SAFE", 0), ("VULNERABLE", 1))} | |
| observed = rates["VULNERABLE"] - rates["SAFE"] | |
| # The eight rollouts sharing a prompt are correlated. Resample/permute | |
| # entire prompt groups rather than treating 7,680 rollouts as IID. | |
| rng = np.random.default_rng(seed) | |
| safe = counts[classes == 0] | |
| vuln = counts[classes == 1] | |
| bootstrap = np.empty(draws) | |
| permutation = np.empty(draws) | |
| for i in range(draws): | |
| bootstrap[i] = (rng.choice(vuln, len(vuln), replace=True).mean() - | |
| rng.choice(safe, len(safe), replace=True).mean()) / 8 | |
| perm = rng.permutation(counts) | |
| permutation[i] = (perm[:len(vuln)].mean() - perm[len(vuln):].mean()) / 8 | |
| return { | |
| "run_dir": str(run_dir), "seed": seed, "draws": draws, | |
| "steps_including_pending": steps, "prompts": len(chosen), | |
| "rollouts": len(chosen) * 8, "failures": len(failures), | |
| "class_counts": { | |
| name: {"prompts": int((classes == label).sum()), | |
| "rollouts": int(8 * (classes == label).sum()), | |
| "failures": int(counts[classes == label].sum()), | |
| "prompts_with_failure": int((counts[classes == label] > 0).sum()), | |
| "failure_rate": rates[name]} | |
| for name, label in (("SAFE", 0), ("VULNERABLE", 1))}, | |
| "vulnerable_minus_safe_failure_rate": observed, | |
| "prompt_cluster_bootstrap_95_interval": np.quantile(bootstrap, [.025, .975]).tolist(), | |
| "prompt_label_permutation_two_sided_p": float(np.mean(np.abs(permutation) >= abs(observed))), | |
| "prompts_with_multiple_failures": int((counts >= 2).sum()), | |
| "failures_on_multiple_failure_prompts": int(counts[counts >= 2].sum()), | |
| "max_failures_on_one_prompt": int(counts.max()), | |
| "note": "Exploratory prompt-cluster comparison; no causal or equal-rate claim.", | |
| } | |
| if __name__ == "__main__": | |
| print(json.dumps(audit(Path(sys.argv[1])), indent=2)) | |