| |
| """Measure normalized exact match and token F1 on labeled JSONL examples.""" |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| import re |
| import string |
| from collections import Counter |
| from pathlib import Path |
|
|
| import torch |
| from transformers import AutoModelForSeq2SeqLM, AutoTokenizer |
|
|
|
|
| def normalize(text: str) -> str: |
| text = text.lower().translate(str.maketrans("", "", string.punctuation)) |
| return " ".join(re.sub(r"\b(a|an|the)\b", " ", text).split()) |
|
|
|
|
| def token_f1(prediction: str, target: str) -> float: |
| predicted, expected = normalize(prediction).split(), normalize(target).split() |
| if not predicted or not expected: |
| return float(predicted == expected) |
| overlap = sum((Counter(predicted) & Counter(expected)).values()) |
| if overlap == 0: |
| return 0.0 |
| precision, recall = overlap / len(predicted), overlap / len(expected) |
| return 2 * precision * recall / (precision + recall) |
|
|
|
|
| def main() -> None: |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument("data", type=Path) |
| parser.add_argument("--model", default="ShinpacheShimura/t5-smaller") |
| parser.add_argument("--subfolder", default="optimized-flan-t5-small") |
| parser.add_argument("--max-new-tokens", type=int, default=64) |
| args = parser.parse_args() |
|
|
| rows = [json.loads(line) for line in args.data.read_text().splitlines() if line.strip()] |
| if not rows or any("input" not in row or "target" not in row for row in rows): |
| raise SystemExit('Use non-empty JSONL rows with "input" and "target" fields.') |
|
|
| common = {"subfolder": args.subfolder} if args.subfolder else {} |
| tokenizer = AutoTokenizer.from_pretrained(args.model, **common) |
| model = AutoModelForSeq2SeqLM.from_pretrained(args.model, device_map="auto", **common) |
| exact, total_f1 = 0, 0.0 |
| for row in rows: |
| inputs = tokenizer(row["input"], return_tensors="pt").to(model.device) |
| with torch.inference_mode(): |
| ids = model.generate(**inputs, max_new_tokens=args.max_new_tokens, do_sample=False) |
| prediction = tokenizer.decode(ids[0], skip_special_tokens=True) |
| exact += normalize(prediction) == normalize(row["target"]) |
| total_f1 += token_f1(prediction, row["target"]) |
| print(json.dumps({**row, "prediction": prediction})) |
|
|
| count = len(rows) |
| print(json.dumps({"examples": count, "exact_match": exact / count, "token_f1": total_f1 / count}, indent=2)) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|