Spaces:
Runtime error
Runtime error
File size: 7,085 Bytes
7b8017a 0008b52 7b8017a 029ef9b 7b8017a d0e51e3 71f8501 7b8017a 0008b52 7b8017a 0008b52 7b8017a 2eaa7de 7b8017a 0008b52 7b8017a b0b6a82 7b8017a 0008b52 7b8017a 0008b52 7b8017a 029ef9b 7b8017a 029ef9b 7b8017a 71f8501 7b8017a 0008b52 7b8017a 71f8501 7b8017a |
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 |
import gradio as gr
import bittensor as bt
import typing
from bittensor.extrinsics.serving import get_metadata
from dataclasses import dataclass
import requests
import wandb
import math
import os
import statistics
import time
from dotenv import load_dotenv
from huggingface_hub import HfApi
from apscheduler.schedulers.background import BackgroundScheduler
load_dotenv()
FONT = """<link href="https://fonts.cdnfonts.com/css/jmh-typewriter" rel="stylesheet">"""
TITLE = """<h1 align="center" id="space-title" class="typewriter">Subnet 6 Leaderboard</h1>"""
IMAGE = """<a href="https://discord.gg/jqVphNsB4H" target="_blank"><img src="https://i.ibb.co/88wyVQ7/nousgirl.png" alt="nousgirl" style="margin: auto; width: 20%; border: 0;" /></a>"""
HEADER = """<h2 align="center" class="typewriter"><a href="https://github.com/NousResearch/finetuning-subnet" target="_blank">Subnet 6</a> is a <a href="https://bittensor.com/" target="_blank">Bittensor</a> subnet that incentivizes the creation of the best open models by evaluating submissions on a constant stream of newly generated synthetic GPT-4 data. The models with the best head-to-head loss on the evaluation data receive a steady emission of TAO.</h3>"""
DETAILS = """<b>Name</b> is the 🤗 Hugging Face model name (click to go to the model card). <b>Rewards / Day</b> are the expected rewards per day for each model. <b>Last Average Loss</b> is the last loss value on the evaluation data for the model as calculated by a validator (lower is better). <b>UID</b> is the Bittensor user id of the submitter. <b>Block</b> is the Bittensor block that the model was submitted in. More stats on <a href="https://taostats.io/subnets/netuid-6/" target="_blank">taostats</a>."""
VALIDATOR_WANDB_PROJECT = os.environ["VALIDATOR_WANDB_PROJECT"]
H4_TOKEN = os.environ.get("H4_TOKEN", None)
API = HfApi(token=H4_TOKEN)
REPO_ID = "NousResearch/finetuning_subnet_leaderboard"
MAX_AVG_LOSS_POINTS = 5
METAGRAPH_RETRIES = 5
METAGRAPH_DELAY_SECS = 3
def get_subtensor_and_metagraph() -> typing.Tuple[bt.subtensor, bt.metagraph]:
subtensor: bt.subtensor = bt.subtensor("finney")
for i in range(0, METAGRAPH_RETRIES):
try:
metagraph: bt.metagraph = subtensor.metagraph(6, lite=False)
return subtensor, metagraph
except:
if i == METAGRAPH_RETRIES - 1:
raise
time.sleep(METAGRAPH_DELAY_SECS)
raise RuntimeError()
@dataclass
class ModelData:
uid: int
hotkey: str
namespace: str
name: str
commit: str
hash: str
block: int
incentive: float
emission: float
@classmethod
def from_compressed_str(cls, uid: int, hotkey: str, cs: str, block: int, incentive: float, emission: float):
"""Returns an instance of this class from a compressed string representation"""
tokens = cs.split(":")
return ModelData(
uid=uid,
hotkey=hotkey,
namespace=tokens[0],
name=tokens[1],
commit=tokens[2] if tokens[2] != "None" else None,
hash=tokens[3] if tokens[3] != "None" else None,
block=block,
incentive=incentive,
emission=emission
)
def get_tao_price() -> float:
for i in range(0, METAGRAPH_RETRIES):
try:
return float(requests.get("https://api.kucoin.com/api/v1/market/stats?symbol=TAO-USDT").json()["data"]["last"])
except:
if i == METAGRAPH_RETRIES - 1:
raise
time.sleep(METAGRAPH_DELAY_SECS)
raise RuntimeError()
def print_validator_weights(metagraph: bt.metagraph):
for uid in metagraph.uids.tolist():
if metagraph.validator_trust[uid].item() > 0:
print(f"uid: {uid}")
for ouid in metagraph.uids.tolist():
if ouid == uid:
continue
weight = round(metagraph.weights[uid][ouid].item(), 4)
if weight > 0:
print(f" {ouid} = {weight}")
def get_subnet_data(subtensor: bt.subtensor, metagraph: bt.metagraph) -> typing.List[ModelData]:
result = []
for uid in metagraph.uids.tolist():
hotkey = metagraph.hotkeys[uid]
metadata = get_metadata(subtensor, metagraph.netuid, hotkey)
if not metadata:
continue
commitment = metadata["info"]["fields"][0]
hex_data = commitment[list(commitment.keys())[0]][2:]
chain_str = bytes.fromhex(hex_data).decode()
block = metadata["block"]
incentive = metagraph.incentive[uid].nan_to_num().item()
emission = metagraph.emission[uid].nan_to_num().item() * 20 # convert to daily TAO
model_data = None
try:
model_data = ModelData.from_compressed_str(uid, hotkey, chain_str, block, incentive, emission)
except:
continue
result.append(model_data)
return result
def get_avg_loss(uids: typing.List[int]) -> typing.Dict[int, float]:
api = wandb.Api()
runs = list(api.runs(VALIDATOR_WANDB_PROJECT))
runs.reverse()
result = {}
for run in runs:
history = run.history()
for uid in uids:
if uid in result.keys():
continue
key = f"uid_data.{uid}"
if key in history:
data = [float(x) for x in list(history[key]) if (isinstance(x, float) and not math.isnan(x)) or isinstance(x, int) ][-MAX_AVG_LOSS_POINTS:]
if len(data) > 0:
result[uid] = statistics.fmean(data)
if len(result.keys()) == len(uids):
break
return result
subtensor, metagraph = get_subtensor_and_metagraph()
tao_price = get_tao_price()
leaderboard_df = get_subnet_data(subtensor, metagraph)
leaderboard_df.sort(key=lambda x: x.incentive, reverse=True)
losses = get_avg_loss([x.uid for x in leaderboard_df])
demo = gr.Blocks(css=".typewriter {font-family: 'JMH Typewriter', sans-serif;}")
with demo:
gr.HTML(FONT)
gr.HTML(TITLE)
gr.HTML(IMAGE)
gr.HTML(HEADER)
gr.HTML(DETAILS)
value = [
[
f'[{c.namespace}/{c.name}](https://huggingface.co/{c.namespace}/{c.name})',
f'${round(c.emission * tao_price, 2):,} (τ{round(c.emission, 2):,})',
f'{round(losses[c.uid], 4) if c.uid in losses.keys() else ""}',
c.uid,
c.block
] for c in leaderboard_df
]
value = [x for x in value if x[2] != ""] # filter out anything without a loss
leaderboard_table = gr.components.Dataframe(
value=value,
headers=["Name", "Rewards / Day", "Last Average Loss", "UID", "Block"],
datatype=["markdown", "str", "number", "number", "number"],
elem_id="leaderboard-table",
interactive=False,
visible=True,
)
def restart_space():
API.restart_space(repo_id=REPO_ID, token=H4_TOKEN)
scheduler = BackgroundScheduler()
scheduler.add_job(restart_space, "interval", seconds=60 * 15) # restart every 15 minutes
scheduler.start()
demo.launch() |