steffenc commited on
Commit
0ffd9af
·
1 Parent(s): 550408e

Cleanup functions and add subtensor-based block-time converter

Browse files
Files changed (1) hide show
  1. meta2frame.py +27 -92
meta2frame.py CHANGED
@@ -9,31 +9,8 @@ import bittensor as bt
9
  import pandas as pd
10
  import plotly.express as px
11
 
12
- def trust(W, S, threshold=0):
13
- """Trust vector for subnets with variable threshold"""
14
 
15
- # assert (S.sum()-1).abs()<1e-4, f'Stake must sum to 1, got {S.sum()}'
16
- Wn = (W > 0).float()
17
- return Wn.T @ S
18
- # return ( (W > threshold)*S.reshape(-1,1) ).sum(axis=0)
19
-
20
- def rank(W, S):
21
- """Rank vector for subnets"""
22
- # assert (S.sum()-1).abs()<1e-4, f'Stake must sum to 1, got {S.sum()}'
23
-
24
- R = W.T @ S
25
- return R / R.sum()
26
-
27
- def emission(C, R):
28
- """Emission vector for subnets"""
29
-
30
- E = C*R
31
- return E / E.sum()
32
-
33
- def YC1(T, a=0.5, b=10):
34
- """Yuma Consensus 1"""
35
-
36
- return torch.sigmoid( b * (T - a) )
37
 
38
 
39
  def load_metagraphs(root_dir, netuid, block_min=0, block_max=3_000_000):
@@ -42,10 +19,11 @@ def load_metagraphs(root_dir, netuid, block_min=0, block_max=3_000_000):
42
  match_path = os.path.join(root_dir, str(netuid), '*.pkl')
43
  files = glob.glob(match_path)
44
  print(f'Found {len(files)} metagraphs in {match_path}')
45
- for path in tqdm.tqdm(files):
46
- block = int(path.split('/')[-1].split('.')[0])
47
- if not block_min <= block <= block_max:
48
- continue
 
49
  with open(path, 'rb') as f:
50
  metagraph = pickle.load(f)
51
  metagraphs.append(metagraph)
@@ -53,75 +31,30 @@ def load_metagraphs(root_dir, netuid, block_min=0, block_max=3_000_000):
53
  return sorted(metagraphs, key=lambda x: x.block)
54
 
55
 
56
- # TODO: can calculate the emission trend using each subnet or just using root subnet
57
- def plot_emission_trend(metagraphs, netuid, max_uids=32):
58
 
59
- df = pd.DataFrame()
60
- max_uids = max_uids or max(m.W.shape[1] for m in metagraphs)
 
61
 
62
- for metagraph in metagraphs:
63
- E = m.W.mean(axis=0)
64
- df = pd.concat([df, pd.DataFrame({'emission':E}).assign(block=metagraph.block)])
65
 
66
- df.sort_values(by='block', inplace=True)
67
 
68
- fig = px.line(df, x=df.index, y='emission',line_group='',
69
- title='Emission Trend',
70
 
71
- width=800, height=600, template='plotly_white')
72
- fig.update_xaxes(title_text='Block Height')
73
- fig.update_yaxes(title_text='Emission')
74
- fig.show()
75
 
76
- return fig
 
 
 
77
 
78
- def block_to_time(blocks):
79
- if not isinstance(blocks, pd.Series):
80
- blocks = pd.Series(blocks)
81
-
82
- block_time_500k = datetime.datetime(2023, 5, 29, 5, 29, 0)
83
- block_time_800k = datetime.datetime(2023, 7, 9, 21, 32, 48)
84
- dt = (pd.Timestamp(block_time_800k)-pd.Timestamp(block_time_500k))/(800_000-500_000)
85
- return block_time_500k + dt*(blocks-500_000)
86
-
87
- root_dir = os.path.expanduser('~/Desktop/py/opentensor/metagraph/subnets/')
88
-
89
- metagraphs = load_metagraphs(root_dir, 0)
90
- metagraphs
91
-
92
- def make_dataframe_old(metagraphs, netuid):
93
- df = pd.DataFrame()
94
- # max_uids=max(m.W.shape[1] for m in metagraphs)
95
- for metagraph in sorted(metagraphs, key=lambda m: m.block):
96
- if metagraph.n.item() == 0:
97
- print(f'Block {metagraph.block} has no nodes, skipping')
98
- continue
99
-
100
- if netuid == 0:
101
- W = metagraph.W.float()
102
- Sn = (metagraph.S/metagraph.S.sum()).clone().float()
103
-
104
- T = trust(W, Sn)
105
- R = rank(W, Sn)
106
- C = YC1(T)
107
- E = emission(C, R)
108
- else:
109
- T = metagraph.T
110
- R = metagraph.R
111
- C = metagraph.C
112
- E = metagraph.E
113
-
114
- frame = pd.DataFrame({'Trust':T, 'Rank':R, 'Consensus':C, 'Emission':E, 'uid':range(len(E))}).assign(block=metagraph.block.item(), netuid=netuid)
115
- df = pd.concat([df, frame])
116
-
117
- df['alive'] = df.groupby('netuid')['Emission'].transform(lambda x: x > 0)
118
- df['owner_take'] = df['Emission'] * 7200 * 0.18
119
- df['timestamp'] = block_to_time(df['block'])
120
- df['day'] = df['timestamp'].dt.dayofyear
121
- df.sort_values(by=['block','netuid'], inplace=True)
122
- return df
123
 
