Spaces:
Running
Running
Commit ·
19eb9db
1
Parent(s): e42d567
feat: merge real (paper) results with new community results
Browse filesPreviously the board showed HF contents OR the bundled sample_results.json
(fallback) — so the first worker write would have hidden the real paper
results. Now the leaderboard treats the bundled paper results as an immutable
base and OVERLAYS new results from braindecode/contents, deduped by
(model, adapter); a freshly evaluated result wins on a same-key clash, every
other paper result is preserved. Falls back to base-only when contents is
absent. Also alias oeb 'frozen' -> arena 'probe' in results mapping so new
linear-probe results align with the paper rows and the frontend filters.
Tests: leaderboard merge + frozen->probe alias (22 passing).
backend/app/services/leaderboard.py
CHANGED
|
@@ -25,59 +25,70 @@ def _build_entry_id(data: Dict[str, Any]) -> str:
|
|
| 25 |
)
|
| 26 |
|
| 27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
class LeaderboardService:
|
| 29 |
def __init__(self):
|
| 30 |
pass
|
| 31 |
|
| 32 |
async def fetch_raw_data(self) -> List[Dict[str, Any]]:
|
| 33 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
try:
|
| 35 |
logger.info(LogFormatter.section("FETCHING LEADERBOARD DATA"))
|
| 36 |
|
| 37 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
try:
|
| 39 |
-
logger.info(LogFormatter.info(f"Loading dataset from {HF_ORGANIZATION}/contents"))
|
| 40 |
dataset = datasets.load_dataset(
|
| 41 |
f"{HF_ORGANIZATION}/contents",
|
| 42 |
-
cache_dir=cache_config.get_cache_path("datasets")
|
|
|
|
| 43 |
)["train"]
|
| 44 |
-
|
| 45 |
-
df = dataset.to_pandas()
|
| 46 |
-
data = df.to_dict('records')
|
| 47 |
-
|
| 48 |
-
stats = {
|
| 49 |
-
"Total_Entries": len(data),
|
| 50 |
-
"Dataset_Size": f"{df.memory_usage(deep=True).sum() / 1024 / 1024:.1f}MB",
|
| 51 |
-
"Source": "HuggingFace Hub",
|
| 52 |
-
}
|
| 53 |
-
for line in LogFormatter.stats(stats, "Dataset Statistics"):
|
| 54 |
-
logger.info(line)
|
| 55 |
-
|
| 56 |
-
return data
|
| 57 |
-
|
| 58 |
except Exception as hf_error:
|
| 59 |
logger.warning(LogFormatter.warning(
|
| 60 |
-
f"
|
| 61 |
))
|
| 62 |
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
else:
|
| 77 |
-
raise HTTPException(
|
| 78 |
-
status_code=500,
|
| 79 |
-
detail="No data source available: HF dataset not found and no local data."
|
| 80 |
-
)
|
| 81 |
|
| 82 |
except HTTPException:
|
| 83 |
raise
|
|
|
|
| 25 |
)
|
| 26 |
|
| 27 |
|
| 28 |
+
def _merge_results(
|
| 29 |
+
base: List[Dict[str, Any]], overlay: List[Dict[str, Any]]
|
| 30 |
+
) -> List[Dict[str, Any]]:
|
| 31 |
+
"""Merge curated/base results with new ones, deduped by (model, adapter).
|
| 32 |
+
|
| 33 |
+
``base`` is the bundled real/paper results; ``overlay`` is new community
|
| 34 |
+
results from the HF contents dataset. Overlay rows override base rows that
|
| 35 |
+
share the same (fullname, adapter) so a freshly evaluated result supersedes
|
| 36 |
+
the baseline, while every other base result is preserved.
|
| 37 |
+
"""
|
| 38 |
+
merged: Dict[tuple, Dict[str, Any]] = {}
|
| 39 |
+
for row in list(base) + list(overlay): # overlay last => wins on conflict
|
| 40 |
+
merged[(row.get("fullname"), row.get("adapter"))] = row
|
| 41 |
+
return list(merged.values())
|
| 42 |
+
|
| 43 |
+
|
| 44 |
class LeaderboardService:
|
| 45 |
def __init__(self):
|
| 46 |
pass
|
| 47 |
|
| 48 |
async def fetch_raw_data(self) -> List[Dict[str, Any]]:
|
| 49 |
+
"""Merge the bundled real/paper results with new community results.
|
| 50 |
+
|
| 51 |
+
``sample_results.json`` (the paper results) is the immutable base. New
|
| 52 |
+
results from the HF ``contents`` dataset are overlaid on top so the board
|
| 53 |
+
shows BOTH; on a (model, adapter) clash the new result wins. Falls back
|
| 54 |
+
to base-only when the contents dataset isn't available yet.
|
| 55 |
+
"""
|
| 56 |
try:
|
| 57 |
logger.info(LogFormatter.section("FETCHING LEADERBOARD DATA"))
|
| 58 |
|
| 59 |
+
# Base: bundled real/paper results (always present).
|
| 60 |
+
base: List[Dict[str, Any]] = []
|
| 61 |
+
if SAMPLE_DATA_PATH.exists():
|
| 62 |
+
with open(SAMPLE_DATA_PATH, "r") as f:
|
| 63 |
+
base = json.load(f)
|
| 64 |
+
|
| 65 |
+
# Overlay: new community results from the HF contents dataset.
|
| 66 |
+
overlay: List[Dict[str, Any]] = []
|
| 67 |
try:
|
|
|
|
| 68 |
dataset = datasets.load_dataset(
|
| 69 |
f"{HF_ORGANIZATION}/contents",
|
| 70 |
+
cache_dir=cache_config.get_cache_path("datasets"),
|
| 71 |
+
download_mode="force_redownload",
|
| 72 |
)["train"]
|
| 73 |
+
overlay = dataset.to_pandas().to_dict("records")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
except Exception as hf_error:
|
| 75 |
logger.warning(LogFormatter.warning(
|
| 76 |
+
f"No HF contents dataset yet ({hf_error}); showing bundled results only."
|
| 77 |
))
|
| 78 |
|
| 79 |
+
data = _merge_results(base, overlay)
|
| 80 |
+
if not data:
|
| 81 |
+
raise HTTPException(
|
| 82 |
+
status_code=500,
|
| 83 |
+
detail="No leaderboard data available: no bundled or HF results.",
|
| 84 |
+
)
|
| 85 |
+
|
| 86 |
+
for line in LogFormatter.stats(
|
| 87 |
+
{"Base": len(base), "New": len(overlay), "Merged": len(data)},
|
| 88 |
+
"Leaderboard Merge",
|
| 89 |
+
):
|
| 90 |
+
logger.info(line)
|
| 91 |
+
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
except HTTPException:
|
| 94 |
raise
|
backend/app/services/results_mapping.py
CHANGED
|
@@ -8,6 +8,10 @@ from app.config.submission_config import DATASET_ID_TO_ACCURACY_FIELD
|
|
| 8 |
|
| 9 |
AVERAGE_FIELD = "Average ⬆️" # "Average ⬆️"
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
def _submitted_date(request: Dict[str, Any]) -> str:
|
| 13 |
ts = str(request.get("submitted_time", ""))
|
|
@@ -56,7 +60,7 @@ def map_oeb_results_to_contents(df, request: Dict[str, Any]) -> List[Dict[str, A
|
|
| 56 |
|
| 57 |
row: Dict[str, Any] = {
|
| 58 |
"fullname": request.get("model_name", ""),
|
| 59 |
-
"adapter": str(strategy),
|
| 60 |
"Precision": "",
|
| 61 |
"Model sha": None,
|
| 62 |
"Architecture": backbone or arch_fallback,
|
|
|
|
| 8 |
|
| 9 |
AVERAGE_FIELD = "Average ⬆️" # "Average ⬆️"
|
| 10 |
|
| 11 |
+
# Map oeb finetuning kinds to the arena's adapter vocabulary used by the existing
|
| 12 |
+
# (paper) results and the frontend filters — frozen linear probing == "probe".
|
| 13 |
+
_ADAPTER_ALIAS = {"frozen": "probe"}
|
| 14 |
+
|
| 15 |
|
| 16 |
def _submitted_date(request: Dict[str, Any]) -> str:
|
| 17 |
ts = str(request.get("submitted_time", ""))
|
|
|
|
| 60 |
|
| 61 |
row: Dict[str, Any] = {
|
| 62 |
"fullname": request.get("model_name", ""),
|
| 63 |
+
"adapter": _ADAPTER_ALIAS.get(str(strategy), str(strategy)),
|
| 64 |
"Precision": "",
|
| 65 |
"Model sha": None,
|
| 66 |
"Architecture": backbone or arch_fallback,
|
backend/tests/test_leaderboard_merge.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from app.services.leaderboard import _merge_results
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def test_merge_overlay_wins_on_conflict():
|
| 5 |
+
base = [
|
| 6 |
+
{"fullname": "BIOT", "adapter": "full_finetune", "Average ⬆️": 30.0},
|
| 7 |
+
{"fullname": "LaBraM", "adapter": "probe", "Average ⬆️": 12.0},
|
| 8 |
+
]
|
| 9 |
+
overlay = [
|
| 10 |
+
{"fullname": "BIOT", "adapter": "full_finetune", "Average ⬆️": 40.0}, # overrides base
|
| 11 |
+
{"fullname": "MyModel", "adapter": "lora", "Average ⬆️": 50.0}, # brand new
|
| 12 |
+
]
|
| 13 |
+
out = _merge_results(base, overlay)
|
| 14 |
+
by = {(r["fullname"], r["adapter"]): r for r in out}
|
| 15 |
+
assert len(out) == 3
|
| 16 |
+
assert by[("BIOT", "full_finetune")]["Average ⬆️"] == 40.0 # new result wins
|
| 17 |
+
assert by[("LaBraM", "probe")]["Average ⬆️"] == 12.0 # paper result preserved
|
| 18 |
+
assert ("MyModel", "lora") in by # new model added
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def test_merge_empty_overlay_returns_base():
|
| 22 |
+
base = [{"fullname": "BIOT", "adapter": "probe"}]
|
| 23 |
+
assert len(_merge_results(base, [])) == 1
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def test_merge_empty_base_returns_overlay():
|
| 27 |
+
assert len(_merge_results([], [{"fullname": "X", "adapter": "frozen"}])) == 1
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def test_merge_distinct_adapters_both_kept():
|
| 31 |
+
# paper "probe" and a new "frozen" for the same model are different keys -> both shown
|
| 32 |
+
base = [{"fullname": "BIOT", "adapter": "probe"}]
|
| 33 |
+
overlay = [{"fullname": "BIOT", "adapter": "frozen"}]
|
| 34 |
+
assert len(_merge_results(base, overlay)) == 2
|
backend/tests/test_results_mapping.py
CHANGED
|
@@ -30,7 +30,7 @@ def test_one_row_per_strategy():
|
|
| 30 |
assert len(rows) == 1
|
| 31 |
row = rows[0]
|
| 32 |
assert row["fullname"] == "BIOT-frozen"
|
| 33 |
-
assert row["adapter"] == "frozen"
|
| 34 |
assert row["Architecture"] == "BIOT"
|
| 35 |
# mean over seeds: bcic2a = (0.40+0.60)/2 = 0.50 (fraction)
|
| 36 |
assert abs(row["bcic2a_accuracy"] - 0.50) < 1e-9
|
|
@@ -52,7 +52,7 @@ def test_multiple_strategies_multiple_rows():
|
|
| 52 |
df = _df()
|
| 53 |
extra = df.copy(); extra["finetuning"] = "lora"
|
| 54 |
rows = map_oeb_results_to_contents(pd.concat([df, extra], ignore_index=True), _request())
|
| 55 |
-
assert {r["adapter"] for r in rows} == {"
|
| 56 |
|
| 57 |
def test_all_failed_run_has_no_metric_column():
|
| 58 |
# When every experiment fails, oeb's DataFrame has NO test_balanced_accuracy
|
|
|
|
| 30 |
assert len(rows) == 1
|
| 31 |
row = rows[0]
|
| 32 |
assert row["fullname"] == "BIOT-frozen"
|
| 33 |
+
assert row["adapter"] == "probe" # oeb "frozen" linear probing -> arena "probe"
|
| 34 |
assert row["Architecture"] == "BIOT"
|
| 35 |
# mean over seeds: bcic2a = (0.40+0.60)/2 = 0.50 (fraction)
|
| 36 |
assert abs(row["bcic2a_accuracy"] - 0.50) < 1e-9
|
|
|
|
| 52 |
df = _df()
|
| 53 |
extra = df.copy(); extra["finetuning"] = "lora"
|
| 54 |
rows = map_oeb_results_to_contents(pd.concat([df, extra], ignore_index=True), _request())
|
| 55 |
+
assert {r["adapter"] for r in rows} == {"probe", "lora"} # frozen aliased to probe; lora unchanged
|
| 56 |
|
| 57 |
def test_all_failed_run_has_no_metric_column():
|
| 58 |
# When every experiment fails, oeb's DataFrame has NO test_balanced_accuracy
|