Instructions to use SinhalaMMLU-SharedTask/team-sinbotics with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use SinhalaMMLU-SharedTask/team-sinbotics with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Download training/sinmmlu/build_dev.py from SinhalaMMLU-SharedTask/team-sinbotics: direct link, hf CLI and curl.
- Browser
- Download file 5.39 kB
-
https://huggingface.co/SinhalaMMLU-SharedTask/team-sinbotics/resolve/main/training/sinmmlu/build_dev.py
- Command line
-
hf download hf://SinhalaMMLU-SharedTask/team-sinbotics/training/sinmmlu/build_dev.py
-
curl -L -o build_dev.py https://huggingface.co/SinhalaMMLU-SharedTask/team-sinbotics/resolve/main/training/sinmmlu/build_dev.py
5.39 kB
| """Validate the public data and build the labelled dev files from public train (Easy only). | |
| dev/archive/easy_full.jsonl all 1,851 public-train questions | |
| dev/archive/easy_clean.jsonl minus the questions with a near-duplicate in the test set (full Jaccard >= 0.5) | |
| dev/archive/inference_subset.jsonl 20 random questions per subject from easy_clean (14 x 20 = 280): screening set for | |
| inference conditions (prompts, scoring, translation) before any training | |
| dev/archive/fewshot_pool.jsonl 5 fixed examples per subject (not in the subset), the only source of few-shot examples | |
| dev/archive/inference_rest.jsonl the rest of easy_clean: confirmation set for the screening winners | |
| Every dev row carries `overlaps_test`. The uid lists are also written to configs/subsets/ (tracked; dev/ is not). | |
| Usage: python -m sinmmlu.build_dev [--per-subject 20 --shots 5 --seed 42] | |
| """ | |
| import argparse | |
| import collections | |
| import random | |
| from . import dedup | |
| from .data import ROOT, load_test, load_train, subject_si, write_jsonl | |
| SUBSET_DIR = ROOT / "configs" / "subsets" | |
| FIELDS = ("uid", "q_no", "subject", "category", "level", "file", "question", "choices") | |
| def check(rows, name, labelled): | |
| bad = [r["uid"] for r in rows if len(r["choices"]) != 4 | |
| or (labelled and int(r.get("answer", 0)) not in (1, 2, 3, 4))] | |
| keys = collections.Counter((r["level"], r["subject"], r["category"], r["q_no"]) for r in rows) | |
| dups = [k for k, v in keys.items() if v > 1] | |
| print(f"{name}: n={len(rows)} files={len({r['file'] for r in rows})} bad={len(bad)} duplicate_keys={len(dups)} " | |
| f"levels={dict(collections.Counter(r['level'] for r in rows))}") | |
| if labelled: | |
| print(" answers:", dict(sorted(collections.Counter(int(r["answer"]) for r in rows).items()))) | |
| assert not bad and not dups, (bad[:5], dups[:5]) | |
| def slim(r): | |
| out = {k: r[k] for k in FIELDS} | |
| out.update(subject_si=subject_si(r), answer=int(r["answer"]), year=r.get("metadata", {}).get("year")) | |
| return out | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--per-subject", type=int, default=20) | |
| ap.add_argument("--shots", type=int, default=5, help="few-shot examples kept per subject") | |
| ap.add_argument("--seed", type=int, default=42) | |
| a = ap.parse_args() | |
| train, test = load_train(), load_test() | |
| check(train, "public train", True) | |
| check(test, "public test", False) | |
| dup = dedup.overlapping_uids(train, test, remove_t=dedup.THRESHOLDS["public"][0]) | |
| rows = [dict(slim(r), overlaps_test=r["uid"] in dup) for r in train] | |
| write_jsonl("dev/archive/easy_full.jsonl", rows) | |
| clean = [r for r in rows if not r["overlaps_test"]] | |
| write_jsonl("dev/archive/easy_clean.jsonl", clean) | |
| print(f"dev/archive/easy_full.jsonl n={len(rows)}; dev/archive/easy_clean.jsonl n={len(clean)} ({len(dup)} overlap the test set)") | |
| sub = inference_subset(clean, a.per_subject, a.seed) | |
| chosen = {r["uid"] for r in sub} | |
| pool = fewshot_pool([r for r in clean if r["uid"] not in chosen], a.shots, a.seed) | |
| chosen |= {r["uid"] for r in pool} | |
| rest = [r for r in clean if r["uid"] not in chosen] | |
| write_jsonl("dev/archive/inference_subset.jsonl", sub) | |
| write_jsonl("dev/archive/fewshot_pool.jsonl", pool) | |
| write_jsonl("dev/archive/inference_rest.jsonl", rest) | |
| SUBSET_DIR.mkdir(parents=True, exist_ok=True) | |
| for name, rs in (("inference_subset", sub), ("fewshot_pool", pool), ("inference_rest", rest)): | |
| (SUBSET_DIR / f"{name}_uids.txt").write_text("".join(r["uid"] + "\n" for r in rs), encoding="utf-8", newline="\n") | |
| print(f"dev/archive/inference_subset.jsonl n={len(sub)} ({a.per_subject} per subject, seed {a.seed}); " | |
| f"dev/archive/fewshot_pool.jsonl n={len(pool)} ({a.shots} per subject); dev/archive/inference_rest.jsonl n={len(rest)}; " | |
| f"uid lists -> {SUBSET_DIR.relative_to(ROOT)}") | |
| def inference_subset(rows, per_subject, seed): | |
| """`per_subject` random questions from every subject (= source file), same seed -> same questions.""" | |
| rng = random.Random(seed) | |
| by_file = collections.defaultdict(list) | |
| for r in sorted(rows, key=lambda r: (r["file"], r["q_no"])): | |
| by_file[r["file"]].append(r) | |
| out = [] | |
| for f in sorted(by_file): | |
| assert len(by_file[f]) >= per_subject, f"{f} has only {len(by_file[f])} questions" | |
| out += sorted(rng.sample(by_file[f], per_subject), key=lambda r: r["q_no"]) | |
| return out | |
| def fewshot_pool(rows, shots, seed): | |
| """`shots` examples per subject; the first four have four different answers (where possible) so that a k-shot | |
| prompt does not teach a position bias. Order inside a subject = the order used for k-shot (first k).""" | |
| rng = random.Random(seed + 1) | |
| by_file = collections.defaultdict(list) | |
| for r in sorted(rows, key=lambda r: (r["file"], r["q_no"])): | |
| by_file[r["file"]].append(r) | |
| out = [] | |
| for f in sorted(by_file): | |
| cands = by_file[f][:] | |
| rng.shuffle(cands) | |
| picked, seen = [], set() | |
| for r in cands: | |
| if r["answer"] not in seen: | |
| picked.append(r) | |
| seen.add(r["answer"]) | |
| picked = picked[:min(4, shots)] | |
| picked += [r for r in cands if r not in picked][:shots - len(picked)] | |
| out += picked | |
| return out | |
| if __name__ == "__main__": | |
| main() | |