Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
cassova
commited on
Commit
·
80820db
1
Parent(s):
338a112
black + fixed timezone on dates
Browse files
utils.py
CHANGED
@@ -14,67 +14,72 @@ import plotly.express as px
|
|
14 |
# TODO: Store relevant wandb data in a database for faster access
|
15 |
|
16 |
|
17 |
-
MIN_STEPS = 10
|
18 |
NETUID = 1
|
19 |
-
BASE_PATH =
|
20 |
-
NETWORK =
|
21 |
-
KEYS = [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
ABBREV_CHARS = 8
|
23 |
-
ENTITY_CHOICES = (
|
24 |
-
LOCAL_WANDB_PATH =
|
25 |
-
USERNAME =
|
26 |
|
27 |
# Initialize wandb with anonymous login
|
28 |
-
wandb.login(anonymous=
|
29 |
api = wandb.Api(timeout=600)
|
30 |
|
31 |
IDENTITIES = {
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
}
|
45 |
|
46 |
EXTRACTORS = {
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
# 'netuid': lambda x: x.config.get('netuid'),
|
56 |
# 'mock': lambda x: x.config.get('neuron').get('mock'),
|
57 |
# 'sample_size': lambda x: x.config.get('neuron').get('sample_size'),
|
58 |
# 'timeout': lambda x: x.config.get('neuron').get('timeout'),
|
59 |
# 'epoch_length': lambda x: x.config.get('neuron').get('epoch_length'),
|
60 |
# 'disable_set_weights': lambda x: x.config.get('neuron').get('disable_set_weights'),
|
61 |
-
|
62 |
# This stuff is from the last logged event
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
'vali_hotkey': lambda x: x.tags[2],
|
73 |
# 'tasks_selected': lambda x: x.tags[3:],
|
74 |
-
|
75 |
# System metrics
|
76 |
-
|
77 |
-
|
78 |
# Really slow stuff below
|
79 |
# 'started_at': lambda x: x.metadata.get('startedAt'),
|
80 |
# 'disk_used': lambda x: x.metadata.get('disk').get('/').get('used'),
|
@@ -82,50 +87,64 @@ EXTRACTORS = {
|
|
82 |
}
|
83 |
|
84 |
|
85 |
-
def get_leaderboard(df, ntop=10, entity_choice=
|
86 |
|
87 |
-
df = df.loc[df.validator_permit==False]
|
88 |
df.index = range(df.shape[0])
|
89 |
return df.groupby(entity_choice).I.sum().sort_values().reset_index().tail(ntop)
|
90 |
|
|
|
91 |
@st.cache_data()
|
92 |
def get_metagraph(time):
|
93 |
-
print(f
|
94 |
subtensor = bt.subtensor(network=NETWORK)
|
95 |
m = subtensor.metagraph(netuid=NETUID)
|
96 |
-
meta_cols = [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
|
98 |
df_m = pd.DataFrame({k: getattr(m, k) for k in meta_cols})
|
99 |
-
df_m[
|
100 |
-
df_m[
|
101 |
-
df_m[
|
102 |
-
df_m[
|
103 |
-
df_m[
|
104 |
-
df_m[
|
105 |
-
df_m[
|
106 |
-
df_m[
|
107 |
return df_m
|
108 |
|
109 |
|
110 |
@st.cache_data(show_spinner=False)
|
111 |
def load_downloaded_runs(time, cols=KEYS):
|
112 |
|
113 |
-
list_cols = [
|
114 |
-
extra_cols = [
|
115 |
df_all = pd.DataFrame()
|
116 |
|
117 |
-
progress = st.progress(0, text=
|
118 |
-
paths = glob.glob(os.path.join(LOCAL_WANDB_PATH,
|
119 |
for i, path in enumerate(paths):
|
120 |
-
run_id = path.split(
|
121 |
frame = pd.read_parquet(path).dropna(subset=cols)
|
122 |
-
frame._timestamp = frame._timestamp.apply(pd.to_datetime, unit=
|
123 |
# handle missing extra cols such as turn which depend on the version of the codebase
|
124 |
found_extra_cols = [c for c in frame.columns if c in extra_cols]
|
125 |
-
df_long = frame[cols+list_cols+found_extra_cols].explode(list_cols)
|
126 |
|
127 |
-
prog_msg = f
|
128 |
-
progress.progress(
|
|
|
|
|
129 |
|
130 |
df_all = pd.concat([df_all, df_long.assign(run_id=run_id)], ignore_index=True)
|
131 |
|
@@ -133,17 +152,16 @@ def load_downloaded_runs(time, cols=KEYS):
|
|
133 |
|
134 |
# Ensure we have consistent naming schema for tasks
|
135 |
task_mapping = {
|
136 |
-
|
137 |
-
|
138 |
}
|
139 |
-
|
140 |
-
df_all['task'] = df_all.task.apply(lambda x: task_mapping.get(x, x))
|
141 |
|
|
|
142 |
|
143 |
# Runs which do not have a turn field are imputed to be turn zero (single turn)
|
144 |
-
df_all[
|
145 |
|
146 |
-
df_all.sort_values(by=[
|
147 |
|
148 |
return df_all
|
149 |
|
@@ -151,88 +169,129 @@ def load_downloaded_runs(time, cols=KEYS):
|
|
151 |
@st.cache_data(show_spinner=False)
|
152 |
def build_data(timestamp=None, path=BASE_PATH, min_steps=MIN_STEPS, use_cache=True):
|
153 |
|
154 |
-
save_path =
|
155 |
filters = {}
|
156 |
df = pd.DataFrame()
|
157 |
# Load the last saved runs so that we only need to update the new ones
|
158 |
if use_cache and os.path.exists(save_path):
|
159 |
df = pd.read_csv(save_path)
|
160 |
-
df[
|
161 |
-
df[
|
162 |
|
163 |
-
timestamp_str = df[
|
164 |
-
filters.update({
|
165 |
|
166 |
-
progress = st.progress(0, text=
|
167 |
|
168 |
runs = api.runs(path, filters=filters)
|
169 |
|
170 |
run_data = []
|
171 |
n_events = 0
|
172 |
for i, run in enumerate(tqdm.tqdm(runs, total=len(runs))):
|
173 |
-
num_steps = run.summary.get(
|
174 |
-
if num_steps<min_steps:
|
175 |
continue
|
176 |
n_events += num_steps
|
177 |
-
prog_msg =
|
178 |
-
|
179 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
180 |
run_data.append(run)
|
181 |
|
182 |
-
|
183 |
progress.empty()
|
184 |
|
185 |
-
df_new = pd.DataFrame(
|
|
|
|
|
|
|
|
|
|
|
186 |
df = pd.concat([df, df_new], ignore_index=True)
|
187 |
-
|
188 |
-
|
189 |
-
df
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
|
191 |
# Drop events that are not related to validator queries
|
192 |
-
df.dropna(subset=
|
193 |
|
194 |
print(df.completions.apply(type).value_counts())
|
195 |
# Assumes completions is in the frame
|
196 |
-
df[
|
197 |
-
|
198 |
-
|
199 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
200 |
|
201 |
df.to_csv(save_path, index=False)
|
202 |
|
203 |
return df
|
204 |
|
|
|
205 |
@st.cache_data()
|
206 |
def normalize_rewards(df, turn=0, percentile=0.98):
|
207 |
-
top_reward_stats =
|
208 |
-
|
209 |
-
|
210 |
-
|
|
|
|
|
|
|
|
|
|
|
211 |
return df
|
212 |
|
|
|
213 |
@st.cache_data(show_spinner=False)
|
214 |
def download_runs(time, df_vali):
|
215 |
|
216 |
pbar = tqdm.tqdm(df_vali.index, total=len(df_vali))
|
217 |
|
218 |
-
progress = st.progress(0, text=
|
219 |
|
220 |
for i, idx in enumerate(pbar):
|
221 |
row = df_vali.loc[idx]
|
222 |
|
223 |
-
prog_msg = f
|
224 |
-
progress.progress(
|
|
|
|
|
|
|
225 |
|
226 |
-
save_path = f
|
227 |
# Create the directory if it does not exist
|
228 |
os.makedirs(os.path.dirname(save_path), exist_ok=True)
|
229 |
|
230 |
if os.path.exists(save_path):
|
231 |
-
pbar.set_description(
|
|
|
|
|
232 |
continue
|
233 |
|
234 |
try:
|
235 |
-
pbar.set_description(f
|
236 |
run = api.run(row.run_path)
|
237 |
|
238 |
# By default we just download a subset of events (500 most recent)
|
@@ -241,7 +300,9 @@ def download_runs(time, df_vali):
|
|
241 |
except KeyboardInterrupt:
|
242 |
break
|
243 |
except Exception as e:
|
244 |
-
pbar.set_description(
|
|
|
|
|
245 |
|
246 |
progress.empty()
|
247 |
|
@@ -250,24 +311,41 @@ def get_productivity(df_runs):
|
|
250 |
|
251 |
total_duration = df_runs.last_event_at.max() - df_runs.created_at.min()
|
252 |
total_steps = df_runs.num_steps.sum()
|
253 |
-
total_completions = (df_runs.num_steps*100).sum()
|
254 |
-
total_completion_words = (df_runs.num_steps*df_runs.completion_words).sum()
|
255 |
-
total_completion_tokens = round(total_completion_words/0.75)
|
256 |
-
total_validator_words = (
|
257 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
258 |
total_dataset_tokens = total_completion_tokens + total_validator_tokens
|
259 |
|
260 |
return {
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
}
|
268 |
|
|
|
269 |
@st.cache_data(show_spinner=False)
|
270 |
-
def get_reward_stats(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
271 |
|
272 |
df = df.loc[df._timestamp.between(pd.Timestamp(date_min), pd.Timestamp(date_max))]
|
273 |
if exclude_multiturn:
|
@@ -275,145 +353,311 @@ def get_reward_stats(df, exclude_multiturn=True, freq='D', remove_zero_rewards=T
|
|
275 |
if remove_zero_rewards:
|
276 |
df = df.loc[df.rewards > 0]
|
277 |
|
278 |
-
groups = [
|
279 |
-
return df.groupby(groups).agg({
|
|
|
280 |
|
281 |
def get_release_dates():
|
282 |
-
release_dates = pd.DataFrame(
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
306 |
return release_dates
|
307 |
|
308 |
|
309 |
-
def plot_reward_trends(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
310 |
|
311 |
stats = df_stats.reset_index()
|
312 |
release_dates = get_release_dates()
|
313 |
-
stats_task = stats.loc[(stats.task == task)].sort_values(by=
|
314 |
-
stats_task[
|
315 |
-
fig = px.area(
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
|
|
|
|
|
|
321 |
|
322 |
if not annotate:
|
323 |
return fig
|
324 |
|
325 |
# Add annotations based on relevant releases
|
326 |
for idx, row in release_dates.iterrows():
|
327 |
-
line_color =
|
328 |
-
if task in row[
|
329 |
-
line_color=
|
330 |
-
elif
|
331 |
-
line_color=
|
332 |
# TODO add annotation or something
|
333 |
-
fig.add_vline(
|
|
|
|
|
|
|
|
|
|
|
|
|
334 |
|
335 |
return fig
|
336 |
|
|
|
337 |
@st.cache_data()
|
338 |
def get_task_counts(df_runs, df_events):
|
339 |
-
# Get mapping from run id to prompting repo version
|
340 |
-
run_to_version = df_runs.set_index(
|
|
|
|
|
341 |
|
342 |
-
df_events['version'] = df_events.run_id.map(run_to_version)
|
343 |
-
|
344 |
def version_to_spec(version):
|
345 |
-
major, minor, patch = version.split(
|
346 |
return 10_000 * major + 100 * minor + patch
|
347 |
-
|
348 |
def get_closest_prev_version(version, my_versions):
|
349 |
-
|
350 |
ref_spec = version_to_spec(version)
|
351 |
my_specs = list(map(version_to_spec, my_versions))
|
352 |
-
|
353 |
match = my_specs[0]
|
354 |
for spec in my_specs[1:]:
|
355 |
-
if spec>ref_spec:
|
356 |
break
|
357 |
-
|
358 |
match = spec
|
359 |
-
|
360 |
return my_versions[my_specs.index(match)]
|
361 |
-
|
362 |
# Now estimate the distribution of tasks for each version using the event data
|
363 |
-
task_rate =
|
|
|
|
|
|
|
|
|
|
|
364 |
# Impute missing versions
|
365 |
for v in sorted(df_runs.version.unique()):
|
366 |
if v not in task_rate.index:
|
367 |
prev_version = get_closest_prev_version(v, list(task_rate.index))
|
368 |
-
print(
|
|
|
|
|
369 |
task_rate.loc[v] = task_rate.loc[prev_version]
|
370 |
-
|
371 |
# get esimated number of each task generated in every run using summary dataframe
|
372 |
-
task_counts =
|
373 |
-
|
|
|
|
|
|
|
|
|
|
|
374 |
|
375 |
|
376 |
def load_state_vars(username=USERNAME, percentile=0.95):
|
377 |
|
378 |
UPDATE_INTERVAL = 600
|
379 |
|
380 |
-
df_runs = build_data(time.time()//UPDATE_INTERVAL, use_cache=False)
|
381 |
-
|
382 |
# df_runs = df_runs.loc[df_runs.netuid.isin([1,61,102])] # Now we filter for the netuid tag in build_data
|
383 |
-
st.toast(f
|
384 |
|
385 |
df_vali = df_runs.loc[df_runs.username == username]
|
386 |
# df_vali = df_runs
|
387 |
|
388 |
-
download_runs(time.time()//UPDATE_INTERVAL, df_vali)
|
389 |
|
390 |
-
df_events = load_downloaded_runs(time.time()//UPDATE_INTERVAL)
|
391 |
df_events = normalize_rewards(df_events, percentile=percentile)
|
392 |
|
393 |
-
yesterday = pd.Timestamp.now() - pd.Timedelta(
|
394 |
-
runs_alive_24h_ago =
|
395 |
|
396 |
df_runs_24h = df_runs.loc[runs_alive_24h_ago]
|
397 |
-
|
398 |
# weight factor indicates the fraction of events that happened within the last 24 hour.
|
399 |
-
fraction = 1 - (yesterday - df_runs_24h.created_at) / (
|
400 |
-
|
401 |
-
|
402 |
-
|
|
|
|
|
403 |
df_task_counts = get_task_counts(df_runs, df_events)
|
404 |
|
405 |
-
df_m = get_metagraph(time.time()//UPDATE_INTERVAL)
|
406 |
|
407 |
return {
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
}
|
415 |
|
416 |
|
417 |
-
if __name__ ==
|
418 |
|
419 |
-
pass
|
|
|
14 |
# TODO: Store relevant wandb data in a database for faster access
|
15 |
|
16 |
|
17 |
+
MIN_STEPS = 10 # minimum number of steps in wandb run in order to be worth analyzing
|
18 |
NETUID = 1
|
19 |
+
BASE_PATH = "macrocosmos/prompting-validators"
|
20 |
+
NETWORK = "finney"
|
21 |
+
KEYS = [
|
22 |
+
"_step",
|
23 |
+
"_timestamp",
|
24 |
+
"task",
|
25 |
+
"query",
|
26 |
+
"reference",
|
27 |
+
"challenge",
|
28 |
+
"topic",
|
29 |
+
"subtopic",
|
30 |
+
]
|
31 |
ABBREV_CHARS = 8
|
32 |
+
ENTITY_CHOICES = ("identity", "hotkey", "coldkey")
|
33 |
+
LOCAL_WANDB_PATH = "./data/wandb"
|
34 |
+
USERNAME = "taostats"
|
35 |
|
36 |
# Initialize wandb with anonymous login
|
37 |
+
wandb.login(anonymous="must")
|
38 |
api = wandb.Api(timeout=600)
|
39 |
|
40 |
IDENTITIES = {
|
41 |
+
"5F4tQyWrhfGVcNhoqeiNsR6KjD4wMZ2kfhLj4oHYuyHbZAc3": "opentensor",
|
42 |
+
"5Hddm3iBFD2GLT5ik7LZnT3XJUnRnN8PoeCFgGQgawUVKNm8": "taostats",
|
43 |
+
"5HEo565WAy4Dbq3Sv271SAi7syBSofyfhhwRNjFNSM2gP9M2": "foundry",
|
44 |
+
"5HK5tp6t2S59DywmHRWPBVJeJ86T61KjurYqeooqj8sREpeN": "bittensor-guru",
|
45 |
+
"5FFApaS75bv5pJHfAp2FVLBj9ZaXuFDjEypsaBNc1wCfe52v": "roundtable-21",
|
46 |
+
"5EhvL1FVkQPpMjZX4MAADcW42i3xPSF1KiCpuaxTYVr28sux": "tao-validator",
|
47 |
+
"5FKstHjZkh4v3qAMSBa1oJcHCLjxYZ8SNTSz1opTv4hR7gVB": "datura",
|
48 |
+
"5DvTpiniW9s3APmHRYn8FroUWyfnLtrsid5Mtn5EwMXHN2ed": "first-tensor",
|
49 |
+
"5HbLYXUBy1snPR8nfioQ7GoA9x76EELzEq9j7F32vWUQHm1x": "tensorplex",
|
50 |
+
"5CsvRJXuR955WojnGMdok1hbhffZyB4N5ocrv82f3p5A2zVp": "owl-ventures",
|
51 |
+
"5CXRfP2ekFhe62r7q3vppRajJmGhTi7vwvb2yr79jveZ282w": "rizzo",
|
52 |
+
"5HNQURvmjjYhTSksi8Wfsw676b4owGwfLR2BFAQzG7H3HhYf": "neural-internet",
|
53 |
}
|
54 |
|
55 |
EXTRACTORS = {
|
56 |
+
"state": lambda x: x.state,
|
57 |
+
"run_id": lambda x: x.id,
|
58 |
+
"run_path": lambda x: os.path.join(BASE_PATH, x.id),
|
59 |
+
"user": lambda x: x.user.name[:16],
|
60 |
+
"username": lambda x: x.user.username[:16],
|
61 |
+
"created_at": lambda x: pd.Timestamp(x.created_at),
|
62 |
+
"last_event_at": lambda x: pd.Timestamp(x.summary.get("_timestamp"), unit="s"),
|
|
|
63 |
# 'netuid': lambda x: x.config.get('netuid'),
|
64 |
# 'mock': lambda x: x.config.get('neuron').get('mock'),
|
65 |
# 'sample_size': lambda x: x.config.get('neuron').get('sample_size'),
|
66 |
# 'timeout': lambda x: x.config.get('neuron').get('timeout'),
|
67 |
# 'epoch_length': lambda x: x.config.get('neuron').get('epoch_length'),
|
68 |
# 'disable_set_weights': lambda x: x.config.get('neuron').get('disable_set_weights'),
|
|
|
69 |
# This stuff is from the last logged event
|
70 |
+
"num_steps": lambda x: x.summary.get("_step"),
|
71 |
+
"runtime": lambda x: x.summary.get("_runtime"),
|
72 |
+
"query": lambda x: x.summary.get("query"),
|
73 |
+
"challenge": lambda x: x.summary.get("challenge"),
|
74 |
+
"reference": lambda x: x.summary.get("reference"),
|
75 |
+
"completions": lambda x: x.summary.get("completions"),
|
76 |
+
"version": lambda x: x.tags[0],
|
77 |
+
"spec_version": lambda x: x.tags[1],
|
78 |
+
"vali_hotkey": lambda x: x.tags[2],
|
|
|
79 |
# 'tasks_selected': lambda x: x.tags[3:],
|
|
|
80 |
# System metrics
|
81 |
+
"disk_read": lambda x: x.system_metrics.get("system.disk.in"),
|
82 |
+
"disk_write": lambda x: x.system_metrics.get("system.disk.out"),
|
83 |
# Really slow stuff below
|
84 |
# 'started_at': lambda x: x.metadata.get('startedAt'),
|
85 |
# 'disk_used': lambda x: x.metadata.get('disk').get('/').get('used'),
|
|
|
87 |
}
|
88 |
|
89 |
|
90 |
+
def get_leaderboard(df, ntop=10, entity_choice="identity"):
|
91 |
|
92 |
+
df = df.loc[df.validator_permit == False]
|
93 |
df.index = range(df.shape[0])
|
94 |
return df.groupby(entity_choice).I.sum().sort_values().reset_index().tail(ntop)
|
95 |
|
96 |
+
|
97 |
@st.cache_data()
|
98 |
def get_metagraph(time):
|
99 |
+
print(f"Loading metagraph with time {time}")
|
100 |
subtensor = bt.subtensor(network=NETWORK)
|
101 |
m = subtensor.metagraph(netuid=NETUID)
|
102 |
+
meta_cols = [
|
103 |
+
"I",
|
104 |
+
"stake",
|
105 |
+
"trust",
|
106 |
+
"validator_trust",
|
107 |
+
"validator_permit",
|
108 |
+
"C",
|
109 |
+
"R",
|
110 |
+
"E",
|
111 |
+
"dividends",
|
112 |
+
"last_update",
|
113 |
+
]
|
114 |
|
115 |
df_m = pd.DataFrame({k: getattr(m, k) for k in meta_cols})
|
116 |
+
df_m["uid"] = range(m.n.item())
|
117 |
+
df_m["hotkey"] = list(map(lambda a: a.hotkey, m.axons))
|
118 |
+
df_m["coldkey"] = list(map(lambda a: a.coldkey, m.axons))
|
119 |
+
df_m["ip"] = list(map(lambda a: a.ip, m.axons))
|
120 |
+
df_m["port"] = list(map(lambda a: a.port, m.axons))
|
121 |
+
df_m["coldkey"] = df_m.coldkey.str[:ABBREV_CHARS]
|
122 |
+
df_m["hotkey"] = df_m.hotkey.str[:ABBREV_CHARS]
|
123 |
+
df_m["identity"] = df_m.apply(lambda x: f"{x.hotkey} @ uid {x.uid}", axis=1)
|
124 |
return df_m
|
125 |
|
126 |
|
127 |
@st.cache_data(show_spinner=False)
|
128 |
def load_downloaded_runs(time, cols=KEYS):
|
129 |
|
130 |
+
list_cols = ["rewards", "uids"]
|
131 |
+
extra_cols = ["turn"]
|
132 |
df_all = pd.DataFrame()
|
133 |
|
134 |
+
progress = st.progress(0, text="Loading downloaded data")
|
135 |
+
paths = glob.glob(os.path.join(LOCAL_WANDB_PATH, "*.parquet"))
|
136 |
for i, path in enumerate(paths):
|
137 |
+
run_id = path.split("/")[-1].split(".")[0]
|
138 |
frame = pd.read_parquet(path).dropna(subset=cols)
|
139 |
+
frame._timestamp = frame._timestamp.apply(pd.to_datetime, unit="s")
|
140 |
# handle missing extra cols such as turn which depend on the version of the codebase
|
141 |
found_extra_cols = [c for c in frame.columns if c in extra_cols]
|
142 |
+
df_long = frame[cols + list_cols + found_extra_cols].explode(list_cols)
|
143 |
|
144 |
+
prog_msg = f"Downloading data {i/len(paths)*100:.0f}%"
|
145 |
+
progress.progress(
|
146 |
+
i / len(paths), text=f"{prog_msg}... **downloading** `{run_id}`"
|
147 |
+
)
|
148 |
|
149 |
df_all = pd.concat([df_all, df_long.assign(run_id=run_id)], ignore_index=True)
|
150 |
|
|
|
152 |
|
153 |
# Ensure we have consistent naming schema for tasks
|
154 |
task_mapping = {
|
155 |
+
"date-based question answering": "date_qa",
|
156 |
+
"question-answering": "qa",
|
157 |
}
|
|
|
|
|
158 |
|
159 |
+
df_all["task"] = df_all.task.apply(lambda x: task_mapping.get(x, x))
|
160 |
|
161 |
# Runs which do not have a turn field are imputed to be turn zero (single turn)
|
162 |
+
df_all["turn"] = df_all.turn.fillna(0)
|
163 |
|
164 |
+
df_all.sort_values(by=["_timestamp"], inplace=True)
|
165 |
|
166 |
return df_all
|
167 |
|
|
|
169 |
@st.cache_data(show_spinner=False)
|
170 |
def build_data(timestamp=None, path=BASE_PATH, min_steps=MIN_STEPS, use_cache=True):
|
171 |
|
172 |
+
save_path = "_saved_runs.csv"
|
173 |
filters = {}
|
174 |
df = pd.DataFrame()
|
175 |
# Load the last saved runs so that we only need to update the new ones
|
176 |
if use_cache and os.path.exists(save_path):
|
177 |
df = pd.read_csv(save_path)
|
178 |
+
df["created_at"] = pd.to_datetime(df["created_at"])
|
179 |
+
df["last_event_at"] = pd.to_datetime(df["last_event_at"])
|
180 |
|
181 |
+
timestamp_str = df["last_event_at"].max().isoformat()
|
182 |
+
filters.update({"updated_at": {"$gte": timestamp_str}})
|
183 |
|
184 |
+
progress = st.progress(0, text="Loading data")
|
185 |
|
186 |
runs = api.runs(path, filters=filters)
|
187 |
|
188 |
run_data = []
|
189 |
n_events = 0
|
190 |
for i, run in enumerate(tqdm.tqdm(runs, total=len(runs))):
|
191 |
+
num_steps = run.summary.get("_step", 0)
|
192 |
+
if num_steps < min_steps:
|
193 |
continue
|
194 |
n_events += num_steps
|
195 |
+
prog_msg = (
|
196 |
+
f"Loading data {i/len(runs)*100:.0f}%, (total {n_events:,.0f} events)"
|
197 |
+
)
|
198 |
+
progress.progress(
|
199 |
+
i / len(runs),
|
200 |
+
text=f"{prog_msg}... **downloading** `{os.path.join(*run.path)}`",
|
201 |
+
)
|
202 |
+
if (
|
203 |
+
"netuid_1" in run.tags
|
204 |
+
or "netuid_61" in run.tags
|
205 |
+
or "netuid_102" in run.tags
|
206 |
+
):
|
207 |
run_data.append(run)
|
208 |
|
|
|
209 |
progress.empty()
|
210 |
|
211 |
+
df_new = pd.DataFrame(
|
212 |
+
[
|
213 |
+
{k: func(run) for k, func in EXTRACTORS.items()}
|
214 |
+
for run in tqdm.tqdm(run_data, total=len(run_data))
|
215 |
+
]
|
216 |
+
)
|
217 |
df = pd.concat([df, df_new], ignore_index=True)
|
218 |
+
|
219 |
+
# Ensure that the timestamps are timezone aware
|
220 |
+
if df.last_event_at.dt.tz is None:
|
221 |
+
df.last_event_at = df.last_event_at.dt.tz_localize("UTC")
|
222 |
+
if df.created_at.dt.tz is None:
|
223 |
+
df.created_at = df.created_at.dt.tz_localize("UTC")
|
224 |
+
|
225 |
+
df["duration"] = (df.last_event_at - df.created_at).round("s")
|
226 |
+
df["identity"] = df["vali_hotkey"].map(IDENTITIES).fillna("unknown")
|
227 |
+
df["vali_hotkey"] = df["vali_hotkey"].str[:ABBREV_CHARS]
|
228 |
|
229 |
# Drop events that are not related to validator queries
|
230 |
+
df.dropna(subset="query", inplace=True)
|
231 |
|
232 |
print(df.completions.apply(type).value_counts())
|
233 |
# Assumes completions is in the frame
|
234 |
+
df["completions"] = df["completions"].apply(
|
235 |
+
lambda x: x if isinstance(x, list) else eval(x)
|
236 |
+
)
|
237 |
+
|
238 |
+
df["completion_words"] = df.completions.apply(
|
239 |
+
lambda x: sum([len(xx.split()) for xx in x]) if isinstance(x, list) else 0
|
240 |
+
)
|
241 |
+
df["validator_words"] = df.apply(
|
242 |
+
lambda x: len(str(x.query).split())
|
243 |
+
+ len(str(x.challenge).split())
|
244 |
+
+ len(str(x.reference).split()),
|
245 |
+
axis=1,
|
246 |
+
)
|
247 |
|
248 |
df.to_csv(save_path, index=False)
|
249 |
|
250 |
return df
|
251 |
|
252 |
+
|
253 |
@st.cache_data()
|
254 |
def normalize_rewards(df, turn=0, percentile=0.98):
|
255 |
+
top_reward_stats = (
|
256 |
+
df.loc[df.turn == turn]
|
257 |
+
.astype({"rewards": float})
|
258 |
+
.groupby("task")
|
259 |
+
.rewards.quantile(percentile)
|
260 |
+
)
|
261 |
+
|
262 |
+
df["best_reward"] = df.task.map(top_reward_stats)
|
263 |
+
df["normalized_rewards"] = df["rewards"].astype(float) / df["best_reward"]
|
264 |
return df
|
265 |
|
266 |
+
|
267 |
@st.cache_data(show_spinner=False)
|
268 |
def download_runs(time, df_vali):
|
269 |
|
270 |
pbar = tqdm.tqdm(df_vali.index, total=len(df_vali))
|
271 |
|
272 |
+
progress = st.progress(0, text="Loading data")
|
273 |
|
274 |
for i, idx in enumerate(pbar):
|
275 |
row = df_vali.loc[idx]
|
276 |
|
277 |
+
prog_msg = f"Downloading data {i/len(df_vali)*100:.0f}%"
|
278 |
+
progress.progress(
|
279 |
+
i / len(df_vali),
|
280 |
+
text=f"{prog_msg}... **downloading** `{os.path.join(*row.run_id)}`",
|
281 |
+
)
|
282 |
|
283 |
+
save_path = f"data/wandb/{row.run_id}.parquet"
|
284 |
# Create the directory if it does not exist
|
285 |
os.makedirs(os.path.dirname(save_path), exist_ok=True)
|
286 |
|
287 |
if os.path.exists(save_path):
|
288 |
+
pbar.set_description(
|
289 |
+
f">> Skipping {row.run_id!r} because file {save_path!r} already exists"
|
290 |
+
)
|
291 |
continue
|
292 |
|
293 |
try:
|
294 |
+
pbar.set_description(f"* Downloading run {row.run_id!r}")
|
295 |
run = api.run(row.run_path)
|
296 |
|
297 |
# By default we just download a subset of events (500 most recent)
|
|
|
300 |
except KeyboardInterrupt:
|
301 |
break
|
302 |
except Exception as e:
|
303 |
+
pbar.set_description(
|
304 |
+
f"- Something went wrong with {row.run_id!r}: {print_exc()}\n"
|
305 |
+
)
|
306 |
|
307 |
progress.empty()
|
308 |
|
|
|
311 |
|
312 |
total_duration = df_runs.last_event_at.max() - df_runs.created_at.min()
|
313 |
total_steps = df_runs.num_steps.sum()
|
314 |
+
total_completions = (df_runs.num_steps * 100).sum() # TODO: Parse from df
|
315 |
+
total_completion_words = (df_runs.num_steps * df_runs.completion_words).sum()
|
316 |
+
total_completion_tokens = round(total_completion_words / 0.75)
|
317 |
+
total_validator_words = (
|
318 |
+
df_runs.num_steps
|
319 |
+
* df_runs.apply(
|
320 |
+
lambda x: len(str(x.query).split())
|
321 |
+
+ len(str(x.challenge).split())
|
322 |
+
+ len(str(x.reference).split()),
|
323 |
+
axis=1,
|
324 |
+
)
|
325 |
+
).sum()
|
326 |
+
total_validator_tokens = round(total_validator_words / 0.75)
|
327 |
total_dataset_tokens = total_completion_tokens + total_validator_tokens
|
328 |
|
329 |
return {
|
330 |
+
"duration": total_duration,
|
331 |
+
"total_events": total_steps,
|
332 |
+
"total_completions": total_completions,
|
333 |
+
"total_completion_tokens": total_completion_tokens,
|
334 |
+
"total_validator_tokens": total_validator_tokens,
|
335 |
+
"total_tokens": total_dataset_tokens,
|
336 |
}
|
337 |
|
338 |
+
|
339 |
@st.cache_data(show_spinner=False)
|
340 |
+
def get_reward_stats(
|
341 |
+
df,
|
342 |
+
exclude_multiturn=True,
|
343 |
+
freq="D",
|
344 |
+
remove_zero_rewards=True,
|
345 |
+
agg="mean",
|
346 |
+
date_min="2024-01-22",
|
347 |
+
date_max="2024-08-12",
|
348 |
+
): # TODO: Set the date_max to the current date
|
349 |
|
350 |
df = df.loc[df._timestamp.between(pd.Timestamp(date_min), pd.Timestamp(date_max))]
|
351 |
if exclude_multiturn:
|
|
|
353 |
if remove_zero_rewards:
|
354 |
df = df.loc[df.rewards > 0]
|
355 |
|
356 |
+
groups = ["run_id", pd.Grouper(key="_timestamp", freq=freq), "task"]
|
357 |
+
return df.groupby(groups).agg({"rewards": agg, "normalized_rewards": agg})
|
358 |
+
|
359 |
|
360 |
def get_release_dates():
|
361 |
+
release_dates = pd.DataFrame(
|
362 |
+
[
|
363 |
+
{
|
364 |
+
"version": "1.0.0",
|
365 |
+
"release_date": pd.Timestamp(month=1, day=22, year=2024),
|
366 |
+
"note": "",
|
367 |
+
"model": "zephyr",
|
368 |
+
"tasks_affected": ["qa", "summarization"],
|
369 |
+
},
|
370 |
+
{
|
371 |
+
"version": "1.0.1",
|
372 |
+
"release_date": pd.Timestamp(month=1, day=22, year=2024),
|
373 |
+
"note": "",
|
374 |
+
"model": "zephyr",
|
375 |
+
"tasks_affected": [],
|
376 |
+
},
|
377 |
+
{
|
378 |
+
"version": "1.0.2",
|
379 |
+
"release_date": pd.Timestamp(month=1, day=24, year=2024),
|
380 |
+
"note": "",
|
381 |
+
"model": "zephyr",
|
382 |
+
"tasks_affected": ["qa", "summarization"],
|
383 |
+
},
|
384 |
+
{
|
385 |
+
"version": "1.0.3",
|
386 |
+
"release_date": pd.Timestamp(month=2, day=14, year=2024),
|
387 |
+
"note": "",
|
388 |
+
"model": "zephyr",
|
389 |
+
"tasks_affected": [],
|
390 |
+
},
|
391 |
+
{
|
392 |
+
"version": "1.0.4",
|
393 |
+
"release_date": pd.Timestamp(month=2, day=15, year=2024),
|
394 |
+
"note": "",
|
395 |
+
"model": "zephyr",
|
396 |
+
"tasks_affected": [],
|
397 |
+
},
|
398 |
+
{
|
399 |
+
"version": "1.1.0",
|
400 |
+
"release_date": pd.Timestamp(month=2, day=21, year=2024),
|
401 |
+
"note": "decay scores",
|
402 |
+
"model": "zephyr",
|
403 |
+
"tasks_affected": ["date_qa", "math"],
|
404 |
+
},
|
405 |
+
{
|
406 |
+
"version": "1.1.1",
|
407 |
+
"release_date": pd.Timestamp(month=2, day=28, year=2024),
|
408 |
+
"note": "reduce penalty weight",
|
409 |
+
"model": "zephyr",
|
410 |
+
"tasks_affected": ["date_qa", "qa", "summarization"],
|
411 |
+
},
|
412 |
+
{
|
413 |
+
"version": "1.1.2",
|
414 |
+
"release_date": pd.Timestamp(month=2, day=29, year=2024),
|
415 |
+
"note": "",
|
416 |
+
"model": "zephyr",
|
417 |
+
"tasks_affected": [],
|
418 |
+
},
|
419 |
+
{
|
420 |
+
"version": "1.1.3",
|
421 |
+
"release_date": pd.Timestamp(month=3, day=11, year=2024),
|
422 |
+
"note": "",
|
423 |
+
"model": "zephyr",
|
424 |
+
"tasks_affected": [],
|
425 |
+
},
|
426 |
+
{
|
427 |
+
"version": "1.2.0",
|
428 |
+
"release_date": pd.Timestamp(month=3, day=19, year=2024),
|
429 |
+
"note": "vllm",
|
430 |
+
"model": "zephyr",
|
431 |
+
"tasks_affected": [],
|
432 |
+
},
|
433 |
+
{
|
434 |
+
"version": "1.3.0",
|
435 |
+
"release_date": pd.Timestamp(month=3, day=27, year=2024),
|
436 |
+
"note": "",
|
437 |
+
"model": "solar",
|
438 |
+
"tasks_affected": ["all", "math"],
|
439 |
+
},
|
440 |
+
{
|
441 |
+
"version": "2.0.0",
|
442 |
+
"release_date": pd.Timestamp(month=4, day=4, year=2024),
|
443 |
+
"note": "streaming",
|
444 |
+
"model": "solar",
|
445 |
+
"tasks_affected": ["math", "qa", "summarization"],
|
446 |
+
},
|
447 |
+
{
|
448 |
+
"version": "2.1.0",
|
449 |
+
"release_date": pd.Timestamp(month=4, day=18, year=2024),
|
450 |
+
"note": "chattensor prompt",
|
451 |
+
"model": "solar",
|
452 |
+
"tasks_affected": ["generic"],
|
453 |
+
},
|
454 |
+
{
|
455 |
+
"version": "2.2.0",
|
456 |
+
"release_date": pd.Timestamp(month=5, day=1, year=2024),
|
457 |
+
"note": "multiturn + paraphrase",
|
458 |
+
"model": "solar",
|
459 |
+
"tasks_affected": ["sentiment", "translation", "math"],
|
460 |
+
},
|
461 |
+
{
|
462 |
+
"version": "2.3.0",
|
463 |
+
"release_date": pd.Timestamp(month=5, day=20, year=2024),
|
464 |
+
"note": "llama + freeform date",
|
465 |
+
"model": "llama",
|
466 |
+
"tasks_affected": ["all", "date_qa"],
|
467 |
+
},
|
468 |
+
{
|
469 |
+
"version": "2.3.1",
|
470 |
+
"release_date": pd.Timestamp(month=5, day=21, year=2024),
|
471 |
+
"note": "",
|
472 |
+
"model": "llama",
|
473 |
+
"tasks_affected": ["date_qa"],
|
474 |
+
},
|
475 |
+
{
|
476 |
+
"version": "2.4.0",
|
477 |
+
"release_date": pd.Timestamp(month=6, day=5, year=2024),
|
478 |
+
"note": "streaming penalty",
|
479 |
+
"model": "llama",
|
480 |
+
"tasks_affected": [],
|
481 |
+
},
|
482 |
+
{
|
483 |
+
"version": "2.4.1",
|
484 |
+
"release_date": pd.Timestamp(month=6, day=6, year=2024),
|
485 |
+
"note": "",
|
486 |
+
"model": "llama",
|
487 |
+
"tasks_affected": [],
|
488 |
+
},
|
489 |
+
{
|
490 |
+
"version": "2.4.2",
|
491 |
+
"release_date": pd.Timestamp(month=6, day=7, year=2024),
|
492 |
+
"note": "",
|
493 |
+
"model": "llama",
|
494 |
+
"tasks_affected": [],
|
495 |
+
},
|
496 |
+
{
|
497 |
+
"version": "2.4.2",
|
498 |
+
"release_date": pd.Timestamp(month=6, day=7, year=2024),
|
499 |
+
"note": "",
|
500 |
+
"model": "llama",
|
501 |
+
"tasks_affected": [],
|
502 |
+
},
|
503 |
+
{
|
504 |
+
"version": "2.5.0",
|
505 |
+
"release_date": pd.Timestamp(month=6, day=18, year=2024),
|
506 |
+
"note": "reduce multiturn",
|
507 |
+
"model": "llama",
|
508 |
+
"tasks_affected": ["translation", "sentiment"],
|
509 |
+
},
|
510 |
+
{
|
511 |
+
"version": "2.5.1",
|
512 |
+
"release_date": pd.Timestamp(month=6, day=25, year=2024),
|
513 |
+
"note": "reduce timeout",
|
514 |
+
"model": "llama",
|
515 |
+
"tasks_affected": [],
|
516 |
+
},
|
517 |
+
]
|
518 |
+
)
|
519 |
return release_dates
|
520 |
|
521 |
|
522 |
+
def plot_reward_trends(
|
523 |
+
df_stats,
|
524 |
+
task="qa",
|
525 |
+
window=14,
|
526 |
+
col="normalized_reward",
|
527 |
+
annotate=False,
|
528 |
+
task_label="Question answering",
|
529 |
+
):
|
530 |
|
531 |
stats = df_stats.reset_index()
|
532 |
release_dates = get_release_dates()
|
533 |
+
stats_task = stats.loc[(stats.task == task)].sort_values(by="_timestamp")
|
534 |
+
stats_task["rewards_ma"] = stats_task[col].rolling(window, min_periods=0).mean()
|
535 |
+
fig = px.area(
|
536 |
+
stats_task,
|
537 |
+
x="_timestamp",
|
538 |
+
y="rewards_ma",
|
539 |
+
title=f"Reward Trend for {task_label} Task",
|
540 |
+
labels={"rewards_ma": f"Rewards [{window} day avg.]", "_timestamp": ""},
|
541 |
+
width=800,
|
542 |
+
height=600,
|
543 |
+
)
|
544 |
|
545 |
if not annotate:
|
546 |
return fig
|
547 |
|
548 |
# Add annotations based on relevant releases
|
549 |
for idx, row in release_dates.iterrows():
|
550 |
+
line_color = "grey"
|
551 |
+
if task in row["tasks_affected"]:
|
552 |
+
line_color = "red"
|
553 |
+
elif "all" not in row["tasks_affected"]:
|
554 |
+
line_color = "blue"
|
555 |
# TODO add annotation or something
|
556 |
+
fig.add_vline(
|
557 |
+
row["release_date"],
|
558 |
+
line_color=line_color,
|
559 |
+
opacity=0.6,
|
560 |
+
line_dash="dot",
|
561 |
+
line_width=1,
|
562 |
+
) # , annotation_text=str(v))
|
563 |
|
564 |
return fig
|
565 |
|
566 |
+
|
567 |
@st.cache_data()
|
568 |
def get_task_counts(df_runs, df_events):
|
569 |
+
# Get mapping from run id to prompting repo version
|
570 |
+
run_to_version = df_runs.set_index("run_id").version.to_dict()
|
571 |
+
|
572 |
+
df_events["version"] = df_events.run_id.map(run_to_version)
|
573 |
|
|
|
|
|
574 |
def version_to_spec(version):
|
575 |
+
major, minor, patch = version.split(".")
|
576 |
return 10_000 * major + 100 * minor + patch
|
577 |
+
|
578 |
def get_closest_prev_version(version, my_versions):
|
579 |
+
|
580 |
ref_spec = version_to_spec(version)
|
581 |
my_specs = list(map(version_to_spec, my_versions))
|
582 |
+
|
583 |
match = my_specs[0]
|
584 |
for spec in my_specs[1:]:
|
585 |
+
if spec > ref_spec:
|
586 |
break
|
587 |
+
|
588 |
match = spec
|
589 |
+
|
590 |
return my_versions[my_specs.index(match)]
|
591 |
+
|
592 |
# Now estimate the distribution of tasks for each version using the event data
|
593 |
+
task_rate = (
|
594 |
+
df_events.groupby("version")
|
595 |
+
.task.value_counts(normalize=True)
|
596 |
+
.unstack()
|
597 |
+
.fillna(0)
|
598 |
+
)
|
599 |
# Impute missing versions
|
600 |
for v in sorted(df_runs.version.unique()):
|
601 |
if v not in task_rate.index:
|
602 |
prev_version = get_closest_prev_version(v, list(task_rate.index))
|
603 |
+
print(
|
604 |
+
f"Imputing version {v} with task rate from closes previous version {prev_version!r}"
|
605 |
+
)
|
606 |
task_rate.loc[v] = task_rate.loc[prev_version]
|
607 |
+
|
608 |
# get esimated number of each task generated in every run using summary dataframe
|
609 |
+
task_counts = (
|
610 |
+
df_runs.set_index("created_at")
|
611 |
+
.sort_index()
|
612 |
+
.apply(lambda x: round(task_rate.loc[x.version] * x.num_steps), axis=1)
|
613 |
+
.cumsum()
|
614 |
+
)
|
615 |
+
return task_counts
|
616 |
|
617 |
|
618 |
def load_state_vars(username=USERNAME, percentile=0.95):
|
619 |
|
620 |
UPDATE_INTERVAL = 600
|
621 |
|
622 |
+
df_runs = build_data(time.time() // UPDATE_INTERVAL, use_cache=False)
|
623 |
+
|
624 |
# df_runs = df_runs.loc[df_runs.netuid.isin([1,61,102])] # Now we filter for the netuid tag in build_data
|
625 |
+
st.toast(f"Loaded {len(df_runs)} runs")
|
626 |
|
627 |
df_vali = df_runs.loc[df_runs.username == username]
|
628 |
# df_vali = df_runs
|
629 |
|
630 |
+
download_runs(time.time() // UPDATE_INTERVAL, df_vali)
|
631 |
|
632 |
+
df_events = load_downloaded_runs(time.time() // UPDATE_INTERVAL)
|
633 |
df_events = normalize_rewards(df_events, percentile=percentile)
|
634 |
|
635 |
+
yesterday = pd.Timestamp.now(tz="UTC") - pd.Timedelta("1d")
|
636 |
+
runs_alive_24h_ago = df_runs.last_event_at > yesterday
|
637 |
|
638 |
df_runs_24h = df_runs.loc[runs_alive_24h_ago]
|
639 |
+
|
640 |
# weight factor indicates the fraction of events that happened within the last 24 hour.
|
641 |
+
fraction = 1 - (yesterday - df_runs_24h.created_at) / (
|
642 |
+
pd.Timestamp.now(tz="UTC") - df_runs_24h.created_at
|
643 |
+
)
|
644 |
+
df_runs_24h["fraction"] = fraction.clip(0, 1)
|
645 |
+
df_runs_24h["num_steps"] *= fraction.clip(0, 1)
|
646 |
+
|
647 |
df_task_counts = get_task_counts(df_runs, df_events)
|
648 |
|
649 |
+
df_m = get_metagraph(time.time() // UPDATE_INTERVAL)
|
650 |
|
651 |
return {
|
652 |
+
"df_runs": df_runs,
|
653 |
+
"df_runs_24h": df_runs_24h,
|
654 |
+
"df_vali": df_vali,
|
655 |
+
"df_events": df_events,
|
656 |
+
"metagraph": df_m,
|
657 |
+
"df_task_counts": df_task_counts,
|
658 |
}
|
659 |
|
660 |
|
661 |
+
if __name__ == "__main__":
|
662 |
|
663 |
+
pass
|