Download code/corpus_eval.py from GermannM/kenga-prophet-m5: direct link, hf CLI and curl.
- Browser
- Download file 4.22 kB
-
https://huggingface.co/GermannM/kenga-prophet-m5/resolve/main/code/corpus_eval.py
- Command line
-
hf download hf://GermannM/kenga-prophet-m5/code/corpus_eval.py
-
curl -L -o corpus_eval.py https://huggingface.co/GermannM/kenga-prophet-m5/resolve/main/code/corpus_eval.py
4.22 kB
| """tools/corpus_eval.py — generation eval on Corpus Factory test split. | |
| For each test record, prompt = first function block only; the model must | |
| generate the rest (helper functions + main with a correct call). Programs | |
| are verified by kenga-lite; stdout must equal the record's ground truth. | |
| Metrics per directive point 8: compile-ok, run-ok, greedy match, pass@k. | |
| Usage: | |
| python tools/corpus_eval.py --model m42 --test minds/corpus_factory/split/test.jsonl | |
| """ | |
| import argparse | |
| import collections | |
| import json | |
| import os | |
| import sys | |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) | |
| import kenchat | |
| CODECS = { | |
| 'm37': 'minds/kenga_digits.pkl', | |
| 'm40': 'minds/kenga_full.pkl', | |
| 'm41': 'minds/kenga_full.pkl', | |
| 'm42': 'minds/kenga_full.pkl', | |
| 'm5': 'minds/kenga_full.pkl', | |
| } | |
| WEIGHTS = {m: f'minds/mid_prophet_{m}_w.txt' for m in CODECS} | |
| def first_fn_block(src): | |
| """Prompt prefix: source up to and including the first top-level '}'.' | |
| The model must continue with helper functions and main.""" | |
| depth = 0 | |
| for i, ch in enumerate(src): | |
| if ch == '{': | |
| depth += 1 | |
| elif ch == '}': | |
| depth -= 1 | |
| if depth == 0: | |
| return src[:i + 1] | |
| return src | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument('--model', required=True, choices=list(CODECS)) | |
| ap.add_argument('--test', default='minds/corpus_factory/split/test.jsonl') | |
| ap.add_argument('--limit', type=int, default=100) | |
| ap.add_argument('--max-tokens', type=int, default=200) | |
| ap.add_argument('-k', type=int, default=8, help='pass@k sampling budget') | |
| args = ap.parse_args() | |
| weights = WEIGHTS[args.model] | |
| codec = kenchat.load_codec_vocab(CODECS[args.model]) | |
| recs = [] | |
| with open(args.test, encoding='utf-8') as f: | |
| for line in f: | |
| line = line.strip() | |
| if line: | |
| recs.append(json.loads(line)) | |
| recs = recs[:args.limit] | |
| stats = collections.defaultdict(lambda: [0, 0, 0, 0]) # compile,run,match,passk | |
| n = 0 | |
| for r in recs: | |
| prompt = first_fn_block(r['src']) | |
| # greedy | |
| _, gsrc = kenchat.gen_tokens(prompt, weights, max_tokens=args.max_tokens, | |
| temperature=None, codec=codec) | |
| full = kenchat.make_valid_program(prompt, gsrc) | |
| rc, out, _ = kenchat.run_via_kenga_lite(full, timeout=10) | |
| first = out.strip().split('\n')[0] if out else '' | |
| ok_compile = rc == 0 | |
| ok_match = first == r['out'] | |
| passed_k = ok_match | |
| # pass@k: sampled candidates until match | |
| if not passed_k and args.k > 1: | |
| for i in range(args.k - 1): | |
| _, ssrc = kenchat.gen_tokens(prompt, weights, | |
| max_tokens=args.max_tokens, | |
| temperature=1.0, codec=codec, seed=i) | |
| ffull = kenchat.make_valid_program(prompt, ssrc) | |
| frc, fout, _ = kenchat.run_via_kenga_lite(ffull, timeout=10) | |
| ffirst = fout.strip().split('\n')[0] if fout else '' | |
| if frc == 0 and ffirst == r['out']: | |
| passed_k = True | |
| break | |
| st = stats[r['category']] | |
| st[0] += int(ok_compile) | |
| st[1] += int(ok_compile and rc == 0) | |
| st[2] += int(ok_match) | |
| st[3] += int(passed_k) | |
| n += 1 | |
| tot = [0, 0, 0, 0] | |
| print(f'model={args.model} test={args.test} programs={n} pass@{args.k}') | |
| print(f'{"category":10s} {"compile":>10s} {"run":>10s} {"match":>10s} {"pass@k":>10s}') | |
| for cat in sorted(stats): | |
| c, ru, m_, pk = stats[cat] | |
| tot[0] += c; tot[1] += ru; tot[2] += m_; tot[3] += pk | |
| print(f'{cat:10s} {c:>6d}/{n:<3d} {ru:>6d}/{n:<3d} ' | |
| f'{m_:>6d}/{n:<3d} {pk:>6d}/{n:<3d}') | |
| print(f'{"TOTAL":10s} {tot[0]:>6d}/{n:<3d} {tot[1]:>6d}/{n:<3d} ' | |
| f'{tot[2]:>6d}/{n:<3d} {tot[3]:>6d}/{n:<3d}') | |
| pct = lambda x: f'{100*x/n:.1f}%' | |
| print(f'\ncompile {pct(tot[0])} run {pct(tot[1])} ' | |
| f'match(greedy) {pct(tot[2])} match(pass@{args.k}) {pct(tot[3])}') | |
| return 0 | |
| if __name__ == '__main__': | |
| sys.exit(main()) | |