Skip to content

Commit 104c47b

Browse files
Merge pull request #168 from macrocosm-os/staging
Staging
2 parents d6b75f1 + cc3f8f2 commit 104c47b

File tree

13 files changed

+193
-69
lines changed

13 files changed

+193
-69
lines changed

demo.ipynb

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"from neurons.validator import Validator\n",
4747
"from folding.store import Job\n",
4848
"from folding.validators.protein import Protein\n",
49-
"from folding.protocol import FoldingSynapse\n",
49+
"from folding.protocol import JobSubmissionSynapse\n",
5050
"from folding.validators.reward import get_energies\n",
5151
"from folding.utils.ops import get_response_info\n",
5252
"from folding.rewards.reward_pipeline import reward_pipeline\n",
@@ -769,7 +769,7 @@
769769
"source": [
770770
"\n",
771771
"# Create a synapse to query the network\n",
772-
"synapse = FoldingSynapse(\n",
772+
"synapse = JobSubmissionSynapse(\n",
773773
" pdb_id=protein.pdb_id, md_inputs=protein.md_inputs, mdrun_args=\"\"\n",
774774
")\n",
775775
"\n",

folding/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from .protocol import FoldingSynapse
1+
from .protocol import JobSubmissionSynapse
22
from .validators.protein import Protein
33

4-
__version__ = "0.2.0"
4+
__version__ = "0.3.0"
55
version_split = __version__.split(".")
66
__spec_version__ = (
77
(10000 * int(version_split[0]))

folding/base/miner.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
import argparse
2222
import traceback
2323

24-
from typing import Tuple
2524
import bittensor as bt
2625

2726
from folding.base.neuron import BaseNeuron
27+
from folding.protocol import PingSynapse
2828
from folding.utils.config import add_miner_args
2929

3030

@@ -60,6 +60,8 @@ def __init__(self, config=None):
6060
forward_fn=self.forward,
6161
blacklist_fn=self.blacklist,
6262
priority_fn=self.priority,
63+
).attach(
64+
forward_fn=self.ping_forward, # not sure if we need blacklist on this.
6365
)
6466
bt.logging.info(f"Axon created: {self.axon}")
6567

@@ -69,6 +71,23 @@ def __init__(self, config=None):
6971
self.thread: threading.Thread = None
7072
self.lock = asyncio.Lock()
7173

74+
def ping_forward(self, synapse: PingSynapse):
75+
"""Respond to the validator with the necessary information about serving
76+
77+
Args:
78+
self (PingSynapse): must attach "can_serve" and "available_compute"
79+
"""
80+
81+
bt.logging.info(f"Received ping request from {synapse.dendrite.hotkey[:8]}")
82+
83+
synapse.available_compute = self.max_workers - len(self.simulations)
84+
85+
# TODO: add more conditions.
86+
if synapse.available_compute > 0:
87+
synapse.can_serve = True
88+
bt.logging.success("Telling validator you can serve ✅")
89+
return synapse
90+
7291
def run(self):
7392
"""
7493
Initiates and manages the main loop for the miner on the Bittensor network. The main loop handles graceful shutdown on keyboard interrupts and logs unforeseen errors.

folding/miners/folding_miner.py

+15-15
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
# import base miner class which takes care of most of the boilerplate
1111
from folding.base.miner import BaseMinerNeuron
12-
from folding.protocol import FoldingSynapse
12+
from folding.protocol import JobSubmissionSynapse
1313
from folding.utils.logging import log_event
1414
from folding.utils.ops import (
1515
run_cmd_commands,
@@ -23,7 +23,9 @@
2323
BASE_DATA_PATH = os.path.join(ROOT_DIR, "miner-data")
2424

2525

26-
def attach_files(files_to_attach: List, synapse: FoldingSynapse) -> FoldingSynapse:
26+
def attach_files(
27+
files_to_attach: List, synapse: JobSubmissionSynapse
28+
) -> JobSubmissionSynapse:
2729
"""function that parses a list of files and attaches them to the synapse object"""
2830
bt.logging.info(f"Sending files to validator: {files_to_attach}")
2931
for filename in files_to_attach:
@@ -45,14 +47,14 @@ def attach_files(files_to_attach: List, synapse: FoldingSynapse) -> FoldingSynap
4547

4648

4749
def attach_files_to_synapse(
48-
synapse: FoldingSynapse,
50+
synapse: JobSubmissionSynapse,
4951
data_directory: str,
5052
state: str,
51-
) -> FoldingSynapse:
53+
) -> JobSubmissionSynapse:
5254
"""load the output files as bytes and add to synapse.md_output
5355
5456
Args:
55-
synapse (FoldingSynapse): Recently received synapse object
57+
synapse (JobSubmissionSynapse): Recently received synapse object
5658
data_directory (str): directory where the miner is holding the necessary data for the validator.
5759
state (str): the current state of the simulation
5860
@@ -72,7 +74,7 @@ def attach_files_to_synapse(
7274
7375
7476
Returns:
75-
FoldingSynapse: synapse with md_output attached
77+
JobSubmissionSynapse: synapse with md_output attached
7678
"""
7779

7880
synapse.md_output = {} # ensure that the initial state is empty
@@ -110,8 +112,8 @@ def attach_files_to_synapse(
110112

111113

112114
def check_synapse(
113-
self, synapse: FoldingSynapse, output_dir: str, event: Dict = None
114-
) -> FoldingSynapse:
115+
self, synapse: JobSubmissionSynapse, output_dir: str, event: Dict = None
116+
) -> JobSubmissionSynapse:
115117
"""Utility function to remove md_inputs if they exist"""
116118
if len(synapse.md_inputs) > 0:
117119
event["md_inputs_sizes"] = list(map(len, synapse.md_inputs.values()))
@@ -240,7 +242,7 @@ def check_and_remove_simulations(self, event: Dict) -> Dict:
240242

241243
return event
242244

243-
def forward(self, synapse: FoldingSynapse) -> FoldingSynapse:
245+
def forward(self, synapse: JobSubmissionSynapse) -> JobSubmissionSynapse:
244246
"""
245247
The main async function that is called by the dendrite to run the simulation.
246248
There are a set of default behaviours the miner should carry out based on the form the synapse comes in as:
@@ -252,7 +254,7 @@ def forward(self, synapse: FoldingSynapse) -> FoldingSynapse:
252254
- If the number of active processes is less than the number of CPUs and the pdb_id is unique, start a new process
253255
254256
Returns:
255-
FoldingSynapse: synapse with md_output attached
257+
JobSubmissionSynapse: synapse with md_output attached
256258
"""
257259
# If we are already running a process with the same identifier, return intermediate information
258260
bt.logging.debug(f"⌛ Query from validator for protein: {synapse.pdb_id} ⌛")
@@ -330,9 +332,7 @@ def forward(self, synapse: FoldingSynapse) -> FoldingSynapse:
330332
f"❗ Cannot start new process: job limit reached. ({len(self.simulations)}/{self.max_workers}).❗"
331333
)
332334

333-
bt.logging.warning(
334-
f"❗ Removing miner from job pool ❗"
335-
)
335+
bt.logging.warning(f"❗ Removing miner from job pool ❗")
336336

337337
event["condition"] = "cpu_limit_reached"
338338
synapse.miner_serving = False
@@ -378,7 +378,7 @@ def forward(self, synapse: FoldingSynapse) -> FoldingSynapse:
378378
self=self, synapse=synapse, event=event, output_dir=output_dir
379379
)
380380

381-
async def blacklist(self, synapse: FoldingSynapse) -> Tuple[bool, str]:
381+
async def blacklist(self, synapse: JobSubmissionSynapse) -> Tuple[bool, str]:
382382
if (
383383
not self.config.blacklist.allow_non_registered
384384
and synapse.dendrite.hotkey not in self.metagraph.hotkeys
@@ -406,7 +406,7 @@ async def blacklist(self, synapse: FoldingSynapse) -> Tuple[bool, str]:
406406
)
407407
return False, "Hotkey recognized!"
408408

409-
async def priority(self, synapse: FoldingSynapse) -> float:
409+
async def priority(self, synapse: JobSubmissionSynapse) -> float:
410410
caller_uid = self.metagraph.hotkeys.index(
411411
synapse.dendrite.hotkey
412412
) # Get the caller index.

folding/protocol.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@
2121
import bittensor as bt
2222

2323

24-
class FoldingSynapse(bt.Synapse):
24+
class PingSynapse(bt.Synapse):
25+
""" Responsible for determining if a miner can accept a request """
26+
can_serve: bool = False
27+
available_compute: typing.Optional[int] = None #TODO: number of threads / gpus?
28+
29+
30+
class JobSubmissionSynapse(bt.Synapse):
2531
"""
2632
A protocol representation which uses bt.Synapse as its base.
2733
This protocol helps in handling request and response communication between
@@ -59,7 +65,7 @@ def deserialize(self) -> int:
5965
f"Deserializing response from miner, I am: {self.pdb_id}, hotkey: {self.axon.hotkey[:8]}"
6066
)
6167
# Right here we perform validation that the reponse has expected hash
62-
if type(self.md_output) != dict:
68+
if not isinstance(self.md_output, dict):
6369
self.md_output = {}
6470
else:
6571
md_output = {}

folding/utils/config.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def add_args(cls, parser):
7070
help="Device to run on.",
7171
default="cpu",
7272
)
73-
73+
7474
parser.add_argument(
7575
"--neuron.metagraph_resync_length",
7676
type=int,
@@ -302,6 +302,12 @@ def add_validator_args(cls, parser):
302302
help="The timeout for each forward call. (seconds)",
303303
default=45,
304304
)
305+
parser.add_argument(
306+
"--neuron.ping_timeout",
307+
type=float,
308+
help="Controls the timeout for the PingSynapse call",
309+
default=3,
310+
)
305311

