Download scripts/eval-holdout.py from arach/training-lab: direct link, hf CLI and curl.
- Browser
- Download file 3.88 kB
-
https://huggingface.co/arach/training-lab/resolve/main/scripts/eval-holdout.py
- Command line
-
hf download hf://arach/training-lab/scripts/eval-holdout.py
-
curl -L -o eval-holdout.py https://huggingface.co/arach/training-lab/resolve/main/scripts/eval-holdout.py
3.88 kB
| #!/usr/bin/env python3 | |
| """Compare v2 vs v3 on the full held-out test split (66 entries).""" | |
| import json | |
| import time | |
| from collections import defaultdict | |
| from mlx_lm import load, generate | |
| SYS = "Reconstruct the intended syntax from the dictated text. Output only the result." | |
| # Load test split | |
| with open("datasets/finetune/chat/test.jsonl") as f: | |
| tests = [] | |
| for line in f: | |
| msg = json.loads(line)["messages"] | |
| tests.append({ | |
| "dictated": msg[1]["content"], | |
| "expected": msg[2]["content"], | |
| }) | |
| print(f"Loaded {len(tests)} held-out test entries\n") | |
| configs = [ | |
| { | |
| "label": "LoRA v2", | |
| "adapter": "datasets/finetune/adapters/qwen-0.5b-lora-v2", | |
| }, | |
| { | |
| "label": "LoRA v3", | |
| "adapter": "datasets/finetune/adapters/qwen-0.5b-lora-v3", | |
| }, | |
| ] | |
| all_results = {} | |
| for cfg in configs: | |
| print(f"\n{'='*60}") | |
| print(f" {cfg['label']}") | |
| print(f"{'='*60}\n") | |
| model, tokenizer = load( | |
| "mlx-community/Qwen2.5-0.5B-Instruct-4bit", | |
| adapter_path=cfg["adapter"], | |
| ) | |
| results = [] | |
| total_time = 0 | |
| for i, t in enumerate(tests): | |
| messages = [ | |
| {"role": "system", "content": SYS}, | |
| {"role": "user", "content": t["dictated"]}, | |
| ] | |
| prompt = tokenizer.apply_chat_template( | |
| messages, tokenize=False, add_generation_prompt=True | |
| ) | |
| start = time.perf_counter() | |
| got = generate(model, tokenizer, prompt=prompt, max_tokens=80, verbose=False) | |
| elapsed = time.perf_counter() - start | |
| total_time += elapsed | |
| got = got.strip() | |
| match = got == t["expected"] | |
| results.append({"match": match, "got": got, "expected": t["expected"], "dictated": t["dictated"]}) | |
| icon = "\033[32m✓\033[0m" if match else "\033[31m✗\033[0m" | |
| if not match: | |
| print(f"{icon} {i+1:>2}. \"{t['dictated']}\"") | |
| print(f" expected: {t['expected']}") | |
| print(f" got: {got}") | |
| correct = sum(1 for r in results if r["match"]) | |
| pct = round(correct / len(results) * 100, 1) | |
| avg_ms = round(total_time / len(results) * 1000) | |
| print(f"\nScore: {correct}/{len(results)} ({pct}%)") | |
| print(f"Avg latency: {avg_ms}ms") | |
| all_results[cfg["label"]] = results | |
| del model, tokenizer | |
| # Head-to-head comparison | |
| print(f"\n{'='*60}") | |
| print(" HEAD TO HEAD") | |
| print(f"{'='*60}\n") | |
| v2 = all_results["LoRA v2"] | |
| v3 = all_results["LoRA v3"] | |
| v2_only = [] # v2 right, v3 wrong | |
| v3_only = [] # v3 right, v2 wrong | |
| both_wrong = [] | |
| for i in range(len(tests)): | |
| if v2[i]["match"] and not v3[i]["match"]: | |
| v2_only.append((i, tests[i], v3[i]["got"])) | |
| elif v3[i]["match"] and not v2[i]["match"]: | |
| v3_only.append((i, tests[i], v2[i]["got"])) | |
| elif not v2[i]["match"] and not v3[i]["match"]: | |
| both_wrong.append((i, tests[i], v2[i]["got"], v3[i]["got"])) | |
| v2_correct = sum(1 for r in v2 if r["match"]) | |
| v3_correct = sum(1 for r in v3 if r["match"]) | |
| print(f"LoRA v2: {v2_correct}/{len(tests)} ({round(v2_correct/len(tests)*100,1)}%)") | |
| print(f"LoRA v3: {v3_correct}/{len(tests)} ({round(v3_correct/len(tests)*100,1)}%)") | |
| if v2_only: | |
| print(f"\nv2 correct, v3 wrong ({len(v2_only)}):") | |
| for i, t, got in v2_only: | |
| print(f" {i+1}. \"{t['dictated']}\" → expected \"{t['expected']}\" got \"{got}\"") | |
| if v3_only: | |
| print(f"\nv3 correct, v2 wrong ({len(v3_only)}):") | |
| for i, t, got in v3_only: | |
| print(f" {i+1}. \"{t['dictated']}\" → expected \"{t['expected']}\" got \"{got}\"") | |
| if both_wrong: | |
| print(f"\nBoth wrong ({len(both_wrong)}):") | |
| for i, t, v2_got, v3_got in both_wrong: | |
| print(f" {i+1}. \"{t['dictated']}\"") | |
| print(f" expected: \"{t['expected']}\"") | |
| print(f" v2: \"{v2_got}\"") | |
| print(f" v3: \"{v3_got}\"") | |