124
- def make_dataframe(root_dir, netuid, cols=None, block_min=0, block_max=3_000_000, weights=False):
 
125
  if cols is None:
126
  cols = ['stake','emission','trust','validator_trust','dividends','incentive','R', 'consensus','validator_permit']
127
  frames = []
@@ -130,7 +63,6 @@ def make_dataframe(root_dir, netuid, cols=None, block_min=0, block_max=3_000_000
130
  for m in metagraphs:
131
  frame = pd.DataFrame({k: getattr(m, k) for k in cols})
132
  frame['block'] = m.block.item()
133
- frame['timestamp'] = block_to_time(frame['block'])
134
  frame['netuid'] = netuid
135
  frame['uid'] = range(len(frame))
136
  frame['hotkey'] = [axon.hotkey for axon in m.axons]
@@ -138,6 +70,9 @@ def make_dataframe(root_dir, netuid, cols=None, block_min=0, block_max=3_000_000
138
  if weights and m.W is not None:
139
  # convert NxN tensor to a list of lists so it fits into the dataframe
140
  frame['weights'] = [w.tolist() for w in m.W]
141
-
142
  frames.append(frame)
143
- return pd.concat(frames).sort_values(by=['timestamp','block','uid'])
 
 
 
 
9
  import pandas as pd
10
  import plotly.express as px
11
 
 
 
12
 
13
+ ROOT_DIR = './data/metagraph/'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
 
16
  def load_metagraphs(root_dir, netuid, block_min=0, block_max=3_000_000):
 
19
  match_path = os.path.join(root_dir, str(netuid), '*.pkl')
20
  files = glob.glob(match_path)
21
  print(f'Found {len(files)} metagraphs in {match_path}')
22
+
23
+ valid_files = [path for path in files if block_min <= int(path.split('/')[-1].split('.')[0]) <= block_max]
24
+ print(f'Found {len(valid_files)} valid metagraphs between {block_min} and {block_max}')
25
+ for path in tqdm.tqdm(valid_files):
26
+
27
  with open(path, 'rb') as f:
28
  metagraph = pickle.load(f)
29
  metagraphs.append(metagraph)
 
31
  return sorted(metagraphs, key=lambda x: x.block)
32
 
33
 
34
+ def get_block_timestamp(block, subtensor):
 
35
 
36
+ info = subtensor.substrate.get_block(block_number=int(block))
37
+ extrinsic_call = info['extrinsics'][0]['call']
38
+ return extrinsic_call.value_serialized['call_args'][0]['value']
39
 
 
 
 
40
 
41
+ def block_to_time(blocks, subtensor=None):
42
 
43
+ if not isinstance(blocks, pd.Series):
44
+ blocks = pd.Series(blocks)
45
 
46
+ if subtensor is None:
47
+ subtensor = bt.subtensor(network='archive')
 
 
48
 
49
+ timestamps = {}
50
+ unique_blocks = set(blocks)
51
+ for block in tqdm.tqdm(unique_blocks):
52
+ timestamps[block] = get_block_timestamp(block, subtensor)
53
 
54
+ return blocks.map(timestamps).apply(pd.to_datetime, unit='ms')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
+
57
+ def make_dataframe(netuid, root_dir=ROOT_DIR, cols=None, block_min=0, block_max=3_000_000, weights=False):
58
  if cols is None:
59
  cols = ['stake','emission','trust','validator_trust','dividends','incentive','R', 'consensus','validator_permit']
60
  frames = []
 
63
  for m in metagraphs:
64
  frame = pd.DataFrame({k: getattr(m, k) for k in cols})
65
  frame['block'] = m.block.item()
 
66
  frame['netuid'] = netuid
67
  frame['uid'] = range(len(frame))
68
  frame['hotkey'] = [axon.hotkey for axon in m.axons]
 
70
  if weights and m.W is not None:
71
  # convert NxN tensor to a list of lists so it fits into the dataframe
72
  frame['weights'] = [w.tolist() for w in m.W]
73
+
74
  frames.append(frame)
75
+
76
+ df = pd.concat(frames)
77
+ df['timestamp'] = block_to_time(df['block'])
78
+ return df.sort_values(by=['timestamp','block','uid'])