306312
parser.add_argument(
307313
"--neuron.update_interval",

folding/utils/ops.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1+
import hashlib
12
import os
3+
import pickle as pkl
4+
import random
25
import re
3-
import sys
4-
import tqdm
56
import shutil
6-
import random
7-
import hashlib
87
import subprocess
8+
import sys
99
import traceback
10-
import pickle as pkl
10+
from typing import Dict, List
1111

12-
from typing import List, Dict
12+
import bittensor as bt
1313
import requests
14+
import tqdm
1415

15-
import bittensor as bt
16-
from folding.protocol import FoldingSynapse
16+
from folding.protocol import JobSubmissionSynapse
1717

1818
# Recommended force field-water pairs, retrieved from gromacs-2024.1/share/top
1919
FF_WATER_PAIRS = {
@@ -244,7 +244,7 @@ def is_pdb_complete(pdb_text: str) -> bool:
244244
return True
245245

246246

247-
def get_response_info(responses: List[FoldingSynapse]) -> Dict:
247+
def get_response_info(responses: List[JobSubmissionSynapse]) -> Dict:
248248
"""Gather all desired response information from the set of miners."""
249249

250250
response_times = []

folding/validators/forward.py

+29-3
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
import bittensor as bt
44
from pathlib import Path
55
from typing import List, Dict
6+
from collections import defaultdict
67

78
from folding.validators.protein import Protein
89
from folding.utils.logging import log_event
910
from folding.validators.reward import get_energies
10-
from folding.protocol import FoldingSynapse
11+
from folding.protocol import PingSynapse, JobSubmissionSynapse
1112

1213
from folding.utils.ops import select_random_pdb_id, load_pdb_ids, get_response_info
1314
from folding.validators.hyperparameters import HyperParameters
@@ -17,6 +18,31 @@
1718
root_dir=ROOT_DIR, filename="pdb_ids.pkl"
1819
) # TODO: Currently this is a small list of PDBs without MISSING flags.
1920

21+
def run_ping_step(
22+
self,
23+
uids: List[int],
24+
timeout: float
25+
) -> Dict:
26+
""" Report a dictionary of ping information from all miners that were
27+
randomly sampled for this batch.
28+
"""
29+
axons = [self.metagraph.axons[uid] for uid in uids]
30+
synapse = PingSynapse()
31+
32+
bt.logging.info(f"Pinging {len(axons)} uids")
33+
responses: List[PingSynapse] = self.dendrite.query(
34+
axons=axons,
35+
synapse=synapse,
36+
timeout=timeout,
37+
)
38+
39+
ping_report = defaultdict(list)
40+
for resp in responses:
41+
ping_report['miner_status'].append(resp.can_serve)
42+
ping_report['reported_compute'].append(resp.available_compute)
43+
44+
return ping_report
45+
2046

2147
def run_step(
2248
self,
@@ -29,13 +55,13 @@ def run_step(
2955

3056
# Get the list of uids to query for this step.
3157
axons = [self.metagraph.axons[uid] for uid in uids]
32-
synapse = FoldingSynapse(
58+
synapse = JobSubmissionSynapse(
3359
pdb_id=protein.pdb_id, md_inputs=protein.md_inputs, mdrun_args=mdrun_args
3460
)
3561

3662
# Make calls to the network with the prompt - this is synchronous.
3763
bt.logging.warning("waiting for responses....")
38-
responses: List[FoldingSynapse] = self.dendrite.query(
64+
responses: List[JobSubmissionSynapse] = self.dendrite.query(
3965
axons=axons,
4066
synapse=synapse,
4167
timeout=timeout,

folding/validators/reward.py

+7-10
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
1-
import os
2-
import pandas as pd
3-
import numpy as np
1+
from typing import List
2+
43
import bittensor as bt
5-
from typing import List, Dict
4+
import numpy as np
65

6+
from folding.protocol import JobSubmissionSynapse
77
from folding.validators.protein import Protein
8-
from folding.utils.data import DataExtractor
9-
from folding.protocol import FoldingSynapse
10-
from folding.rewards.reward import RewardEvent
11-
from folding.rewards.energy import EnergyRewardModel
12-
from folding.rewards.rmsd import RMSDRewardModel
138

149

15-
def get_energies(protein: Protein, responses: List[FoldingSynapse], uids: List[int]):
10+
def get_energies(
11+
protein: Protein, responses: List[JobSubmissionSynapse], uids: List[int]
12+
):
1613
"""Takes all the data from reponse synapses, applies the reward pipeline, and aggregates the rewards
1714
into a single torch.FloatTensor. Also aggregates the RMSDs for logging.
1815

min_compute.yml

+7-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
# NOTE: Specification for miners may be different from validators
99

10-
version: '1.0' # update this version key as needed, ideally should match your release version
10+
version: '0.3.0' # update this version key as needed, ideally should match your release version
1111

1212
compute_spec:
1313

@@ -20,6 +20,12 @@ compute_spec:
2020
recommended_speed: 3.5 # Recommended speed per core (GHz)
2121
architecture: "x86_64" # Architecture type (e.g., x86_64, arm64)
2222

23+
gpu:
24+
required: True # Does the application require a GPU?
25+
min_vram: 24 # Minimum GPU VRAM (GB)
26+
min_compute_capability: 6.0 # Minimum CUDA compute capability
27+
recommended_compute_capability: 7.0 # Recommended CUDA compute capability
28+
2329
memory:
2430
min_ram: 16 # Minimum RAM (GB)
2531
min_swap: 4 # Minimum swap space (GB)

0 commit comments

Comments
 (0)