Implement Leaderboard Graph
#2
by
AlexNijjar
- opened
- app.py +90 -1
- requirements.txt +1 -0
app.py
CHANGED
@@ -1,8 +1,11 @@
|
|
1 |
import os
|
2 |
import time
|
3 |
from dataclasses import dataclass
|
|
|
|
|
4 |
|
5 |
import gradio as gr
|
|
|
6 |
import schedule
|
7 |
import wandb
|
8 |
from substrateinterface import Keypair
|
@@ -14,6 +17,10 @@ demo = gr.Blocks(css=".typewriter {font-family: 'JMH Typewriter', sans-serif;}")
|
|
14 |
SOURCE_VALIDATOR_UID = int(os.environ["SOURCE_VALIDATOR_UID"])
|
15 |
WANDB_RUN_PATH = os.environ["WANDB_RUN_PATH"]
|
16 |
|
|
|
|
|
|
|
|
|
17 |
|
18 |
@dataclass
|
19 |
class LeaderboardEntry:
|
@@ -25,6 +32,14 @@ class LeaderboardEntry:
|
|
25 |
rank: int
|
26 |
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
def is_valid_run(run: Run):
|
29 |
required_config_keys = ["hotkey", "uid", "contest", "signature"]
|
30 |
|
@@ -44,8 +59,80 @@ def is_valid_run(run: Run):
|
|
44 |
return False
|
45 |
|
46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
def refresh_leaderboard():
|
48 |
-
|
|
|
49 |
|
50 |
demo.clear()
|
51 |
|
@@ -92,6 +179,8 @@ def refresh_leaderboard():
|
|
92 |
for entry in sorted(entries.values(), key=lambda entry: (entry.score, entry.rank), reverse=True)
|
93 |
]
|
94 |
|
|
|
|
|
95 |
gr.components.Dataframe(
|
96 |
value=leaderboard,
|
97 |
headers=["Rank", "Uid", "Model", "Score", "Hotkey", "Previous day winner"],
|
|
|
1 |
import os
|
2 |
import time
|
3 |
from dataclasses import dataclass
|
4 |
+
from datetime import datetime
|
5 |
+
from zoneinfo import ZoneInfo
|
6 |
|
7 |
import gradio as gr
|
8 |
+
import plotly.graph_objects as go
|
9 |
import schedule
|
10 |
import wandb
|
11 |
from substrateinterface import Keypair
|
|
|
17 |
SOURCE_VALIDATOR_UID = int(os.environ["SOURCE_VALIDATOR_UID"])
|
18 |
WANDB_RUN_PATH = os.environ["WANDB_RUN_PATH"]
|
19 |
|
20 |
+
BASELINE = 0.0
|
21 |
+
GRAPH_HISTORY_DAYS = 30
|
22 |
+
MAX_GRAPH_ENTRIES = 5
|
23 |
+
|
24 |
|
25 |
@dataclass
|
26 |
class LeaderboardEntry:
|
|
|
32 |
rank: int
|
33 |
|
34 |
|
35 |
+
@dataclass
|
36 |
+
class GraphEntry:
|
37 |
+
dates: list[datetime]
|
38 |
+
scores: list[float]
|
39 |
+
models: list[str]
|
40 |
+
max_score: float
|
41 |
+
|
42 |
+
|
43 |
def is_valid_run(run: Run):
|
44 |
required_config_keys = ["hotkey", "uid", "contest", "signature"]
|
45 |
|
|
|
59 |
return False
|
60 |
|
61 |
|
62 |
+
def get_graph_entries(runs: Runs) -> dict[int, GraphEntry]:
|
63 |
+
graph_entries: dict[int, GraphEntry] = {}
|
64 |
+
|
65 |
+
for run in reversed(runs[:GRAPH_HISTORY_DAYS]):
|
66 |
+
if not is_valid_run(run):
|
67 |
+
continue
|
68 |
+
|
69 |
+
date = datetime.strptime(run.created_at, "%Y-%m-%dT%H:%M:%S")
|
70 |
+
|
71 |
+
for key, value in run.summary.items():
|
72 |
+
if key.startswith("_"):
|
73 |
+
continue
|
74 |
+
|
75 |
+
uid = int(key)
|
76 |
+
score = value["score"]
|
77 |
+
model = value["model"]
|
78 |
+
|
79 |
+
if uid not in graph_entries:
|
80 |
+
graph_entries[uid] = GraphEntry([date], [score], [model], score)
|
81 |
+
else:
|
82 |
+
if score > graph_entries[uid].max_score:
|
83 |
+
graph_entries[uid].max_score = score
|
84 |
+
|
85 |
+
data = graph_entries[uid]
|
86 |
+
data.dates.append(date)
|
87 |
+
data.scores.append(data.max_score)
|
88 |
+
data.models.append(model)
|
89 |
+
|
90 |
+
return dict(sorted(graph_entries.items(), key=lambda entry: entry[1].max_score, reverse=True)[:MAX_GRAPH_ENTRIES])
|
91 |
+
|
92 |
+
|
93 |
+
def create_graph(graph_entries: dict[int, GraphEntry]):
|
94 |
+
fig = go.Figure()
|
95 |
+
|
96 |
+
for uid, data in graph_entries.items():
|
97 |
+
fig.add_trace(go.Scatter(
|
98 |
+
x=data.dates,
|
99 |
+
y=data.scores,
|
100 |
+
customdata=data.models,
|
101 |
+
mode="lines+markers",
|
102 |
+
name=uid,
|
103 |
+
hovertemplate=(
|
104 |
+
"<b>Date:</b> %{x|%Y-%m-%d}<br>" +
|
105 |
+
"<b>Score:</b> %{y}<br>" +
|
106 |
+
"<b>Model:</b> %{customdata}<br>"
|
107 |
+
),
|
108 |
+
))
|
109 |
+
|
110 |
+
date_range = max(graph_entries.values(), key=lambda entry: len(entry.dates)).dates
|
111 |
+
|
112 |
+
fig.add_trace(go.Scatter(
|
113 |
+
x=date_range,
|
114 |
+
y=[BASELINE] * len(date_range),
|
115 |
+
line=dict(color="#ff0000", width=3),
|
116 |
+
mode="lines",
|
117 |
+
name="Baseline",
|
118 |
+
))
|
119 |
+
|
120 |
+
background_color = gr.themes.default.colors.slate.c800
|
121 |
+
|
122 |
+
fig.update_layout(
|
123 |
+
title="Score Improvements",
|
124 |
+
yaxis_title="Score",
|
125 |
+
plot_bgcolor=background_color,
|
126 |
+
paper_bgcolor=background_color,
|
127 |
+
template="plotly_dark"
|
128 |
+
)
|
129 |
+
|
130 |
+
gr.Plot(fig)
|
131 |
+
|
132 |
+
|
133 |
def refresh_leaderboard():
|
134 |
+
now = datetime.now(tz=ZoneInfo("America/New_York"))
|
135 |
+
print(f"Refreshing Leaderboard at {now.strftime('%Y-%m-%d %H:%M:%S')}")
|
136 |
|
137 |
demo.clear()
|
138 |
|
|
|
179 |
for entry in sorted(entries.values(), key=lambda entry: (entry.score, entry.rank), reverse=True)
|
180 |
]
|
181 |
|
182 |
+
create_graph(get_graph_entries(runs))
|
183 |
+
|
184 |
gr.components.Dataframe(
|
185 |
value=leaderboard,
|
186 |
headers=["Rank", "Uid", "Model", "Score", "Hotkey", "Previous day winner"],
|
requirements.txt
CHANGED
@@ -3,3 +3,4 @@ gradio
|
|
3 |
wandb
|
4 |
substrate-interface
|
5 |
schedule
|
|
|
|
3 |
wandb
|
4 |
substrate-interface
|
5 |
schedule
|
6 |
+
plotly
|