Skip to content

Commit dc16459

Browse files
authored
Merge pull request #320 from opentensor/feat/thewhaleking/allow-arbitrary-hyperparams
Arbitrary Hyperparams Setting
2 parents 1149ecd + a88531d commit dc16459

File tree

3 files changed

+135
-42
lines changed

3 files changed

+135
-42
lines changed

bittensor_cli/cli.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
WalletValidationTypes as WV,
2727
Constants,
2828
COLOR_PALETTE,
29+
HYPERPARAMS,
2930
)
3031
from bittensor_cli.src.bittensor import utils
3132
from bittensor_cli.src.bittensor.balances import Balance
@@ -3985,7 +3986,7 @@ def sudo_set(
39853986
param_name: str = typer.Option(
39863987
"", "--param", "--parameter", help="The subnet hyperparameter to set"
39873988
),
3988-
param_value: str = typer.Option(
3989+
param_value: Optional[str] = typer.Option(
39893990
"", "--value", help="Value to set the hyperparameter to."
39903991
),
39913992
quiet: bool = Options.quiet,
@@ -4034,9 +4035,12 @@ def sudo_set(
40344035
param_value = f"{low_val},{high_val}"
40354036

40364037
if not param_value:
4037-
param_value = Prompt.ask(
4038-
f"Enter the new value for [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{param_name}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] in the VALUE column format"
4039-
)
4038+
if HYPERPARAMS.get(param_name):
4039+
param_value = Prompt.ask(
4040+
f"Enter the new value for [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{param_name}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] in the VALUE column format"
4041+
)
4042+
else:
4043+
param_value = None
40404044

40414045
wallet = self.wallet_ask(
40424046
wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME, WO.PATH]

bittensor_cli/src/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ class WalletValidationTypes(Enum):
672672
"commit_reveal_weights_enabled": ("sudo_set_commit_reveal_weights_enabled", False),
673673
"alpha_values": ("sudo_set_alpha_values", False),
674674
"liquid_alpha_enabled": ("sudo_set_liquid_alpha_enabled", False),
675-
"network_registration_allowed": ("sudo_set_network_registration_allowed", False),
675+
"registration_allowed": ("sudo_set_network_registration_allowed", False),
676676
"network_pow_registration_allowed": (
677677
"sudo_set_network_pow_registration_allowed",
678678
False,

bittensor_cli/src/commands/sudo.py

Lines changed: 126 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
normalize_hyperparameters,
1919
unlock_key,
2020
blocks_to_duration,
21+
float_to_u64,
22+
float_to_u16,
2123
)
2224

2325
if TYPE_CHECKING:
@@ -70,12 +72,76 @@ def allowed_value(
7072
return True, value
7173

7274

75+
def search_metadata(
76+
param_name: str, value: Union[str, bool, float, list[float]], netuid: int, metadata
77+
) -> tuple[bool, Optional[dict]]:
78+
"""
79+
Searches the substrate metadata AdminUtils pallet for a given parameter name. Crafts a response dict to be used
80+
as call parameters for setting this hyperparameter.
81+
82+
Args:
83+
param_name: the name of the hyperparameter
84+
value: the value to set the hyperparameter
85+
netuid: the specified netuid
86+
metadata: the subtensor.substrate.metadata
87+
88+
Returns:
89+
(success, dict of call params)
90+
91+
"""
92+
93+
def string_to_bool(val) -> bool:
94+
try:
95+
return {"true": True, "1": True, "0": False, "false": False}[val.lower()]
96+
except KeyError:
97+
return ValueError
98+
99+
def type_converter_with_retry(type_, val, arg_name):
100+
try:
101+
if val is None:
102+
val = input(
103+
f"Enter a value for field '{arg_name}' with type '{arg_type_output[type_]}': "
104+
)
105+
return arg_types[type_](val)
106+
except ValueError:
107+
return type_converter_with_retry(type_, None, arg_name)
108+
109+
arg_types = {"bool": string_to_bool, "u16": float_to_u16, "u64": float_to_u64}
110+
arg_type_output = {"bool": "bool", "u16": "float", "u64": "float"}
111+
112+
call_crafter = {"netuid": netuid}
113+
114+
for pallet in metadata.pallets:
115+
if pallet.name == "AdminUtils":
116+
for call in pallet.calls:
117+
if call.name == param_name:
118+
if "netuid" not in [x.name for x in call.args]:
119+
return False, None
120+
call_args = [
121+
arg for arg in call.args if arg.value["name"] != "netuid"
122+
]
123+
if len(call_args) == 1:
124+
arg = call_args[0].value
125+
call_crafter[arg["name"]] = type_converter_with_retry(
126+
arg["typeName"], value, arg["name"]
127+
)
128+
else:
129+
for arg_ in call_args:
130+
arg = arg_.value
131+
call_crafter[arg["name"]] = type_converter_with_retry(
132+
arg["typeName"], None, arg["name"]
133+
)
134+
return True, call_crafter
135+
else:
136+
return False, None
137+
138+
73139
async def set_hyperparameter_extrinsic(
74140
subtensor: "SubtensorInterface",
75141
wallet: "Wallet",
76142
netuid: int,
77143
parameter: str,
78-
value: Union[str, bool, float, list[float]],
144+
value: Optional[Union[str, bool, float, list[float]]],
79145
wait_for_inclusion: bool = False,
80146
wait_for_finalization: bool = True,
81147
) -> bool:
@@ -110,44 +176,58 @@ async def set_hyperparameter_extrinsic(
110176
if not unlock_key(wallet).success:
111177
return False
112178

179+
arbitrary_extrinsic = False
180+
113181
extrinsic, sudo_ = HYPERPARAMS.get(parameter, ("", False))
114-
if extrinsic is None:
115-
err_console.print(":cross_mark: [red]Invalid hyperparameter specified.[/red]")
116-
return False
182+
if not extrinsic:
183+
arbitrary_extrinsic, call_params = search_metadata(
184+
parameter, value, netuid, subtensor.substrate.metadata
185+
)
186+
extrinsic = parameter
187+
if not arbitrary_extrinsic:
188+
err_console.print(
189+
":cross_mark: [red]Invalid hyperparameter specified.[/red]"
190+
)
191+
return False
117192

193+
substrate = subtensor.substrate
194+
msg_value = value if not arbitrary_extrinsic else call_params
118195
with console.status(
119-
f":satellite: Setting hyperparameter [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{parameter}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] to [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{value}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] on subnet: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{netuid}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] ...",
196+
f":satellite: Setting hyperparameter [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{parameter}"
197+
f"[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] to [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{msg_value}"
198+
f"[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] on subnet: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]"
199+
f"{netuid}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] ...",
120200
spinner="earth",
121201
):
122-
substrate = subtensor.substrate
123-
extrinsic_params = await substrate.get_metadata_call_function(
124-
"AdminUtils", extrinsic
125-
)
126-
call_params: dict[str, Union[str, bool, float]] = {"netuid": netuid}
127-
128-
# if input value is a list, iterate through the list and assign values
129-
if isinstance(value, list):
130-
# Ensure that there are enough values for all non-netuid parameters
131-
non_netuid_fields = [
132-
param["name"]
133-
for param in extrinsic_params["fields"]
134-
if "netuid" not in param["name"]
135-
]
136-
137-
if len(value) < len(non_netuid_fields):
138-
raise ValueError(
139-
"Not enough values provided in the list for all parameters"
140-
)
141-
142-
call_params.update(
143-
{str(name): val for name, val in zip(non_netuid_fields, value)}
202+
if not arbitrary_extrinsic:
203+
extrinsic_params = await substrate.get_metadata_call_function(
204+
"AdminUtils", extrinsic
144205
)
206+
call_params = {"netuid": netuid}
207+
208+
# if input value is a list, iterate through the list and assign values
209+
if isinstance(value, list):
210+
# Ensure that there are enough values for all non-netuid parameters
211+
non_netuid_fields = [
212+
param["name"]
213+
for param in extrinsic_params["fields"]
214+
if "netuid" not in param["name"]
215+
]
216+
217+
if len(value) < len(non_netuid_fields):
218+
raise ValueError(
219+
"Not enough values provided in the list for all parameters"
220+
)
145221

146-
else:
147-
value_argument = extrinsic_params["fields"][
148-
len(extrinsic_params["fields"]) - 1
149-
]
150-
call_params[str(value_argument["name"])] = value
222+
call_params.update(
223+
{str(name): val for name, val in zip(non_netuid_fields, value)}
224+
)
225+
226+
else:
227+
value_argument = extrinsic_params["fields"][
228+
len(extrinsic_params["fields"]) - 1
229+
]
230+
call_params[str(value_argument["name"])] = value
151231

152232
# create extrinsic call
153233
call_ = await substrate.compose_call(
@@ -167,11 +247,16 @@ async def set_hyperparameter_extrinsic(
167247
if not success:
168248
err_console.print(f":cross_mark: [red]Failed[/red]: {err_msg}")
169249
await asyncio.sleep(0.5)
170-
250+
elif arbitrary_extrinsic:
251+
console.print(
252+
f":white_heavy_check_mark: "
253+
f"[dark_sea_green3]Hyperparameter {parameter} values changed to {call_params}[/dark_sea_green3]"
254+
)
171255
# Successful registration, final check for membership
172256
else:
173257
console.print(
174-
f":white_heavy_check_mark: [dark_sea_green3]Hyperparameter {parameter} changed to {value}[/dark_sea_green3]"
258+
f":white_heavy_check_mark: "
259+
f"[dark_sea_green3]Hyperparameter {parameter} changed to {value}[/dark_sea_green3]"
175260
)
176261
return True
177262

@@ -470,7 +555,7 @@ async def sudo_set_hyperparameter(
470555
subtensor: "SubtensorInterface",
471556
netuid: int,
472557
param_name: str,
473-
param_value: str,
558+
param_value: Optional[str],
474559
):
475560
"""Set subnet hyperparameters."""
476561

@@ -481,7 +566,12 @@ async def sudo_set_hyperparameter(
481566
"commit_reveal_weights_enabled",
482567
"liquid_alpha_enabled",
483568
]:
484-
normalized_value = param_value.lower() in ["true", "True", "1"]
569+
normalized_value = param_value.lower() in ["true", "1"]
570+
elif param_value in ("True", "False"):
571+
normalized_value = {
572+
"True": True,
573+
"False": False,
574+
}[param_value]
485575
else:
486576
normalized_value = param_value
487577

@@ -492,7 +582,6 @@ async def sudo_set_hyperparameter(
492582
f"Value is {normalized_value} but must be {value}"
493583
)
494584
return
495-
496585
success = await set_hyperparameter_extrinsic(
497586
subtensor, wallet, netuid, param_name, value
498587
)

0 commit comments

Comments
 (0)