Download source/scripts/benchmarks/report_ime_metrics.py from Voltline/vimeml-tiny-zh-v1: direct link, hf CLI and curl.
- Browser
- Download file 4.46 kB
-
https://huggingface.co/Voltline/vimeml-tiny-zh-v1/resolve/main/source/scripts/benchmarks/report_ime_metrics.py
- Command line
-
hf download hf://Voltline/vimeml-tiny-zh-v1/source/scripts/benchmarks/report_ime_metrics.py
-
curl -L -o report_ime_metrics.py https://huggingface.co/Voltline/vimeml-tiny-zh-v1/resolve/main/source/scripts/benchmarks/report_ime_metrics.py
4.46 kB
| """Registered IME metrics (configs/ime-metrics-v2.json) on completed FP32 rerank scores. | |
| Reads only completed `scores.jsonl` files; no model is run. For each model and track it | |
| reports exact, notation-lenient and pool-conditional Top-1, and for each model pair the | |
| paired gain/loss with per-item McNemar, the cluster sign-flip p-value and cluster | |
| bootstrap interval under author, template and union clusters. | |
| """ | |
| import argparse | |
| import hashlib | |
| import json | |
| import sys | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parents[2] | |
| sys.path.insert(0, str(ROOT / 'src')) | |
| from vimeml.training.data import write_json | |
| from vimeml.benchmarks.notation import error_class | |
| from vimeml.benchmarks import statistics | |
| POLICY = ROOT / 'configs/ime-metrics-v2.json' | |
| TRACKS = ['standard-development', 'legacy-regression', 'ajimee', 'historical-development'] | |
| MODELS = { | |
| 'v21': ROOT / 'outputs/evaluation-v4-20261015/v21', | |
| 'v42-e20': ROOT / 'outputs/evaluation-v42-20261020', | |
| 'v43-10ep': ROOT / 'outputs/evaluation-v43-20261020/epoch10', | |
| 'v43-e30': ROOT / 'outputs/evaluation-v43-20261020/epoch30', | |
| 'v5-10ep': ROOT / 'outputs/evaluation-v5-20261021/epoch10', | |
| 'v5-e30': ROOT / 'outputs/evaluation-v5-20261021/epoch30', | |
| } | |
| PAIRS = [('v21', 'v42-e20'), ('v42-e20', 'v43-e30'), ('v42-e20', 'v5-e30'), | |
| ('v43-10ep', 'v5-10ep'), ('v43-e30', 'v5-e30')] | |
| OUTCOMES = {'exact': ('correct',), 'notation_lenient': ('correct', 'notation')} | |
| def read_rows(path): | |
| with open(path, encoding='utf-8') as handle: | |
| return [json.loads(line) for line in handle] | |
| def code_hashes(policy): | |
| return {name: hashlib.sha256((ROOT / path).read_bytes()).hexdigest() for name, path in policy['code'].items()} | |
| def main(): | |
| parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) | |
| parser.add_argument('--output', type=Path, required=True, help='Separate empty output directory') | |
| args = parser.parse_args() | |
| out = args.output.resolve() | |
| if out.exists() and any(out.iterdir()): | |
| parser.error('Use an empty output directory') | |
| policy = json.loads(POLICY.read_text(encoding='utf-8')) | |
| summary = {'policy': str(POLICY.relative_to(ROOT)), 'policy_sha256': hashlib.sha256(POLICY.read_bytes()).hexdigest(), | |
| 'code_sha256': code_hashes(policy), 'models': {k: str(v.relative_to(ROOT)) for k, v in MODELS.items()}, | |
| 'blind_read': False, 'reference_read': False, 'tracks': {}} | |
| for track in TRACKS: | |
| rows = {name: read_rows(folder / track / 'scores.jsonl') for name, folder in MODELS.items()} | |
| base = rows['v21'] | |
| for name, data in rows.items(): | |
| assert [r['id'] for r in data] == [r['id'] for r in base], (track, name) | |
| assert all(r['answers'] == b['answers'] and r['orders']['azookey'] == b['orders']['azookey'] | |
| for r, b in zip(data, base)), (track, name) | |
| reachable = [any(a in {c['text'] for c in r['candidates']} for a in r['answers']) for r in base] | |
| labels = {'author': statistics.clusters(base, template=None), | |
| 'template': statistics.clusters([{'answers': r['answers']} for r in base]), | |
| 'union': statistics.clusters(base)} | |
| classes = {name: [error_class(r, r['orders']['lm_context_sum'][0])[0] for r in data] for name, data in rows.items()} | |
| entry = {'cases': len(base), 'pool_reachable': sum(reachable), | |
| 'clusters': {k: len(set(v)) for k, v in labels.items()}, 'models': {}, 'paired': {}} | |
| for name, items in classes.items(): | |
| exact = items.count('correct') | |
| entry['models'][name] = {'exact': exact, 'notation_lenient': exact + items.count('notation'), | |
| 'pool_conditional': exact / sum(reachable)} | |
| for a, b in PAIRS: | |
| result = {} | |
| for metric, ok in OUTCOMES.items(): | |
| before = [c in ok for c in classes[a]] | |
| after = [c in ok for c in classes[b]] | |
| result[metric] = {scheme: statistics.paired(before, after, lab) for scheme, lab in labels.items()} | |
| entry['paired'][f'{a}->{b}'] = result | |
| summary['tracks'][track] = entry | |
| print(track, json.dumps({k: entry['models'][k] for k in entry['models']}), flush=True) | |
| out.mkdir(parents=True, exist_ok=True) | |
| write_json(out / 'summary.json', summary) | |
| if __name__ == '__main__': | |
| main() | |