File size: 5,696 Bytes
ec24fb0 903fb32 ec24fb0 903fb32 ec24fb0 903fb32 ec24fb0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | """
Sinhala MMLU Shared Task - Final inference script
Team: Nexus
The organizers will run this file exactly as it is, changing ONLY the DATA_REPO line
below to point to the final Sinhala MMLU dataset:
pip install -r requirements.txt
python inference.py
System (see README.md): Gemma 4 E4B-it, text-only (7.463B parameters, vision/audio towers removed, weights unchanged),
no fine-tuning. Every question is answered with the model's thinking mode, greedy decoding only (no sampling).
A fast one-step answer (next-token scores over the labels 1-4, averaged over 4 cyclic option orders) is used only as a
fallback if a thinking answer cannot be read. Set SELF_CONSISTENCY = True for an earlier, sampling-based variant
(not the submitted system).
Section 2 runs the exact pipeline that produced our Codabench submission (inference/predict.py with
configs/submission_base_think_greedy.yaml), on the questions loaded by section 1.
"""
# ======================= ORGANIZERS CHANGE ONLY THIS LINE =======================
DATA_REPO = "SinhalaMMLU-SharedTask/Sinhala-MMLU-SharedTask-Test-Dataset"
# ================================================================================
OUTPUT_FILE = "predictions.jsonl"
# ----------------------- TEAM SETTINGS (keep exactly as used for your final submission)
MODEL_ID = "SinhalaMMLU-SharedTask/team-nexus-gemma-4-e4b-it-text" # text-only extraction of google/gemma-4-E4B-it
MODEL_REVISION = "8f686039aad1a865c9335c17874d9b870fdec766" # exact commit of MODEL_ID used for our submission
SEED = 1234
SELF_CONSISTENCY = False # False = our submitted system (greedy thinking only, no sampling); True = earlier sampling variant, NOT submitted
import json
import os
import random
import re
import numpy as np
import torch
from huggingface_hub import HfFileSystem, list_repo_files
def set_seed(seed):
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
# =============== 1. LOAD THE DATASET FROM HUGGING FACE (do not change) ===============
def load_questions(data_repo):
fs = HfFileSystem()
files = sorted(f for f in list_repo_files(data_repo, repo_type="dataset") if f.endswith(".json"))
rows = []
for f in files:
with fs.open(f"datasets/{data_repo}/{f}", "r", encoding="utf-8") as fh:
raw = json.load(fh)
if isinstance(raw, dict):
raw = next(v for v in raw.values() if isinstance(v, list))
for r in raw:
r["_file"] = f
rows.append(r)
return rows
def get_level(r):
return (r.get("metadata") or {}).get("difficulty") or r["_file"].split("/")[0]
# =============== 2. OUR SYSTEM ===============
# predict_all() writes the loaded questions to a temporary folder (same file layout as the dataset repo), runs
# inference/predict.py on it offline, and maps its answers back to `rows` by (level, subject, q_no).
HERE = os.path.dirname(os.path.abspath(__file__))
CONFIG = os.path.join(HERE, "configs", "submission_base_think_gated_sc.yaml" if SELF_CONSISTENCY
else "submission_base_think_greedy.yaml")
def load_system():
from huggingface_hub import snapshot_download
return snapshot_download(MODEL_ID, revision=MODEL_REVISION) # local folder with weights + tokenizer
def predict_all(system, rows):
import subprocess
import sys
import tempfile
import zipfile
import yaml
model_dir = system
with tempfile.TemporaryDirectory() as tmp:
by_file = {}
for r in rows:
by_file.setdefault(r["_file"], []).append({k: v for k, v in r.items() if k != "_file"})
for f, recs in by_file.items():
path = os.path.join(tmp, "data", f)
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w", encoding="utf-8") as fh:
json.dump(recs, fh, ensure_ascii=False)
with open(CONFIG, encoding="utf-8") as fh:
cfg = yaml.safe_load(fh)
cfg["model"] = model_dir
cfg["seed"] = SEED
cfg_path = os.path.join(tmp, "config.yaml")
with open(cfg_path, "w", encoding="utf-8") as fh:
yaml.safe_dump(cfg, fh, allow_unicode=True)
out_zip = os.path.join(tmp, "predictions.zip")
subprocess.run([sys.executable, "-m", "inference.predict", "--config", cfg_path,
"--input", os.path.join(tmp, "data"), "--output", out_zip], cwd=HERE, check=True)
with zipfile.ZipFile(out_zip) as z:
preds = [json.loads(l) for l in z.read("predictions.jsonl").decode("utf-8").splitlines() if l.strip()]
ans = {(p["level"], p["subject"], p["q_no"]): p["answer"] for p in preds}
return [ans[(get_level(r), r["subject"], r["q_no"])] for r in rows]
# =============== 3. WRITE PREDICTIONS (do not change) ===============
if __name__ == "__main__":
set_seed(SEED)
rows = load_questions(DATA_REPO)
print(len(rows), "questions loaded from", DATA_REPO)
system = load_system()
answers = predict_all(system, rows)
assert len(answers) == len(rows), "predict_all() must return one answer per question"
with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
for r, a in zip(rows, answers):
a = str(a).strip()
assert a in {"1", "2", "3", "4"}, f"invalid answer {a!r} for q_no={r.get('q_no')}"
f.write(json.dumps({
"q_no": r["q_no"],
"subject": r["subject"],
"category": r["category"],
"level": get_level(r),
"answer": a,
}, ensure_ascii=False, separators=(",", ":")) + "\n")
print("\nSaved", OUTPUT_FILE)
|