Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arbitrary Hyperparams Setting #320

Merged
5 changes: 3 additions & 2 deletions bittensor_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3229,10 +3229,11 @@ def stake_remove(
ask_for=[WO.NAME, WO.PATH],
)
else:
if not hotkey_ss58_address and not wallet_hotkey:
if not hotkey_ss58_address and not wallet_hotkey:
hotkey_or_ss58 = Prompt.ask(
"Enter the [blue]hotkey[/blue] name or [blue]ss58 address[/blue] to unstake all from [dim](or enter 'all' to unstake from all hotkeys)[/dim]",
default=self.config.get("wallet_hotkey") or defaults.wallet.hotkey,
default=self.config.get("wallet_hotkey")
or defaults.wallet.hotkey,
)
else:
hotkey_or_ss58 = hotkey_ss58_address or wallet_hotkey
Expand Down
2 changes: 1 addition & 1 deletion bittensor_cli/src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ class WalletValidationTypes(Enum):
"commit_reveal_weights_enabled": ("sudo_set_commit_reveal_weights_enabled", False),
"alpha_values": ("sudo_set_alpha_values", False),
"liquid_alpha_enabled": ("sudo_set_liquid_alpha_enabled", False),
"network_registration_allowed": ("sudo_set_network_registration_allowed", False),
"registration_allowed": ("sudo_set_network_registration_allowed", False),
"network_pow_registration_allowed": (
"sudo_set_network_pow_registration_allowed",
False,
Expand Down
8 changes: 2 additions & 6 deletions bittensor_cli/src/commands/stake/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,7 @@ async def safe_stake_extrinsic(
)
return
else:
err_out(
f"\n{failure_prelude} with error: {format_error_message(e)}"
)
err_out(f"\n{failure_prelude} with error: {format_error_message(e)}")
return
else:
await response.process_events()
Expand Down Expand Up @@ -180,9 +178,7 @@ async def stake_extrinsic(
extrinsic, wait_for_inclusion=True, wait_for_finalization=False
)
except SubstrateRequestException as e:
err_out(
f"\n{failure_prelude} with error: {format_error_message(e)}"
)
err_out(f"\n{failure_prelude} with error: {format_error_message(e)}")
return
else:
await response.process_events()
Expand Down
8 changes: 3 additions & 5 deletions bittensor_cli/src/commands/subnets/subnets.py
Original file line number Diff line number Diff line change
Expand Up @@ -889,8 +889,8 @@ async def show_root():
total_emission_per_block = 0
for netuid_ in range(len(all_subnets)):
subnet = all_subnets[netuid_]
emission_on_subnet = (
root_state.emission_history[netuid_][idx] / (subnet.tempo or 1)
emission_on_subnet = root_state.emission_history[netuid_][idx] / (
subnet.tempo or 1
)
total_emission_per_block += subnet.alpha_to_tao(
Balance.from_rao(emission_on_subnet)
Expand Down Expand Up @@ -2135,9 +2135,7 @@ async def get_identity(subtensor: "SubtensorInterface", netuid: int, title: str
title = "Subnet Identity"

if not await subtensor.subnet_exists(netuid):
print_error(
f"Subnet {netuid} does not exist."
)
print_error(f"Subnet {netuid} does not exist.")
raise typer.Exit()

with console.status(
Expand Down
145 changes: 112 additions & 33 deletions bittensor_cli/src/commands/sudo.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
normalize_hyperparameters,
unlock_key,
blocks_to_duration,
float_to_u64,
float_to_u16,
)

if TYPE_CHECKING:
Expand Down Expand Up @@ -70,6 +72,64 @@ def allowed_value(
return True, value


def search_metadata(
param_name: str, value: Union[str, bool, float, list[float]], netuid: int, metadata
) -> tuple[bool, Optional[dict]]:
"""
Searches the substrate metadata AdminUtils pallet for a given parameter name. Crafts a response dict to be used
as call parameters for setting this hyperparameter.

Args:
param_name: the name of the hyperparameter
value: the value to set the hyperparameter
netuid: the specified netuid
metadata: the subtensor.substrate.metadata

Returns:
(success, dict of call params)

"""

def type_converter_with_retry(type_, val, arg_name):
try:
if val is None:
val = input(
f"Enter a value for field '{arg_name}' with type '{arg_type_output[type_]}'"
)
return arg_types[type_](val)
except ValueError:
return type_converter_with_retry(type_, None, arg_name)

arg_types = {"bool": bool, "u16": float_to_u16, "u64": float_to_u64}
arg_type_output = {"bool": bool, "u16": float, "u64": float}

call_crafter = {"netuid": netuid}

for pallet in metadata.pallets:
if pallet.name == "AdminUtils":
for call in pallet.calls:
if call.name == param_name:
if "netuid" not in [x.name for x in call.args]:
return False, None
call_args = [
arg for arg in call.args if arg.value["name"] != "netuid"
]
if len(call_args) == 1:
arg = call_args[0].value
call_crafter[arg["name"]] = type_converter_with_retry(
arg["typeName"], value, arg["name"]
)
else:
for arg_ in call_args:
arg = arg_.value
call_crafter[arg["name"]] = type_converter_with_retry(
arg["typeName"], None, arg["name"]
)
return True, call_crafter
else:
return False, None


async def set_hyperparameter_extrinsic(
subtensor: "SubtensorInterface",
wallet: "Wallet",
Expand Down Expand Up @@ -110,44 +170,54 @@ async def set_hyperparameter_extrinsic(
if not unlock_key(wallet).success:
return False

arbitrary_extrinsic = False

extrinsic, sudo_ = HYPERPARAMS.get(parameter, ("", False))
if extrinsic is None:
err_console.print(":cross_mark: [red]Invalid hyperparameter specified.[/red]")
return False
if not extrinsic:
arbitrary_extrinsic, call_params = search_metadata(
parameter, value, netuid, subtensor.substrate.metadata
)
extrinsic = parameter
if not arbitrary_extrinsic:
err_console.print(
":cross_mark: [red]Invalid hyperparameter specified.[/red]"
)
return False

with console.status(
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']}] ...",
spinner="earth",
):
substrate = subtensor.substrate
extrinsic_params = await substrate.get_metadata_call_function(
"AdminUtils", extrinsic
)
call_params: dict[str, Union[str, bool, float]] = {"netuid": netuid}

# if input value is a list, iterate through the list and assign values
if isinstance(value, list):
# Ensure that there are enough values for all non-netuid parameters
non_netuid_fields = [
param["name"]
for param in extrinsic_params["fields"]
if "netuid" not in param["name"]
]

if len(value) < len(non_netuid_fields):
raise ValueError(
"Not enough values provided in the list for all parameters"
)

call_params.update(
{str(name): val for name, val in zip(non_netuid_fields, value)}
if not arbitrary_extrinsic:
extrinsic_params = await substrate.get_metadata_call_function(
"AdminUtils", extrinsic
)
call_params = {"netuid": netuid}

# if input value is a list, iterate through the list and assign values
if isinstance(value, list):
# Ensure that there are enough values for all non-netuid parameters
non_netuid_fields = [
param["name"]
for param in extrinsic_params["fields"]
if "netuid" not in param["name"]
]

if len(value) < len(non_netuid_fields):
raise ValueError(
"Not enough values provided in the list for all parameters"
)

else:
value_argument = extrinsic_params["fields"][
len(extrinsic_params["fields"]) - 1
]
call_params[str(value_argument["name"])] = value
call_params.update(
{str(name): val for name, val in zip(non_netuid_fields, value)}
)

else:
value_argument = extrinsic_params["fields"][
len(extrinsic_params["fields"]) - 1
]
call_params[str(value_argument["name"])] = value

# create extrinsic call
call_ = await substrate.compose_call(
Expand All @@ -167,11 +237,16 @@ async def set_hyperparameter_extrinsic(
if not success:
err_console.print(f":cross_mark: [red]Failed[/red]: {err_msg}")
await asyncio.sleep(0.5)

elif arbitrary_extrinsic:
console.print(
f":white_heavy_check_mark: "
f"[dark_sea_green3]Hyperparameter {parameter} values changed to {call_params}[/dark_sea_green3]"
)
# Successful registration, final check for membership
else:
console.print(
f":white_heavy_check_mark: [dark_sea_green3]Hyperparameter {parameter} changed to {value}[/dark_sea_green3]"
f":white_heavy_check_mark: "
f"[dark_sea_green3]Hyperparameter {parameter} changed to {value}[/dark_sea_green3]"
)
return True

Expand Down Expand Up @@ -481,7 +556,12 @@ async def sudo_set_hyperparameter(
"commit_reveal_weights_enabled",
"liquid_alpha_enabled",
]:
normalized_value = param_value.lower() in ["true", "True", "1"]
normalized_value = param_value.lower() in ["true", "1"]
elif param_value in ("True", "False"):
normalized_value = {
"True": True,
"False": False,
}[param_value]
else:
normalized_value = param_value

Expand All @@ -492,7 +572,6 @@ async def sudo_set_hyperparameter(
f"Value is {normalized_value} but must be {value}"
)
return

success = await set_hyperparameter_extrinsic(
subtensor, wallet, netuid, param_name, value
)
Expand Down
Loading