forked from MakazhanAlpamys/Soup
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathleaderboard.py
More file actions
158 lines (128 loc) · 4.56 KB
/
Copy pathleaderboard.py
File metadata and controls
158 lines (128 loc) · 4.56 KB
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
"""Leaderboard — aggregate eval results from experiments.db."""
from __future__ import annotations
import json
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class LeaderboardEntry:
"""A single entry in the leaderboard."""
model_path: str
benchmark: str
score: float
run_id: Optional[str] = None
created_at: str = ""
@dataclass
class Leaderboard:
"""Aggregated leaderboard across all evaluated models."""
entries: list[LeaderboardEntry] = field(default_factory=list)
models: dict[str, dict[str, float]] = field(default_factory=dict)
def compute(self) -> None:
"""Aggregate entries by model, computing per-benchmark scores."""
self.models = {}
for entry in self.entries:
model = entry.model_path
if model not in self.models:
self.models[model] = {}
# Keep the latest score per benchmark per model
self.models[model][entry.benchmark] = entry.score
def get_sorted_models(
self, sort_by: Optional[str] = None,
) -> list[tuple[str, dict[str, float], float]]:
"""Return models sorted by average score or specific benchmark.
Returns list of (model_path, benchmark_scores, sort_score).
"""
result = []
for model, scores in self.models.items():
if sort_by and sort_by in scores:
sort_score = scores[sort_by]
else:
sort_score = (
sum(scores.values()) / len(scores) if scores else 0.0
)
result.append((model, scores, sort_score))
result.sort(key=lambda item: item[2], reverse=True)
return result
def build_leaderboard_from_tracker(
tracker: object,
run_id: Optional[str] = None,
) -> Leaderboard:
"""Build a leaderboard from experiment tracker eval results."""
eval_results = tracker.get_eval_results(run_id=run_id)
entries = []
for row in eval_results:
entries.append(LeaderboardEntry(
model_path=row.get("model_path", ""),
benchmark=row.get("benchmark", ""),
score=row.get("score", 0.0),
run_id=row.get("run_id"),
created_at=row.get("created_at", ""),
))
leaderboard = Leaderboard(entries=entries)
leaderboard.compute()
return leaderboard
def compare_runs(
tracker: object,
run_id_1: str,
run_id_2: str,
) -> dict:
"""Compare eval results between two runs.
Returns dict with per-benchmark comparison and deltas.
"""
results_1 = tracker.get_eval_results(run_id=run_id_1)
results_2 = tracker.get_eval_results(run_id=run_id_2)
scores_1: dict[str, float] = {}
for row in results_1:
scores_1[row["benchmark"]] = row["score"]
scores_2: dict[str, float] = {}
for row in results_2:
scores_2[row["benchmark"]] = row["score"]
all_benchmarks = sorted(set(scores_1.keys()) | set(scores_2.keys()))
comparisons = []
regressions = []
for bench in all_benchmarks:
score_a = scores_1.get(bench)
score_b = scores_2.get(bench)
delta = None
if score_a is not None and score_b is not None:
delta = score_b - score_a
if delta < -0.01:
regressions.append(bench)
comparisons.append({
"benchmark": bench,
"run_1_score": score_a,
"run_2_score": score_b,
"delta": delta,
})
return {
"run_1": run_id_1,
"run_2": run_id_2,
"comparisons": comparisons,
"regressions": regressions,
"has_regressions": len(regressions) > 0,
}
def export_leaderboard(
leaderboard: Leaderboard,
fmt: str = "json",
) -> str:
"""Export leaderboard to JSON or CSV string."""
sorted_models = leaderboard.get_sorted_models()
if fmt == "csv":
# Collect all benchmarks
all_benchmarks = set()
for _, scores, _ in sorted_models:
all_benchmarks.update(scores.keys())
benchmarks = sorted(all_benchmarks)
lines = ["model," + ",".join(benchmarks) + ",average"]
for model, scores, avg in sorted_models:
vals = [str(scores.get(bench, "")) for bench in benchmarks]
lines.append(f"{model},{','.join(vals)},{avg:.4f}")
return "\n".join(lines)
# Default: JSON
data = []
for model, scores, avg in sorted_models:
data.append({
"model": model,
"scores": scores,
"average": round(avg, 4),
})
return json.dumps(data, indent=2)