Spaces:
Running
Running
File size: 10,449 Bytes
60c1c5f a1e9cea 319595d 60c1c5f a1e9cea 60c1c5f a1e9cea 60c1c5f a1e9cea 60c1c5f a1e9cea 60c1c5f 319595d a1e9cea 60c1c5f a1e9cea 319595d a1e9cea 60c1c5f a1e9cea 60c1c5f a1e9cea 60c1c5f a1e9cea 60c1c5f ab4ccfc 60c1c5f a1e9cea 60c1c5f c7a8a09 60c1c5f ab4ccfc 60c1c5f a1e9cea 60c1c5f a1e9cea 60c1c5f a1e9cea 60c1c5f ab4ccfc 60c1c5f c7a8a09 60c1c5f c7a8a09 ab4ccfc 60c1c5f | 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 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | import json
import os
import shutil
import tempfile
import zipfile
from dataclasses import dataclass
from src.about import MMRED_GROUP_KEYS, MMRED_SUBTASK_KEYS, Tasks
from src.leaderboard.metrics import extract_exact_match_max_flexible_strict, extract_metric_value
LOGS_PUBLIC_ZIP = "logs_public.zip"
LOGS_PUBLIC_DIR = "logs_public"
RESULTS_PREFIX = "results_"
@dataclass
class ParsedResultFile:
path: str
benchmark: str
data: dict
TASK_KEY_ALIASES: dict[str, set[str]] = {
task.value.benchmark: {task.value.benchmark, task.value.col_name.lower()}
for task in Tasks
}
TASK_KEY_ALIASES["t_math"].update({"tmath", "t-math"})
for task in Tasks:
benchmark = task.value.benchmark
TASK_KEY_ALIASES[benchmark].add(benchmark.replace("_", ""))
def _normalize_task_key(task_key: str) -> str:
key = task_key.lower().removesuffix("_gen")
return key.replace("-", "_")
def _benchmark_for_task_key(task_key: str) -> str | None:
normalized = _normalize_task_key(task_key)
if normalized == "tmath":
return "t_math"
if normalized == "mmred" or normalized.startswith("mmred_"):
return "mmred"
for benchmark, aliases in TASK_KEY_ALIASES.items():
alias_norm = {_normalize_task_key(alias) for alias in aliases}
if normalized in alias_norm or normalized.startswith(benchmark):
return benchmark
return None
def _submission_name_candidates(task) -> set[str]:
benchmark = task.value.benchmark
col_name = task.value.col_name
return {
benchmark.lower(),
col_name.lower(),
benchmark.replace("_", "").lower(),
col_name.replace("-", "").lower(),
col_name.replace("-", "_").lower(),
"tmath",
}
BENCHMARKS_MAX_EXACT_MATCH = {"ruaime", "luzitania"}
def _extract_exact_match_score(benchmark: str, task_result: dict) -> float | None:
if benchmark in BENCHMARKS_MAX_EXACT_MATCH:
return extract_exact_match_max_flexible_strict(task_result)
return extract_metric_value(task_result, "exact_match")
def _extract_mmred_scores(task_key: str, task_result: dict, scores: dict[str, float]) -> None:
normalized = _normalize_task_key(task_key)
if normalized == "mmred":
value = extract_metric_value(task_result, "em.dc_aggregate")
if value is not None:
scores["em.dc_aggregate"] = value
return
if normalized in MMRED_GROUP_KEYS:
value = extract_metric_value(task_result, "em.dc_aggregate")
if value is not None:
scores[f"{normalized}::em.dc_aggregate"] = value
return
if normalized in MMRED_SUBTASK_KEYS:
value = extract_metric_value(task_result, "exact_match")
if value is not None:
scores[f"{normalized}::exact_match"] = value
def _extract_benchmark_scores(task_key: str, task_result: dict) -> dict[str, float]:
benchmark = _benchmark_for_task_key(task_key)
if benchmark is None:
return {}
if benchmark == "mmred":
scores: dict[str, float] = {}
_extract_mmred_scores(task_key, task_result, scores)
return scores
value = _extract_exact_match_score(benchmark, task_result)
if value is None:
return {}
return {"exact_match": value}
def parse_results_data(data: dict) -> dict[str, dict[str, float]]:
merged: dict[str, dict[str, float]] = {}
for task_key, task_result in data.get("results", {}).items():
if not isinstance(task_result, dict):
continue
benchmark = _benchmark_for_task_key(task_key)
if benchmark is None:
continue
scores = _extract_benchmark_scores(task_key, task_result)
if scores:
merged.setdefault(benchmark, {}).update(scores)
return merged
def get_scores_from_result(parsed: ParsedResultFile) -> dict[str, float]:
return parse_results_data(parsed.data).get(parsed.benchmark, {})
def extract_submission_archive(zip_path: str) -> str:
if not zip_path or not os.path.isfile(zip_path):
raise ValueError("Please upload a valid zip submission file.")
if not zipfile.is_zipfile(zip_path):
raise ValueError("Uploaded file is not a zip archive.")
extract_dir = tempfile.mkdtemp(prefix="mera_reason_submission_")
with zipfile.ZipFile(zip_path, "r") as archive:
archive.extractall(extract_dir)
return extract_dir
def _find_submission_root(extract_dir: str) -> str:
entries = [
name
for name in os.listdir(extract_dir)
if not name.startswith(".") and name not in ("__MACOSX",)
]
if len(entries) == 1:
only_entry = os.path.join(extract_dir, entries[0])
if os.path.isdir(only_entry):
return only_entry
return extract_dir
def _resolve_logs_public_dir(submission_root: str) -> str:
nested_zip = os.path.join(submission_root, LOGS_PUBLIC_ZIP)
nested_dir = os.path.join(submission_root, LOGS_PUBLIC_DIR)
if os.path.isfile(nested_zip):
extract_dir = tempfile.mkdtemp(prefix="mera_reason_logs_public_")
with zipfile.ZipFile(nested_zip, "r") as archive:
archive.extractall(extract_dir)
return extract_dir
if os.path.isdir(nested_dir):
return nested_dir
raise ValueError(
f"Submission must contain `{LOGS_PUBLIC_ZIP}` or `{LOGS_PUBLIC_DIR}/` with evaluation logs."
)
def _collect_submission_json_files(submission_root: str) -> dict[str, str]:
files = {}
for name in os.listdir(submission_root):
if not name.endswith(".json") or name == LOGS_PUBLIC_ZIP:
continue
path = os.path.join(submission_root, name)
if os.path.isfile(path):
files[os.path.splitext(name)[0].lower()] = path
return files
def validate_submission_files(submission_root: str) -> list[str]:
submission_files = _collect_submission_json_files(submission_root)
missing = []
for task in Tasks:
candidates = _submission_name_candidates(task)
if not any(candidate in submission_files for candidate in candidates):
missing.append(task.value.col_name)
return missing
def _iter_results_files(*roots: str):
seen = set()
for root in roots:
if not os.path.isdir(root):
continue
for name in sorted(os.listdir(root)):
if not name.startswith(RESULTS_PREFIX) or not name.endswith(".json"):
continue
path = os.path.join(root, name)
if path in seen:
continue
seen.add(path)
yield path
def _count_results_files(*roots: str) -> int:
count = 0
for root in roots:
if not os.path.isdir(root):
continue
for name in os.listdir(root):
if name.startswith(RESULTS_PREFIX) and name.endswith(".json"):
count += 1
return count
def parse_logs_public_results(logs_public_dir: str, submission_root: str | None = None) -> dict[str, dict[str, float]]:
merged: dict[str, dict[str, float]] = {}
roots = [logs_public_dir]
if submission_root:
roots.append(submission_root)
for path in _iter_results_files(*roots):
with open(path, encoding="utf-8") as fp:
data = json.load(fp)
for benchmark, scores in parse_results_data(data).items():
merged.setdefault(benchmark, {}).update(scores)
return merged
def _fill_missing_benchmarks(
parsed_results: dict[str, dict[str, float]],
) -> tuple[dict[str, dict[str, float]], list[str]]:
"""Ensure all benchmarks are present; missing tasks score 0."""
complete: dict[str, dict[str, float]] = {}
missing_names: list[str] = []
for task in Tasks:
benchmark = task.value.benchmark
primary = task.value.primary_metric
raw_scores = parsed_results.get(benchmark, {})
if raw_scores and primary in raw_scores:
complete[benchmark] = raw_scores
continue
if benchmark not in parsed_results or not raw_scores:
missing_names.append(task.value.col_name)
if raw_scores:
complete[benchmark] = {primary: 0.0, **raw_scores}
else:
complete[benchmark] = {primary: 0.0}
return complete, missing_names
def build_normalized_result_payload(
results: dict[str, dict[str, float]],
model_name: str,
team: str,
) -> dict:
return {
"model": model_name,
"team": team,
"results": results,
}
def process_submission_zip(
zip_path: str,
model_name: str,
team: str,
) -> tuple[dict, dict[str, dict[str, float]], list[str], list[str]]:
extract_dir = extract_submission_archive(zip_path)
logs_public_dir = None
try:
submission_root = _find_submission_root(extract_dir)
missing_files = validate_submission_files(submission_root)
logs_public_dir = _resolve_logs_public_dir(submission_root)
parsed_results = parse_logs_public_results(logs_public_dir, submission_root)
if not parsed_results:
roots = [logs_public_dir]
if submission_root:
roots.append(submission_root)
has_results = _count_results_files(*roots) > 0
if has_results:
detail = "Found results_*.json files but could not extract leaderboard metrics from them."
else:
detail = (
"logs_public contains no results_*.json files (only samples are not enough). "
"Re-pack the submission with log_to_reasoning_submission.py after evaluation."
)
raise ValueError(
f"No leaderboard task scores found in logs_public. {detail} "
f"Expected results for: {', '.join(t.value.col_name for t in Tasks)}."
)
parsed_results, missing_benchmarks = _fill_missing_benchmarks(parsed_results)
resolved_model = model_name.strip()
if not resolved_model:
raise ValueError("Model name is required.")
payload = build_normalized_result_payload(parsed_results, resolved_model, team)
return payload, parsed_results, missing_files, missing_benchmarks
finally:
shutil.rmtree(extract_dir, ignore_errors=True)
if logs_public_dir and logs_public_dir.startswith(tempfile.gettempdir()):
shutil.rmtree(logs_public_dir, ignore_errors=True)
|