diff --git a/.dockerignore b/.dockerignore index 7ddf229532..a498c9ee64 100644 --- a/.dockerignore +++ b/.dockerignore @@ -10,4 +10,5 @@ **/env/* **/venv/* ./circleci/* -./github/* \ No newline at end of file +./github/* +.ipynb \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 14555572c1..a523032bfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 5.1.0 / 2023-05-30 + +## What's Changed +* update readme by @unconst in https://github.com/opentensor/bittensor/pull/1344 +* Reset scores for validators by @adriansmares in https://github.com/opentensor/bittensor/pull/1359 + + +**Full Changelog**: https://github.com/opentensor/bittensor/compare/v5.0.0...v5.1.0 + + ## 5.0.0 / 2023-05-17 **Full Changelog**: https://github.com/opentensor/bittensor/compare/v4.0.1...v5.0.0 diff --git a/VERSION b/VERSION index 0062ac9718..acf69b48b8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.0 +5.1.0 \ No newline at end of file diff --git a/bittensor/__init__.py b/bittensor/__init__.py index ecc8a03256..1923c376f0 100644 --- a/bittensor/__init__.py +++ b/bittensor/__init__.py @@ -27,7 +27,7 @@ nest_asyncio.apply() # Bittensor code and protocol version. -__version__ = '5.0.0' +__version__ = '5.1.0' version_split = __version__.split(".") __version_as_int__ = (100 * int(version_split[0])) + (10 * int(version_split[1])) + (1 * int(version_split[2])) __new_signature_version__ = 360 @@ -168,6 +168,8 @@ def turn_console_off(): from bittensor._serializer import serializer as serializer from bittensor._dataset import dataset as dataset from bittensor._threadpool import prioritythreadpool as prioritythreadpool +from bittensor._blacklist import blacklist as blacklist +from bittensor._priority import priority as priority # ---- Classes ----- from bittensor._cli.cli_impl import CLI as CLI @@ -207,7 +209,10 @@ def turn_console_off(): from bittensor._dendrite.text_prompting.dendrite_pool import TextPromptingDendritePool as text_prompting_pool # ---- Base Miners ----- -from bittensor._synapse.text_prompting.miner import BasePromptingMiner +from bittensor._neuron.base_miner_neuron import BaseMinerNeuron +from bittensor._neuron.base_validator import BaseValidator +from bittensor._neuron.base_prompting_miner import BasePromptingMiner +from bittensor._neuron.base_huggingface_miner import HuggingFaceMiner # ---- Errors and Exceptions ----- from bittensor._keyfile.keyfile_impl import KeyFileError as KeyFileError diff --git a/bittensor/_axon/__init__.py b/bittensor/_axon/__init__.py index 719400d71d..01d656f0a9 100644 --- a/bittensor/_axon/__init__.py +++ b/bittensor/_axon/__init__.py @@ -51,7 +51,7 @@ def info(self) -> 'axon_info': def __init__( self, wallet: "bittensor.Wallet", - metagraph: "bittensor.Metagraph", + metagraph: Optional["bittensor.Metagraph"] = None, config: Optional["bittensor.config"] = None, port: Optional[int] = None, ip: Optional[str] = None, @@ -159,6 +159,11 @@ def help(cls): def add_args(cls, parser: argparse.ArgumentParser, prefix: str = None): """Accept specific arguments from parser""" prefix_str = "" if prefix is None else prefix + "." + if prefix is not None: + if not hasattr(bittensor.defaults, prefix): + setattr(bittensor.defaults, prefix, bittensor.Config()) + getattr(bittensor.defaults, prefix).axon = bittensor.defaults.axon + bittensor.prioritythreadpool.add_args(parser, prefix=prefix_str + "axon") try: parser.add_argument( @@ -290,7 +295,7 @@ def __init__( self.receiver_hotkey = receiver_hotkey - def parse_signature_v2(self, signature: str) -> Union[Tuple[int, str, str, str, int], None]: + def parse_signature_v2(self, signature: str) -> Optional[Tuple[int, str, str, str]]: r"""Attempts to parse a signature using the v2 format""" parts = signature.split(".") if len(parts) != 4: @@ -304,7 +309,7 @@ def parse_signature_v2(self, signature: str) -> Union[Tuple[int, str, str, str, receptor_uuid = parts[3] return (nonce, sender_hotkey, signature, receptor_uuid) - def parse_signature(self, metadata: Dict[str, str]) -> Tuple[int, str, str, str, int]: + def parse_signature(self, metadata: Dict[str, str]) -> Tuple[int, str, str, str]: r"""Attempts to parse a signature from the metadata""" signature = metadata.get("bittensor-signature") version = metadata.get('bittensor-version') @@ -444,7 +449,7 @@ def to_parameter_dict( self ) -> 'torch.nn.ParameterDict': ) @classmethod - def from_parameter_dict( cls, parameter_dict: 'torch.nn.ParameterDict' ) -> 'SubnetInfo': - r""" Returns a SubnetInfo object from a torch parameter_dict. + def from_parameter_dict( cls, parameter_dict: 'torch.nn.ParameterDict' ) -> 'axon_info': + r""" Returns an axon_info object from a torch parameter_dict. """ return cls( **dict(parameter_dict) ) \ No newline at end of file diff --git a/bittensor/_blacklist/__init__.py b/bittensor/_blacklist/__init__.py new file mode 100644 index 0000000000..2a023a5495 --- /dev/null +++ b/bittensor/_blacklist/__init__.py @@ -0,0 +1,114 @@ +# The MIT License (MIT) +# Copyright © 2021 Yuma Rao +# Copyright © 2022 Opentensor Foundation + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +import argparse +import bittensor +from typing import Union, Tuple + +class blacklist: + + def __init__( self, config: "bittensor.Config" = None ): + self.config = config or blacklist.config() + + @classmethod + def config( cls ) -> "bittensor.Config": + parser = argparse.ArgumentParser() + blacklist.add_args(parser) + return bittensor.config( parser ) + + @classmethod + def help(cls): + parser = argparse.ArgumentParser() + cls.add_args(parser) + print( cls.__new__.__doc__ ) + parser.print_help() + + @classmethod + def add_args( cls, parser: argparse.ArgumentParser, prefix: str = None ): + prefix_str = "" if prefix is None else prefix + "." + parser.add_argument( + '--' + prefix_str + 'blacklist.blacklisted_keys', + type = str, + required = False, + nargs = '*', + action = 'store', + help = 'List of ss58 addresses which are always disallowed pass through.', default=[] + ) + parser.add_argument( + '--' + prefix_str + 'blacklist.whitelisted_keys', + type = str, + required = False, + nargs = '*', + action = 'store', + help = 'List of ss58 addresses which are always allowed pass through.', default=[] + ) + parser.add_argument( + '--' + prefix_str + 'blacklist.allow_non_registered', + action = 'store_true', + help = 'If True, the miner will allow non-registered hotkeys to mine.', + default = True + ) + parser.add_argument( + '--' + prefix_str + 'blacklist.min_allowed_stake', + type = float, + help = 'Minimum stake required to pass blacklist.', + default = 0.0 + ) + parser.add_argument( + '--' + prefix_str + 'blacklist.vpermit_required', + action = 'store_true', + help = 'If True, the miner will require a vpermit to pass blacklist.', + default = False + ) + + def blacklist( + self, + forward_call: "bittensor.SynapseCall", + metagraph: "bittensor.Metagraph" = None, + ) -> Union[ Tuple[bool, str], bool ]: + + # Check for blacklisted keys which take priority over all other checks. + src_hotkey = forward_call.src_hotkey + if src_hotkey in self.config.blacklist.blacklisted_keys: + return True, 'blacklisted key' + + # Check for whitelisted keys which take priority over all remaining checks. + if src_hotkey in self.config.blacklist.whitelisted_keys: + return False, 'whitelisted key' + + # Check if pubkey is registered. + is_registered = False + if metagraph is not None: + is_registered = src_hotkey in metagraph.hotkeys + + if not is_registered and not self.config.blacklist.allow_non_registered: + return True, 'pubkey not registered' + + # Check for stake amount. + if is_registered and self.config.blacklist.min_allowed_stake > 0.0: + uid = metagraph.hotkeys.index(src_hotkey) + stake = metagraph.S[uid].item() + if stake < self.config.blacklist.min_allowed_stake: + return True, 'pubkey stake below min_allowed_stake' + + # Check for vpermit. + if metagraph is not None and self.config.blacklist.vpermit_required and is_registered: + uid = metagraph.hotkeys.index(src_hotkey) + return metagraph.neurons[uid].validator_permit + + # All checks passed. + return False, 'passed blacklist' \ No newline at end of file diff --git a/bittensor/_cli/commands/delegates.py b/bittensor/_cli/commands/delegates.py index 4d5487c829..a08460adef 100644 --- a/bittensor/_cli/commands/delegates.py +++ b/bittensor/_cli/commands/delegates.py @@ -206,7 +206,7 @@ def check_config( config: 'bittensor.Config' ): config.delegate_ss58key = str(delegates[int(delegate_index)].hotkey_ss58) console.print("Selected: [yellow]{}[/yellow]".format(config.delegate_ss58key)) - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) @@ -281,10 +281,7 @@ def add_args( parser: argparse.ArgumentParser ): @staticmethod def check_config( config: 'bittensor.Config' ): - # if config.subtensor.get('network') == bittensor.defaults.subtensor.network and not config.no_prompt: - # config.subtensor.network = Prompt.ask("Enter subtensor network", choices=bittensor.__networks__, default = bittensor.defaults.subtensor.network) - - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) @@ -410,11 +407,11 @@ def add_args( parser: argparse.ArgumentParser ): @staticmethod def check_config( config: 'bittensor.Config' ): - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) - if config.wallet.get('hotkey') == bittensor.defaults.wallet.hotkey and not config.no_prompt: + if not config.is_set('wallet.hotkey') and not config.no_prompt: hotkey = Prompt.ask("Enter hotkey name", default = bittensor.defaults.wallet.hotkey) config.wallet.hotkey = str(hotkey) @@ -527,7 +524,7 @@ def add_args( parser: argparse.ArgumentParser ): @staticmethod def check_config( config: 'bittensor.Config' ): - if not config.get( 'all', d=None ) and config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.get( 'all', d=None ) and not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) diff --git a/bittensor/_cli/commands/inspect.py b/bittensor/_cli/commands/inspect.py index ed622ac242..3596f5a731 100644 --- a/bittensor/_cli/commands/inspect.py +++ b/bittensor/_cli/commands/inspect.py @@ -121,6 +121,16 @@ def run (cli): for netuid in netuids: for neuron in neuron_state_dict[netuid]: if neuron.coldkey == wallet.coldkeypub.ss58_address: + hotkey_name: str = '' + + hotkey_names: List[str] = \ + [ wallet.hotkey_str for wallet in filter( + lambda hotkey: hotkey.hotkey.ss58_address == neuron.hotkey, + hotkeys + ) ] + if len(hotkey_names) > 0: + hotkey_name = f'{hotkey_names[0]}-' + table.add_row( '', '', @@ -128,7 +138,7 @@ def run (cli): '', '', str( netuid ), - str( neuron.hotkey ), + f'{hotkey_name}{neuron.hotkey}', str( neuron.stake ), str( bittensor.Balance.from_tao(neuron.emission) ) ) @@ -139,7 +149,7 @@ def run (cli): @staticmethod def check_config( config: 'bittensor.Config' ): - if not config.get( 'all', d=None ) and config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.get( 'all', d=None ) and not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) diff --git a/bittensor/_cli/commands/overview.py b/bittensor/_cli/commands/overview.py index cbc668e4ab..8f86539f6c 100644 --- a/bittensor/_cli/commands/overview.py +++ b/bittensor/_cli/commands/overview.py @@ -333,7 +333,7 @@ def add_args( parser: argparse.ArgumentParser ): @staticmethod def check_config( config: 'bittensor.Config' ): - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt and not config.get( 'all', d=None ): + if not config.is_set('wallet.name') and not config.no_prompt and not config.get( 'all', d=None ): wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) diff --git a/bittensor/_cli/commands/register.py b/bittensor/_cli/commands/register.py index 21884d58df..67d74eecf6 100644 --- a/bittensor/_cli/commands/register.py +++ b/bittensor/_cli/commands/register.py @@ -83,11 +83,11 @@ def add_args( parser: argparse.ArgumentParser ): def check_config( config: 'bittensor.Config' ): check_netuid_set( config, subtensor = bittensor.subtensor( config = config ) ) - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) - if config.wallet.get('hotkey') == bittensor.defaults.wallet.hotkey and not config.no_prompt: + if not config.is_set('wallet.hotkey') and not config.no_prompt: hotkey = Prompt.ask("Enter hotkey name", default = bittensor.defaults.wallet.hotkey) config.wallet.hotkey = str(hotkey) @@ -158,15 +158,15 @@ def add_args( parser: argparse.ArgumentParser ): @staticmethod def check_config( config: 'bittensor.Config' ): - if config.subtensor.get('network') == bittensor.defaults.subtensor.network and not config.no_prompt: + if not config.is_set('subtensor.network') and not config.no_prompt: config.subtensor.network = Prompt.ask("Enter subtensor network", choices=bittensor.__networks__, default = bittensor.defaults.subtensor.network) check_netuid_set( config, subtensor = bittensor.subtensor( config = config ) ) - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) - if config.wallet.get('hotkey') == bittensor.defaults.wallet.hotkey and not config.no_prompt: + if not config.is_set('wallet.hotkey') and not config.no_prompt: hotkey = Prompt.ask("Enter hotkey name", default = bittensor.defaults.wallet.hotkey) config.wallet.hotkey = str(hotkey) diff --git a/bittensor/_cli/commands/stake.py b/bittensor/_cli/commands/stake.py index c361989cac..4ee784ff81 100644 --- a/bittensor/_cli/commands/stake.py +++ b/bittensor/_cli/commands/stake.py @@ -137,11 +137,11 @@ def run( cli ): @classmethod def check_config( cls, config: 'bittensor.Config' ): - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) - if config.wallet.get('hotkey') == bittensor.defaults.wallet.hotkey and not config.no_prompt and not config.get('all_hotkeys') and not config.get('hotkeys'): + if not config.is_set('wallet.hotkey') and not config.no_prompt and not config.wallet.get('all_hotkeys') and not config.wallet.get('hotkeys'): hotkey = Prompt.ask("Enter hotkey name", default = bittensor.defaults.wallet.hotkey) config.wallet.hotkey = str(hotkey) diff --git a/bittensor/_cli/commands/transfer.py b/bittensor/_cli/commands/transfer.py index cdbd141032..9631cf51f0 100644 --- a/bittensor/_cli/commands/transfer.py +++ b/bittensor/_cli/commands/transfer.py @@ -33,7 +33,7 @@ def run (cli): @staticmethod def check_config( config: 'bittensor.Config' ): - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) diff --git a/bittensor/_cli/commands/unstake.py b/bittensor/_cli/commands/unstake.py index a820773c2a..dfb26e369e 100644 --- a/bittensor/_cli/commands/unstake.py +++ b/bittensor/_cli/commands/unstake.py @@ -26,13 +26,13 @@ class UnStakeCommand: - @classmethod - def check_config( cls, config: 'bittensor.Config' ): - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + @classmethod + def check_config( cls, config: 'bittensor.Config' ): + if config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) - if not config.get('hotkey_ss58address') and config.wallet.get('hotkey') == bittensor.defaults.wallet.hotkey and not config.no_prompt and not config.get('all_hotkeys') and not config.get('hotkeys'): + if not config.get( 'hotkey_ss58address', d=None ) and config.is_set('wallet.hotkey') and not config.no_prompt and not config.get('all_hotkeys') and not config.get('hotkeys'): hotkey = Prompt.ask("Enter hotkey name", default = bittensor.defaults.wallet.hotkey) config.wallet.hotkey = str(hotkey) diff --git a/bittensor/_cli/commands/utils.py b/bittensor/_cli/commands/utils.py index 4b72f6d125..ee6e3b8027 100644 --- a/bittensor/_cli/commands/utils.py +++ b/bittensor/_cli/commands/utils.py @@ -38,14 +38,14 @@ def check_choice( self, value: str ) -> bool: def check_netuid_set( config: 'bittensor.Config', subtensor: 'bittensor.Subtensor', allow_none: bool = False ): - if subtensor.network =='finney': + if subtensor.network != 'nakamoto': all_netuids = [str(netuid) for netuid in subtensor.get_subnets()] if len(all_netuids) == 0: console.print(":cross_mark:[red]There are no open networks.[/red]") sys.exit() # Make sure netuid is set. - if config.get('netuid', 'notset') == 'notset': + if not config.is_set('netuid'): if not config.no_prompt: netuid = IntListPrompt.ask("Enter netuid", choices=all_netuids, default=str(all_netuids[0])) else: diff --git a/bittensor/_cli/commands/wallets.py b/bittensor/_cli/commands/wallets.py index 3d97ca357b..a9ce0ac5c1 100644 --- a/bittensor/_cli/commands/wallets.py +++ b/bittensor/_cli/commands/wallets.py @@ -44,7 +44,7 @@ def run ( cli ): @staticmethod def check_config( config: 'bittensor.Config' ): - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) if config.mnemonic == None and config.get( 'seed', d=None ) == None and config.get( 'json', d=None ) == None: @@ -128,7 +128,7 @@ def run ( cli ): @staticmethod def check_config( config: 'bittensor.Config' ): - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) if config.ss58_address == None and config.public_key_hex == None: @@ -204,11 +204,11 @@ def run ( cli ): @staticmethod def check_config( config: 'bittensor.Config' ): - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) - if config.wallet.get('hotkey') == bittensor.defaults.wallet.hotkey and not config.no_prompt: + if not config.is_set('wallet.hotkey') and not config.no_prompt: hotkey = Prompt.ask("Enter hotkey name", default = bittensor.defaults.wallet.hotkey) config.wallet.hotkey = str(hotkey) if config.mnemonic == None and config.get( 'seed', d=None ) == None and config.get( 'json', d=None ) == None: @@ -295,11 +295,11 @@ def run( cli ): @staticmethod def check_config( config: 'bittensor.Config' ): - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) - if config.wallet.get('hotkey') == bittensor.defaults.wallet.hotkey and not config.no_prompt: + if not config.is_set('wallet.hotkey') and not config.no_prompt: hotkey = Prompt.ask("Enter hotkey name", default = bittensor.defaults.wallet.hotkey) config.wallet.hotkey = str(hotkey) @@ -351,7 +351,7 @@ def run ( cli ): @staticmethod def check_config( config: 'bittensor.Config' ): - if config.wallet.get('name') == bittensor.defaults.wallet.name and not config.no_prompt: + if not config.is_set('wallet.name') and not config.no_prompt: wallet_name = Prompt.ask("Enter wallet name", default = bittensor.defaults.wallet.name) config.wallet.name = str(wallet_name) diff --git a/bittensor/_config/__init__.py b/bittensor/_config/__init__.py index e7eca84f46..e26a611a06 100644 --- a/bittensor/_config/__init__.py +++ b/bittensor/_config/__init__.py @@ -22,11 +22,12 @@ import os import sys from argparse import ArgumentParser, Namespace -from typing import List, Optional +from typing import List, Optional, Dict import bittensor import yaml from loguru import logger +import pandas as pd from . import config_impl @@ -115,8 +116,49 @@ def __new__( cls, parser: ArgumentParser = None, strict: bool = False, args: Opt if len(keys) == 1: head[keys[0]] = arg_val + # Get defaults for this config + is_set_map = cls.__fill_is_set_list__(_config, bittensor.defaults) + + _config['__is_set'] = is_set_map + + _config.__fill_with_defaults__(is_set_map, bittensor.defaults) + return _config + @staticmethod + def __fill_is_set_list__(_config: 'bittensor.Config', defaults: 'bittensor.Config') -> Dict[str, bool]: + """Creates an is_set map + Args: + _config (bittensor.Config): + Config to generate is_set mapping. + defaults (bittensor.Config): + The bittensor defaults + Returns: + is_set_map (Dict[str, bool]): + A map from flattened param name to whether this param was set in a flag. + """ + is_set_map = {} + config_d = _config.__dict__ + # Only defaults we are concerned with + defaults_filtered = {} + for key in config_d.keys(): + if key in defaults.keys(): + defaults_filtered[key] = getattr(defaults, key) + # Avoid erroring out if defaults aren't set for a submodule + if defaults_filtered == {}: + return is_set_map + + flat_config = pd.json_normalize(config_d, sep='.').to_dict('records')[0] + flat_defaults = pd.json_normalize(defaults_filtered, sep='.').to_dict('records')[0] + for key, _ in flat_defaults.items(): + if key in flat_config: + is_set_map[key] = True + else: + is_set_map[key] = False + + return is_set_map + + @staticmethod def __parse_args__( args: List[str], parser: ArgumentParser = None, strict: bool = False) -> Namespace: """Parses the passed args use the passed parser. @@ -150,4 +192,3 @@ def full(): bittensor.dataset.add_args( parser ) bittensor.prometheus.add_args( parser ) return bittensor.config( parser ) - diff --git a/bittensor/_config/config_impl.py b/bittensor/_config/config_impl.py index 94c498733a..28b975d934 100644 --- a/bittensor/_config/config_impl.py +++ b/bittensor/_config/config_impl.py @@ -25,11 +25,17 @@ import bittensor from munch import Munch from prometheus_client import Info +from pandas import json_normalize +from typing import Dict +import copy +import bittensor class Config ( Munch ): """ Implementation of the config class, which manages the config of different bittensor modules. """ + __is_set: Dict[str, bool] + def __init__(self, loaded_config = None ): super().__init__() if loaded_config: @@ -52,10 +58,25 @@ def update_with_kwargs( self, kwargs ): for key,val in kwargs.items(): self[key] = val + @classmethod + def _merge( cls, a, b ): + """Merge two configurations recursively. + If there is a conflict, the value from the second configuration will take precedence. + """ + for key in b: + if key in a: + if isinstance( a[key], dict ) and isinstance( b[key], dict ): + a[key] = cls._merge( a[key], b[key] ) + else: + a[key] = b[key] + else: + a[key] = b[key] + return a + def merge(self, b): """ Merge two configs """ - self = _merge(self, b) + self = self._merge( self, b ) def to_prometheus(self): """ @@ -63,7 +84,12 @@ def to_prometheus(self): """ try: prometheus_info = Info('config', 'Config Values') - config_info = pandas.json_normalize(json.loads(json.dumps(self)), sep='.').to_dict(orient='records')[0] + # Make copy, remove __is_set map + config_copy = copy.deepcopy(self) + + del config_copy['__is_set'] + + config_info = json_normalize(json.loads(json.dumps(config_copy)), sep='.').to_dict(orient='records')[0] formatted_info = {} for key in config_info: config_info[key] = str(config_info[key]) @@ -74,6 +100,42 @@ def to_prometheus(self): # TODO(const): need a way of distinguishing the various config items. bittensor.__console__.print("The config has already been added to prometheus.", highlight=True) + def is_set(self, param_name: str) -> bool: + """ + Returns a boolean indicating whether the parameter has been set or is still the default. + """ + if param_name not in self.get('__is_set'): + return False + else: + return self.get('__is_set')[param_name] + + def __fill_with_defaults__(self, is_set_map: Dict[str, bool], defaults: 'Config') -> None: + """ + Recursively fills the config with the default values using is_set_map + """ + defaults_filtered = {} + for key in self.keys(): + if key in defaults.keys(): + defaults_filtered[key] = getattr(defaults, key) + # Avoid erroring out if defaults aren't set for a submodule + if defaults_filtered == {}: return + + flat_defaults = json_normalize(defaults_filtered, sep='.').to_dict('records')[0] + for key, val in flat_defaults.items(): + if key not in is_set_map: + continue + elif not is_set_map[key]: + # If the key is not set, set it to the default value + # Loop through flattened key to get leaf + a = self + keys = key.split('.') + for key_ in keys[:-1]: + if key_ not in a: + a[key_] = {} + a = a[key_] + # Set leaf to default value + a[keys[-1]] = val + def to_defaults(self): try: if 'axon' in self.keys(): diff --git a/bittensor/_dataset/__init__.py b/bittensor/_dataset/__init__.py index 8fb68b8f19..92628dfb04 100644 --- a/bittensor/_dataset/__init__.py +++ b/bittensor/_dataset/__init__.py @@ -134,6 +134,10 @@ def add_args(cls, parser: argparse.ArgumentParser, prefix: str = None ): """ Accept specific arguments from parser """ prefix_str = '' if prefix == None else prefix + '.' + if prefix is not None: + if not hasattr(bittensor.defaults, prefix): + setattr(bittensor.defaults, prefix, bittensor.Config()) + getattr(bittensor.defaults, prefix).dataset = bittensor.defaults.dataset try: parser.add_argument('--' + prefix_str + 'dataset.batch_size', type=int, help='Batch size.', default = bittensor.defaults.dataset.batch_size) parser.add_argument('--' + prefix_str + 'dataset.block_size', type=int, help='Number of text items to pull for each example..', default = bittensor.defaults.dataset.block_size) diff --git a/bittensor/_dendrite/dendrite.py b/bittensor/_dendrite/dendrite.py index f724360caa..0fa0a42797 100644 --- a/bittensor/_dendrite/dendrite.py +++ b/bittensor/_dendrite/dendrite.py @@ -43,6 +43,7 @@ def __init__( self.completed = False self.timeout = timeout self.start_time = time.time() + self.elapsed_time = 0.0 self.src_hotkey = self.dendrite.keypair.ss58_address self.src_version = bittensor.__version_as_int__ self.dest_hotkey = self.dendrite.axon_info.hotkey @@ -208,6 +209,7 @@ async def apply( self, dendrite_call: 'DendriteCall' ) -> DendriteCall: finally: dendrite_call.end() dendrite_call.log_inbound() + dendrite_call.elapsed_time = time.time() - dendrite_call.start_time return dendrite_call def __exit__ ( self ): diff --git a/bittensor/_logging/__init__.py b/bittensor/_logging/__init__.py index 314c9fd892..9ae0b35b02 100644 --- a/bittensor/_logging/__init__.py +++ b/bittensor/_logging/__init__.py @@ -143,6 +143,10 @@ def add_args(cls, parser: argparse.ArgumentParser, prefix: str = None ): """ Accept specific arguments fro parser """ prefix_str = '' if prefix == None else prefix + '.' + if prefix is not None: + if not hasattr(bittensor.defaults, prefix): + setattr(bittensor.defaults, prefix, bittensor.Config()) + getattr(bittensor.defaults, prefix).logging = bittensor.defaults.logging try: parser.add_argument('--' + prefix_str + 'logging.debug', action='store_true', help='''Turn on bittensor debugging information''', default = bittensor.defaults.logging.debug ) parser.add_argument('--' + prefix_str + 'logging.trace', action='store_true', help='''Turn on bittensor trace level information''', default = bittensor.defaults.logging.trace ) diff --git a/bittensor/_metagraph/__init__.py b/bittensor/_metagraph/__init__.py index b4060f88d0..f66632e9e4 100644 --- a/bittensor/_metagraph/__init__.py +++ b/bittensor/_metagraph/__init__.py @@ -108,8 +108,9 @@ def __init__(self, netuid: int, network: str = 'finney', lite: bool = True, sync if sync: self.sync( block = None, lite = lite ) - def sync ( self, block: Optional[int] = None, lite: bool = True ) -> 'metagraph': - subtensor = bittensor.subtensor( network = self.network ) + def sync ( self, block: Optional[int] = None, lite: bool = True, subtensor: Optional['bittensor.Subtensor'] = None ) -> 'metagraph': + if not subtensor: + subtensor = bittensor.subtensor( network = self.network ) if lite: self.neurons = subtensor.neurons_lite( block = block, netuid = self.netuid ) else: @@ -117,7 +118,7 @@ def sync ( self, block: Optional[int] = None, lite: bool = True ) -> 'metagraph' self.lite = lite self.n = torch.nn.Parameter( torch.tensor( len(self.neurons), dtype=torch.int64 ), requires_grad=False ) self.version = torch.nn.Parameter( torch.tensor( [bittensor.__version_as_int__], dtype=torch.int64 ), requires_grad=False ) - self.block = torch.nn.Parameter( torch.tensor( subtensor.block, dtype=torch.int64 ), requires_grad=False ) + self.block = torch.nn.Parameter( torch.tensor( block if block else subtensor.block, dtype=torch.int64 ), requires_grad=False ) self.uids = torch.nn.Parameter( torch.tensor( [ neuron.uid for neuron in self.neurons ], dtype=torch.int64 ), requires_grad=False ) self.trust = torch.nn.Parameter( torch.tensor( [ neuron.trust for neuron in self.neurons ], dtype=torch.float32 ), requires_grad=False ) self.consensus = torch.nn.Parameter( torch.tensor( [ neuron.consensus for neuron in self.neurons ], dtype=torch.float32 ), requires_grad=False ) diff --git a/bittensor/_neuron/text/core_server/__init__.py b/bittensor/_neuron/__init__.py similarity index 100% rename from bittensor/_neuron/text/core_server/__init__.py rename to bittensor/_neuron/__init__.py diff --git a/bittensor/_neuron/base_huggingface_miner.py b/bittensor/_neuron/base_huggingface_miner.py new file mode 100644 index 0000000000..0c78648edd --- /dev/null +++ b/bittensor/_neuron/base_huggingface_miner.py @@ -0,0 +1,95 @@ +# The MIT License (MIT) +# Copyright © 2023 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import bittensor +import argparse +from typing import List, Dict +from abc import ABC, abstractmethod + +class HuggingFaceMiner( bittensor.BasePromptingMiner, ABC ): + arg_prefix: str + assistant_label: str + user_label: str + system_label: str + + @classmethod + def check_config( cls, config: 'bittensor.Config' ): + pass + + @classmethod + def add_args( cls, parser: argparse.ArgumentParser ): + parser.add_argument( f'--{cls.arg_prefix}.model_name', type=str, default=None, help='Name or path of model to load' ) + parser.add_argument( f'--{cls.arg_prefix}.api_key', type=str, help='huggingface api key', default=None ) + parser.add_argument( f'--{cls.arg_prefix}.device', type=str, help='Device to load model', default="cuda" ) + parser.add_argument( f'--{cls.arg_prefix}.max_new_tokens', type=int, help='Max tokens for model output.', default=256 ) + parser.add_argument( f'--{cls.arg_prefix}.temperature', type=float, help='Sampling temperature of model', default=0.5 ) + parser.add_argument( f'--{cls.arg_prefix}.do_sample', action='store_true', default=False, help='Whether to use multinomial sampling.' ) + parser.add_argument( f'--{cls.arg_prefix}.repetition_penalty', type=float, help='Repetition penalty for model', default=1.3 ) + parser.add_argument( f'--{cls.arg_prefix}.do_prompt_injection', action='store_true', default=False, help='Whether to use a custom "system" prompt instead of the one sent by bittensor.' ) + parser.add_argument( f'--{cls.arg_prefix}.system_prompt', type=str, help='What prompt to replace the system prompt with', default= "BEGINNING OF CONVERSATION: " ) + parser.add_argument( f'--{cls.arg_prefix}.repetition-penalty', type=float, default=1.1, help='Repetition penalty for greedy decoding. Between 1.0 and infinity. 1.0 means no penalty. Default: 1.0' ) + parser.add_argument( f'--{cls.arg_prefix}.top_p', type=float, default=0.9, help='Top-p (nucleus) sampling. Defaults to 1.0 (top-k sampling). Must be between 0.0 and 1.0.' ) + parser.add_argument( f'--{cls.arg_prefix}.top_k', type=int, default=0, help='Top-k sampling. Defaults to 0 (no top-k sampling). Must be between 0 and 1000.' ) + parser.add_argument( f'--{cls.arg_prefix}.load_in_8bit', type=bool, default=False, help='Load model in 8 bit precision') + parser.add_argument( f'--{cls.arg_prefix}.device_map', type=str, default=None, help='Device map for model parallelism.') + parser.add_argument( f'--{cls.arg_prefix}.pad_tokens', type=int, default=[], nargs='+', help='A list of integers separated by spaces for the pad_tokens.') + + def __init__(self): + super( HuggingFaceMiner, self ).__init__() + + # Set model name if unset. + if getattr( self.config, self.arg_prefix ).model_name == None: + getattr( self.config, self.arg_prefix ).model_name = self.arg_prefix + + bittensor.logging.info( 'Loading ' + str( getattr( self.config, self.arg_prefix ).model_name ) ) + self.tokenizer = self.load_tokenizer() + self.model = self.load_model() + bittensor.logging.info( 'Model loaded!' ) + + # Device already configured if using pipieline or device_map is set. (i.e. Pipelines have no `.to()` method) + if getattr( self.config, self.arg_prefix ).device != "cpu" \ + and 'pipeline' not in self.model.__class__.__name__.lower() \ + and getattr( self.config, self.arg_prefix ).device_map == None: + self.model = self.model.to( getattr( self.config, self.arg_prefix ).device ) + + @abstractmethod + def load_model(self): + ... + + @abstractmethod + def load_tokenizer(self): + ... + + @abstractmethod + def forward(self, messages: List[Dict[str, str]], **kwargs) -> str: + ... + + def process_history( self, history: List[Dict[str, str]] ) -> str: + processed_history = '' + + if getattr(self.config, self.arg_prefix).do_prompt_injection: + processed_history += getattr(self.config, self.arg_prefix).system_prompt + + for message in history: + if message['role'] == 'system': + if not getattr(self.config, self.arg_prefix).do_prompt_injection or message != history[0]: + processed_history += self.system_label + message['content'].strip() + ' ' + if message['role'] == 'assistant': + processed_history += self.assistant_label + message['content'].strip() + '' + if message['role'] == 'user': + processed_history += self.user_label + message['content'].strip() + ' ' + return processed_history diff --git a/bittensor/_neuron/base_miner_neuron.py b/bittensor/_neuron/base_miner_neuron.py new file mode 100644 index 0000000000..a2d25862ed --- /dev/null +++ b/bittensor/_neuron/base_miner_neuron.py @@ -0,0 +1,214 @@ +# The MIT License (MIT) +# Copyright © 2023 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import os +import time +import torch +import threading +import argparse +import bittensor + +from rich import print +from typing import Union, Tuple +from datetime import datetime + +class BaseMinerNeuron: + + def priority( self, forward_call: "bittensor.SynapseCall" ) -> float: + return self.prioritizer.priority( forward_call, metagraph = self.metagraph ) + + def blacklist( self, forward_call: "bittensor.SynapseCall" ) -> Union[ Tuple[bool, str], bool ]: + return self.blacklister.blacklist( forward_call, metagraph = self.metagraph ) + + @classmethod + def config( cls ) -> "bittensor.Config": + parser = argparse.ArgumentParser() + cls.add_args( parser ) + return bittensor.config( parser ) + + @classmethod + def help( cls ): + parser = argparse.ArgumentParser() + cls.add_args(parser) + print( cls.__new__.__doc__ ) + parser.print_help() + + @classmethod + def check_config( cls, config: "bittensor.Config" ): + bittensor.axon.check_config( config ) + bittensor.wallet.check_config( config ) + bittensor.logging.check_config( config ) + bittensor.subtensor.check_config( config ) + full_path = os.path.expanduser( + '{}/{}/{}/{}'.format( config.logging.logging_dir, config.wallet.get('name', bittensor.defaults.wallet.name), + config.wallet.get('hotkey', bittensor.defaults.wallet.hotkey), config.neuron.name ) ) + config.neuron.full_path = os.path.expanduser( full_path ) + if not os.path.exists( config.neuron.full_path ): + os.makedirs( config.neuron.full_path ) + + @classmethod + def add_args( cls, parser: argparse.ArgumentParser, prefix: str = None ): + prefix_str = "" if prefix is None else prefix + "." + parser.add_argument( + '--' + prefix_str + 'netuid', + type = int, + help = 'Subnet netuid', + default = 1 + ) + parser.add_argument( + '--' + prefix_str + 'neuron.name', + type = str, + help = 'Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name ', + default = 'openai_prompting_miner' + ) + parser.add_argument( + '--' + prefix_str + 'neuron.blocks_per_epoch', + type = str, + help = 'Blocks until the miner sets weights on chain', + default = 100 + ) + parser.add_argument( + '--' + prefix_str + 'neuron.no_set_weights', + action = 'store_true', + help = 'If True, the model does not set weights.', + default = False + ) + bittensor.wallet.add_args( parser, prefix = prefix ) + bittensor.axon.add_args( parser, prefix = prefix ) + bittensor.subtensor.add_args( parser, prefix = prefix ) + bittensor.logging.add_args( parser, prefix = prefix ) + bittensor.blacklist.add_args( parser, prefix = prefix_str + 'neuron' ) + bittensor.priority.add_args( parser, prefix = prefix_str + 'neuron' ) + + def __init__(self, netuid: int = None, config: "bittensor.Config" = None ): + super_config = config if config != None else BaseMinerNeuron.config() # Grab super (BaseMinerNeuron) config + child_config = self.config() # grab child (Miner) class configs. + self.config = child_config + self.config.merge( super_config ) # Merge the two configs. Child configs override super configs. + self.config.netuid = netuid or self.config.netuid + BaseMinerNeuron.check_config( self.config ) + + # Build objects. + bittensor.logging( config = self.config, logging_dir = self.config.neuron.full_path ) + self.subtensor = bittensor.subtensor( self.config ) + self.wallet = bittensor.wallet( self.config ) + self.metagraph = self.subtensor.metagraph( self.config.netuid ) + self.axon = bittensor.axon( wallet = self.wallet, config = self.config ) + self.blacklister = bittensor.blacklist( config = self.config.neuron ) + self.prioritizer = bittensor.priority( config = self.config.neuron ) + + # Used for backgounr process. + self.is_running = False + self.should_exit = False + self.background_thread = None + + def attach( self, synapse: "bittensor.Synapse" ): + # pass through attach function. + self.axon.attach( synapse ) + + def __enter__(self): + bittensor.logging.trace( 'BaseMinerNeuron.__enter__()' ) + self.start_in_background() + return self + + def __exit__(self, exc_type, exc_value, traceback): + bittensor.logging.trace( 'BaseMinerNeuron.__exit__()' ) + self.stop() + + def start_in_background(self): + if self.is_running: + bittensor.logging.warning( 'The base miner neuron is already running.') + else: + self.should_exit = False + self.background_thread = threading.Thread( target = self.run, daemon = True ) + self.background_thread.start() + self.is_running = True + bittensor.logging.trace( 'Starting the base miner neuron in the background.') + + def stop(self): + if self.is_running: + self.should_exit = True + else: + bittensor.logging.warning( 'The base miner neuron is not running.') + + def run( self ): + bittensor.logging.debug( 'BaseMinerNeuron.run()' ) + + # --- Start the miner. + self.is_running = True + self.wallet.reregister( netuid = self.config.netuid, subtensor = self.subtensor ) + self.axon.start() + self.subtensor.serve_axon( netuid = self.config.netuid, axon = self.axon, wait_for_finalization = False, wait_for_inclusion = False ) #TODO: fix finalization & inclusion + + # --- Run Forever. + last_update = self.subtensor.get_current_block() + retries = 0 + while not self.should_exit: + + # --- Wait until next epoch. + current_block = self.subtensor.get_current_block() + while (current_block - last_update) < self.config.neuron.blocks_per_epoch: + if self.should_exit: continue + time.sleep( 0.1 ) #bittensor.__blocktime__ + current_block = self.subtensor.get_current_block() + last_update = self.subtensor.get_current_block() + + # --- Update the metagraph with the latest network state. + try: + self.metagraph.sync( lite = True ) + uid = self.metagraph.hotkeys.index( self.wallet.hotkey.ss58_address ) + except: + # --- If we fail to sync the metagraph, wait and try again. + if(retries > 8): + bittensor.logging.error( f'Failed to sync metagraph, exiting.') + self.stop() + break + seconds_to_sleep = 5 * 1.5**(retries) + bittensor.logging.error( f'Failed to sync metagraph, retrying in {seconds_to_sleep} seconds.') + time.sleep( seconds_to_sleep ) + retries += 1 + continue + + if(retries > 0): + retries = 0 + + # --- Log performance. + print( + f"[white not bold]{datetime.now():%Y-%m-%d %H:%M:%S}[/white not bold]{' ' * 4} | " + f"{f'UID [bright_cyan]{uid}[/bright_cyan]'.center(16 + len('[bright_cyan][/bright_cyan]'))} | " + f'[dim white not bold] [green]{str(self.metagraph.S[uid].item()):.4}[/green] Stake [/dim white not bold]' + f'[dim white not bold]| [yellow]{str(self.metagraph.trust[uid].item()) :.3}[/yellow] Trust [/dim white not bold]' + f'[dim white not bold]| [green]{str(self.metagraph.incentive[uid].item()):.3}[/green] Incentive [/dim white not bold]') + + # --- Set weights. + if not self.config.neuron.no_set_weights: + try: + # --- query the chain for the most current number of peers on the network + chain_weights = torch.zeros( self.subtensor.subnetwork_n( netuid = self.config.netuid )) + chain_weights[uid] = 1 + did_set = self.subtensor.set_weights( + uids = torch.arange(0, len(chain_weights)), + netuid = self.config.netuid, + weights = chain_weights, + wait_for_inclusion = False, + walle = self.wallet, + version_key = 1 + ) + except: + pass + + self.axon.stop() \ No newline at end of file diff --git a/bittensor/_neuron/base_prompting_miner.py b/bittensor/_neuron/base_prompting_miner.py new file mode 100644 index 0000000000..1bcd155773 --- /dev/null +++ b/bittensor/_neuron/base_prompting_miner.py @@ -0,0 +1,77 @@ +# The MIT License (MIT) +# Copyright © 2023 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import argparse +import bittensor + +from rich import print +from typing import List, Dict, Union, Tuple +from abc import ABC, abstractmethod + +class BasePromptingMiner( bittensor.BaseMinerNeuron, ABC ): + + @classmethod + @abstractmethod + def add_args( cls, parser: argparse.ArgumentParser ): + ... + + @abstractmethod + def forward( self, messages: List[Dict[str, str]] ) -> str: + ... + + @classmethod + @abstractmethod + def check_config( cls, config: 'bittensor.Config' ): + ... + + @classmethod + def config( cls ) -> "bittensor.Config": + parser = argparse.ArgumentParser() + cls.add_super_args( parser ) + return bittensor.config( parser ) + + @classmethod + def add_super_args( cls, parser: argparse.ArgumentParser ): + """ Add arguments specific to BasePromptingMiner to parser. + """ + cls.add_args(parser) + parser.add_argument( + '--neuron.max_batch_size', + type = int, + help = 'The maximum batch size for forward requests.', + default = -1 + ) + parser.add_argument( + '--neuron.max_sequence_len', + type = int, + help = 'The maximum sequence length for forward requests.', + default = -1 + ) + + def __init__( self, config: "bittensor.Config" = None ): + super( BasePromptingMiner, self ).__init__() + + class Synapse( bittensor.TextPromptingSynapse ): + def priority( _, forward_call: "bittensor.TextPromptingForwardCall" ) -> float: + return self.priority( forward_call ) + def blacklist( _, forward_call: "bittensor.TextPromptingForwardCall" ) -> Union[ Tuple[bool, str], bool ]: + return self.blacklist( forward_call ) + def backward( self, messages: List[Dict[str, str]], response: str, rewards: torch.FloatTensor ) -> str: pass + def forward( _, messages: List[Dict[str, str]] ) -> str: + return self.forward( messages ) + self.synapse = Synapse( axon = self.axon ) diff --git a/bittensor/_neuron/base_validator.py b/bittensor/_neuron/base_validator.py new file mode 100644 index 0000000000..1542bb450f --- /dev/null +++ b/bittensor/_neuron/base_validator.py @@ -0,0 +1,167 @@ +# The MIT License (MIT) +# Copyright © 2023 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import os +import time +import torch +import threading +import argparse +import bittensor + +from rich import print +from typing import List, Dict, Union, Tuple, Optional +from datetime import datetime + +class BaseValidator: + + @classmethod + def config( cls ) -> "bittensor.Config": + parser = argparse.ArgumentParser() + cls.add_args( parser ) + return bittensor.config( parser ) + + @classmethod + def help( cls ): + parser = argparse.ArgumentParser() + cls.add_args(parser) + print( cls.__new__.__doc__ ) + parser.print_help() + + @classmethod + def check_config( cls, config: "bittensor.Config" ): + bittensor.wallet.check_config( config ) + bittensor.logging.check_config( config ) + bittensor.subtensor.check_config( config ) + full_path = os.path.expanduser( + '{}/{}/{}/{}'.format( config.logging.logging_dir, config.wallet.get('name', bittensor.defaults.wallet.name), + config.wallet.get('hotkey', bittensor.defaults.wallet.hotkey), config.neuron.name ) ) + config.neuron.full_path = os.path.expanduser( full_path ) + if not os.path.exists( config.neuron.full_path ): + os.makedirs( config.neuron.full_path ) + + @classmethod + def add_args( cls, parser: argparse.ArgumentParser, prefix: str = None ): + prefix_str = "" if prefix is None else prefix + "." + parser.add_argument( + '--' + prefix_str + 'netuid', + type = int, + help = 'Subnet netuid', + default = 1 + ) + parser.add_argument( + '--' + prefix_str + 'neuron.name', + type = str, + help = 'Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name ', + default = 'openai_prompting_miner' + ) + parser.add_argument( + '--' + prefix_str + 'neuron.blocks_per_epoch', + type = str, + help = 'Blocks until the miner sets weights on chain', + default = 100 + ) + parser.add_argument( + '--' + prefix_str + 'neuron.no_set_weights', + action = 'store_true', + help = 'If True, the model does not set weights.', + default = False + ) + bittensor.wallet.add_args( parser, prefix = prefix ) + bittensor.subtensor.add_args( parser, prefix = prefix ) + bittensor.logging.add_args( parser, prefix = prefix ) + + def __init__(self, netuid: int = None, config: "bittensor.Config" = None ): + # Build config. + self.config = config if config != None else BaseValidator.config() + self.config.netuid = netuid or self.config.netuid + BaseValidator.check_config( self.config ) + + # Build objects. + bittensor.logging( config = self.config, logging_dir = self.config.neuron.full_path ) + self.subtensor = bittensor.subtensor( self.config ) + self.wallet = bittensor.wallet( self.config ) + self.metagraph = self.subtensor.metagraph( self.config.netuid ) + + # Used for backgounr process. + self.is_running = False + self.should_exit = False + self.background_thread = None + + def __enter__(self): + bittensor.logging.trace( 'BaseValidator.__enter__()' ) + self.start_in_background() + return self + + def __exit__(self, exc_type, exc_value, traceback): + bittensor.logging.trace( 'BaseValidator.__exit__()' ) + self.stop() + + def start_in_background(self): + if self.is_running: + bittensor.logging.warning( 'The base miner neuron is already running.') + else: + self.should_exit = False + self.background_thread = threading.Thread( target = self.run, daemon = True ) + self.background_thread.start() + self.is_running = True + bittensor.logging.trace( 'Starting the base miner neuron in the background.') + + def stop(self): + if self.is_running: + self.should_exit = True + else: + bittensor.logging.warning( 'The base miner neuron is not running.') + + def run( self ): + bittensor.logging.debug( 'BaseMinBaseValidatorerNeuron.run()' ) + + # --- Start the miner. + self.is_running = True + self.wallet.reregister( netuid = self.config.netuid, subtensor = self.subtensor ) + + # --- Run Forever. + last_update = self.subtensor.get_current_block() + while not self.should_exit: + + # --- Wait until next epoch. + current_block = self.subtensor.get_current_block() + while (current_block - last_update) < self.config.neuron.blocks_per_epoch: + if self.should_exit: continue + time.sleep( 12 ) + current_block = self.subtensor.get_current_block() + last_update = self.subtensor.get_current_block() + + # --- Update the metagraph with the latest network state. + self.metagraph.sync( lite = True ) + uid = self.metagraph.hotkeys.index( self.wallet.hotkey.ss58_address ) + + # --- Set weights. + if not self.config.neuron.no_set_weights: + try: + # --- query the chain for the most current number of peers on the network + chain_weights = torch.zeros( self.subtensor.subnetwork_n( netuid = self.config.netuid )) + chain_weights[uid] = 1 + did_set = self.subtensor.set_weights( + uids = torch.arange(0, len(chain_weights)), + netuid = self.config.netuid, + weights = chain_weights, + wait_for_inclusion = False, + walle = self.wallet, + version_key = 1 + ) + except: + pass \ No newline at end of file diff --git a/bittensor/_priority/__init__.py b/bittensor/_priority/__init__.py new file mode 100644 index 0000000000..cd30cc5cd4 --- /dev/null +++ b/bittensor/_priority/__init__.py @@ -0,0 +1,87 @@ +# The MIT License (MIT) +# Copyright © 2021 Yuma Rao +# Copyright © 2022 Opentensor Foundation + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +import math +import argparse +import bittensor + +class priority: + + def __init__( self, config: "bittensor.Config" = None ): + self.config = config or priority.config() + + @classmethod + def config( cls ) -> "bittensor.Config": + parser = argparse.ArgumentParser() + priority.add_args(parser) + return bittensor.config( parser ) + + @classmethod + def help(cls): + parser = argparse.ArgumentParser() + cls.add_args(parser) + print( cls.__new__.__doc__ ) + parser.print_help() + + @classmethod + def add_args( cls, parser: argparse.ArgumentParser, prefix: str = None ): + prefix_str = "" if prefix is None else prefix + "." + parser.add_argument( + '--' + prefix_str + 'priority.default_priority', + type = float, + help = 'Default call priority in queue.', + default = 0.0 + ) + parser.add_argument( + '--' + prefix_str + 'priority.blacklisted_keys', + type = str, + required = False, + nargs = '*', + action = 'store', + help = 'List of ss58 addresses which are always given -math.inf priority', default=[] + ) + parser.add_argument( + '--' + prefix_str + 'priority.whitelisted_keys', + type = str, + required = False, + nargs = '*', + action = 'store', + help = 'List of ss58 addresses which are always given math.inf priority', default=[] + ) + + def priority( + self, + forward_call: "bittensor.SynapseCall", + metagraph: "bittensor.Metagraph" = None, + ) -> float: + + # Check for blacklisted keys which take priority over all other checks. + src_hotkey = forward_call.src_hotkey + if src_hotkey in self.config.priority.blacklisted_keys: + return -math.inf + + # Check for whitelisted keys which take priority over all remaining checks. + if src_hotkey in self.config.priority.whitelisted_keys: + return math.inf + + # Otherwise priority of requests is based on stake. + if metagraph is not None: + uid = metagraph.hotkeys.index( forward_call.src_hotkey ) + return metagraph.S[ uid ].item() + + # Default priority. + return self.config.priority.default_priority diff --git a/bittensor/_prometheus/__init__.py b/bittensor/_prometheus/__init__.py index b8ccea8a7d..9d22c7a573 100644 --- a/bittensor/_prometheus/__init__.py +++ b/bittensor/_prometheus/__init__.py @@ -149,6 +149,10 @@ def add_args(cls, parser: argparse.ArgumentParser, prefix: str = None ): """ Accept specific arguments from parser """ prefix_str = '' if prefix == None else prefix + '.' + if prefix is not None: + if not hasattr(bittensor.defaults, prefix): + setattr(bittensor.defaults, prefix, bittensor.Config()) + getattr(bittensor.defaults, prefix).prometheus = bittensor.defaults.prometheus try: parser.add_argument('--' + prefix_str + 'prometheus.port', type=int, required=False, default = bittensor.defaults.prometheus.port, help='''Prometheus serving port.''') diff --git a/bittensor/_subtensor/__init__.py b/bittensor/_subtensor/__init__.py index 374a1216aa..1020d85b11 100644 --- a/bittensor/_subtensor/__init__.py +++ b/bittensor/_subtensor/__init__.py @@ -141,8 +141,12 @@ def help(cls): @classmethod def add_args(cls, parser: argparse.ArgumentParser, prefix: str = None ): prefix_str = '' if prefix == None else prefix + '.' + if prefix is not None: + if not hasattr(bittensor.defaults, prefix): + setattr(bittensor.defaults, prefix, bittensor.Config()) + getattr(bittensor.defaults, prefix).subtensor = bittensor.defaults.subtensor try: - parser.add_argument('--' + prefix_str + 'subtensor.network', default = bittensor.defaults.subtensor.network, type=str, + parser.add_argument('--' + prefix_str + 'subtensor.network', default = argparse.SUPPRESS, type=str, help='''The subtensor network flag. The likely choices are: -- finney (main network) -- local (local running network) diff --git a/bittensor/_subtensor/subtensor_impl.py b/bittensor/_subtensor/subtensor_impl.py index 10df88a7a6..bd4cc1a506 100644 --- a/bittensor/_subtensor/subtensor_impl.py +++ b/bittensor/_subtensor/subtensor_impl.py @@ -945,25 +945,23 @@ def make_substrate_call_with_retry(): return NeuronInfoLite.list_from_vec_u8( result ) - def metagraph( self, netuid: int, lite: bool = True ) -> 'bittensor.Metagraph': + def metagraph( self, netuid: int, lite: bool = True, block: Optional[int] = None ) -> 'bittensor.Metagraph': r""" Returns the metagraph for the subnet. Args: netuid ( int ): The network uid of the subnet to query. lite (bool, default=True): If true, returns a metagraph using the lite sync (no weights, no bonds) + block ( Optional[int] ): + block to sync from, or None for latest block. Returns: metagraph ( `bittensor.Metagraph` ): The metagraph for the subnet at the block. - """ - return bittensor.metagraph( network = self.network, netuid = netuid, lite = lite ) - - ################ - #### Transfer ## - ################ - - + """ + metagraph_ = bittensor.metagraph( network = self.network, netuid = netuid, lite = lite, sync = False ) + metagraph_.sync( block = block, lite = lite, subtensor = self) + return metagraph_ ################ #### Legacy #### diff --git a/bittensor/_synapse/text_prompting/miner.py b/bittensor/_synapse/text_prompting/miner.py deleted file mode 100644 index 84e8b10a0a..0000000000 --- a/bittensor/_synapse/text_prompting/miner.py +++ /dev/null @@ -1,253 +0,0 @@ -# The MIT License (MIT) -# Copyright © 2021 Yuma Rao - -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -# documentation files (the “Software”), to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, -# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of -# the Software. - -# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - -import os -import time -import copy -import torch -import argparse -import bittensor - -from rich import print -from typing import List, Dict, Union, Tuple, Optional -from datetime import datetime -from abc import ABC, abstractmethod - -class BasePromptingMiner( ABC ): - - @classmethod - @abstractmethod - def add_args( cls, parser: argparse.ArgumentParser ): - ... - - def priority( self, forward_call: "bittensor.TextPromptingForwardCall" ) -> float: - if self.metagraph is not None: - uid = self.metagraph.hotkeys.index(forward_call.src_hotkey) - return self.metagraph.S[uid].item() - else: - return self.config.neuron.default_priority - - def blacklist( self, forward_call: "bittensor.TextPromptingForwardCall" ) -> Union[ Tuple[bool, str], bool ]: - # Check for registration - def registration_check(): - is_registered = forward_call.src_hotkey in self.metagraph.hotkeys - if not is_registered: - if self.config.neuron.blacklist.allow_non_registered: return False, 'passed blacklist' - else: return True, 'pubkey not registered' - - # Blacklist based on stake. - def stake_check() -> bool: - default_stake = self.config.neuron.blacklist.default_stake - if default_stake <= 0.0: - return False, 'passed blacklist' - uid = self.metagraph.hotkeys.index(forward_call.src_hotkey) - if self.metagraph.S[uid].item() < default_stake: - bittensor.logging.debug( "Blacklisted. Stake too low.") - return True, 'Stake too low.' - else: return False, 'passed blacklist' - - # Optionally blacklist based on checks. - try: - registration_check() - stake_check() - return False, 'passed blacklist' - except Exception as e: - bittensor.logging.warning( "Blacklisted. Error in `registration_check` or `stake_check()" ) - return True, 'Error in `registration_check` or `stake_check()' - - @abstractmethod - def forward( self, messages: List[Dict[str, str]] ) -> str: - ... - - @classmethod - @abstractmethod - def check_config( cls, config: 'bittensor.Config' ): - ... - - @classmethod - def config( cls ) -> "bittensor.Config": - parser = argparse.ArgumentParser() - cls.add_super_args( parser ) - return bittensor.config( parser ) - - @classmethod - def help( cls ): - parser = argparse.ArgumentParser() - cls.add_super_args( parser ) - cls.add_args(parser) - print( cls.__new__.__doc__ ) - parser.print_help() - - @classmethod - def super_check_config( cls, config: "bittensor.Config" ): - cls.check_config( config ) - bittensor.axon.check_config( config ) - bittensor.wallet.check_config( config ) - bittensor.logging.check_config( config ) - bittensor.subtensor.check_config( config ) - full_path = os.path.expanduser( - '{}/{}/{}/{}'.format( config.logging.logging_dir, config.wallet.get('name', bittensor.defaults.wallet.name), - config.wallet.get('hotkey', bittensor.defaults.wallet.hotkey), config.neuron.name ) ) - config.neuron.full_path = os.path.expanduser( full_path ) - if not os.path.exists( config.neuron.full_path ): - os.makedirs( config.neuron.full_path ) - - @classmethod - def add_super_args( cls, parser: argparse.ArgumentParser ): - cls.add_args(parser) - parser.add_argument( - '--netuid', - type = int, - help = 'Subnet netuid', - default = 41 - ) - parser.add_argument( - '--neuron.name', - type = str, - help = 'Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name ', - default = 'openai_prompting_miner' - ) - parser.add_argument( - '--neuron.blocks_per_epoch', - type = str, - help = 'Blocks until the miner sets weights on chain', - default = 100 - ) - parser.add_argument( - '--neuron.no_set_weights', - action = 'store_true', - help = 'If True, the model does not set weights.', - default = False - ) - parser.add_argument( - '--neuron.max_batch_size', - type = int, - help = 'The maximum batch size for forward requests.', - default = -1 - ) - parser.add_argument( - '--neuron.max_sequence_len', - type = int, - help = 'The maximum sequence length for forward requests.', - default = -1 - ) - parser.add_argument( - '--neuron.blacklist.hotkeys', - type = str, - required = False, - nargs = '*', - action = 'store', - help = 'To blacklist certain hotkeys', default=[] - ) - parser.add_argument( - '--neuron.blacklist.allow_non_registered', - action = 'store_true', - help = 'If True, the miner will allow non-registered hotkeys to mine.', - default = True - ) - parser.add_argument( - '--neuron.blacklist.default_stake', - type = float, - help = 'Set default stake for miners.', - default = 0.0 - ) - parser.add_argument( - '--neuron.default_priority', - type = float, - help = 'Set default priority for miners.', - default = 0.0 - ) - bittensor.wallet.add_args( parser ) - bittensor.axon.add_args( parser ) - bittensor.subtensor.add_args( parser ) - bittensor.logging.add_args( parser ) - - def __init__( - self, - config: "bittensor.Config" = None - ): - config = config if config != None else self.config() - self.config = copy.deepcopy( config ) - self.super_check_config( self.config ) - self.config.to_defaults() - bittensor.logging( config = self.config, logging_dir = self.config.neuron.full_path ) - self.subtensor = bittensor.subtensor( self.config ) - self.wallet = bittensor.wallet( self.config ) - self.metagraph = self.subtensor.metagraph( self.config.netuid ) - self.axon = bittensor.axon( - wallet = self.wallet, - metagraph = self.metagraph, - config = self.config, - ) - class Synapse( bittensor.TextPromptingSynapse ): - def priority( _, forward_call: "bittensor.TextPromptingForwardCall" ) -> float: - return self.priority( forward_call ) - def blacklist( _, forward_call: "bittensor.TextPromptingForwardCall" ) -> Union[ Tuple[bool, str], bool ]: - return self.blacklist( forward_call ) - def backward( self, messages: List[Dict[str, str]], response: str, rewards: torch.FloatTensor ) -> str: pass - def forward( _, messages: List[Dict[str, str]] ) -> str: - return self.forward( messages ) - self.synapse = Synapse( axon = self.axon ) - - def run( self ): - - # --- Start the miner. - self.wallet.reregister( netuid = self.config.netuid, subtensor = self.subtensor ) - self.axon.start() - self.axon.netuid = self.config.netuid - self.axon.protocol = 4 - self.subtensor.serve_axon( netuid = self.config.netuid, axon = self.axon ) - - # --- Run Forever. - last_update = self.subtensor.get_current_block() - while True: - - # --- Wait until next epoch. - current_block = self.subtensor.get_current_block() - while (current_block - last_update) < self.config.neuron.blocks_per_epoch: - time.sleep( 0.1 ) #bittensor.__blocktime__ - current_block = self.subtensor.get_current_block() - last_update = self.subtensor.get_current_block() - - # --- Update the metagraph with the latest network state. - self.metagraph.sync( lite = True ) - uid = self.metagraph.hotkeys.index( self.wallet.hotkey.ss58_address ) - - # --- Log performance. - print( - f"[white not bold]{datetime.now():%Y-%m-%d %H:%M:%S}[/white not bold]{' ' * 4} | " - f"{f'UID [bright_cyan]{uid}[/bright_cyan]'.center(16 + len('[bright_cyan][/bright_cyan]'))} | " - f'[dim white not bold] [green]{str(self.metagraph.S[uid].item()):.4}[/green] Stake [/dim white not bold]' - f'[dim white not bold]| [yellow]{str(self.metagraph.trust[uid].item()) :.3}[/yellow] Trust [/dim white not bold]' - f'[dim white not bold]| [green]{str(self.metagraph.incentive[uid].item()):.3}[/green] Incentive [/dim white not bold]') - - # --- Set weights. - if not self.config.neuron.no_set_weights: - try: - # --- query the chain for the most current number of peers on the network - chain_weights = torch.zeros( self.subtensor.subnetwork_n( netuid = self.config.netuid )) - chain_weights[uid] = 1 - did_set = self.subtensor.set_weights( - uids=torch.arange(0, len(chain_weights)), - netuid=self.config.netuid, - weights=chain_weights, - wait_for_inclusion=False, - wallet=self.wallet, - version_key=1 - ) - except: - pass \ No newline at end of file diff --git a/bittensor/_synapse/text_prompting/synapse.py b/bittensor/_synapse/text_prompting/synapse.py index 8920123a44..e2f544ac5f 100644 --- a/bittensor/_synapse/text_prompting/synapse.py +++ b/bittensor/_synapse/text_prompting/synapse.py @@ -31,7 +31,7 @@ class SynapseForwardMulti( bittensor.SynapseCall ): def __init__( self, - synapse: "TextPromptingSynapseMulti", + synapse: "bittensor.TextPromptingSynapseMulti", request_proto: bittensor.proto.MultiForwardTextPromptingRequest, multi_forward_callback: Callable, ): diff --git a/bittensor/_threadpool/__init__.py b/bittensor/_threadpool/__init__.py index c641b1bc29..ac76d4812d 100644 --- a/bittensor/_threadpool/__init__.py +++ b/bittensor/_threadpool/__init__.py @@ -55,6 +55,10 @@ def add_args(cls, parser: argparse.ArgumentParser, prefix: str = None ): """ Accept specific arguments from parser """ prefix_str = '' if prefix == None else prefix + '.' + if prefix is not None: + if not hasattr(bittensor.defaults, prefix): + setattr(bittensor.defaults, prefix, bittensor.Config()) + getattr(bittensor.defaults, prefix).priority = bittensor.defaults.priority try: parser.add_argument('--' + prefix_str + 'priority.max_workers', type = int, help='''maximum number of threads in thread pool''', default = bittensor.defaults.priority.max_workers) parser.add_argument('--' + prefix_str + 'priority.maxsize', type=int, help='''maximum size of tasks in priority queue''', default = bittensor.defaults.priority.maxsize) diff --git a/bittensor/_wallet/__init__.py b/bittensor/_wallet/__init__.py index 821260e506..3bb036de3a 100644 --- a/bittensor/_wallet/__init__.py +++ b/bittensor/_wallet/__init__.py @@ -107,9 +107,13 @@ def add_args(cls, parser: argparse.ArgumentParser, prefix: str = None ): """ Accept specific arguments from parser """ prefix_str = '' if prefix == None else prefix + '.' + if prefix is not None: + if not hasattr(bittensor.defaults, prefix): + setattr(bittensor.defaults, prefix, bittensor.Config()) + getattr(bittensor.defaults, prefix).wallet = bittensor.defaults.wallet try: - parser.add_argument('--' + prefix_str + 'wallet.name', required=False, default=bittensor.defaults.wallet.name, help='''The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet)''') - parser.add_argument('--' + prefix_str + 'wallet.hotkey', required=False, default=bittensor.defaults.wallet.hotkey, help='''The name of wallet's hotkey.''') + parser.add_argument('--' + prefix_str + 'wallet.name', required=False, default=argparse.SUPPRESS, help='''The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet)''') + parser.add_argument('--' + prefix_str + 'wallet.hotkey', required=False, default=argparse.SUPPRESS, help='''The name of wallet's hotkey.''') parser.add_argument('--' + prefix_str + 'wallet.path', required=False, default=bittensor.defaults.wallet.path, help='''The path to your bittensor wallets''') parser.add_argument('--' + prefix_str + 'wallet._mock', action='store_true', default=bittensor.defaults.wallet._mock, help='To turn on wallet mocking for testing purposes.') diff --git a/examples/text_prompting.py b/examples/text_prompting.py index f56873a442..9329593804 100644 --- a/examples/text_prompting.py +++ b/examples/text_prompting.py @@ -1,5 +1,5 @@ # The MIT License (MIT) -# Copyright © 2021 Yuma Rao +# Copyright © 2023 Yuma Rao # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated # documentation files (the “Software”), to deal in the Software without restriction, including without limitation @@ -15,7 +15,6 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. -import json import torch import bittensor from typing import List, Dict, Union, Tuple @@ -40,22 +39,21 @@ def multi_forward(self, messages: List[Dict[str, str]]) -> List[ str ]: # Create a mock wallet. wallet = bittensor.wallet().create_if_non_existent() -axon = bittensor.axon( wallet = wallet, port = 9090, ip = "127.0.0.1", metagraph = None ) -dendrite = bittensor.text_prompting( axon = axon.info(), keypair = wallet.hotkey ) +axon = bittensor.axon( wallet = wallet, port = 9090, external_ip = "127.0.0.1" ) + +dendrite = bittensor.text_prompting( axon = axon, keypair = wallet.hotkey ) synapse = Synapse( axon = axon ) axon.start() -# bittensor.logging.debug( "Start example") -# forward_call = dendrite.forward( -# roles = ['system', 'assistant'], -# messages = ['you are chat bot', 'what is the whether'], -# timeout = 1e6 -# ) -# print ( forward_call ) -# print ( 'success', forward_call.is_success, 'failed', forward_call.did_fail, 'timedout', forward_call.did_timeout ) -# backward_call = forward_call.backward( 1 ) -# print ( backward_call ) -# print ( 'success', backward_call.is_success, 'failed', backward_call.did_fail, 'timedout', backward_call.did_timeout ) + +forward_call = dendrite.forward( + roles = ['system', 'assistant'], + messages = ['you are chat bot', 'what is the whether'], + timeout = 1e6 +) +print ( forward_call ) +print ( 'success', forward_call.is_success, 'failed', forward_call.did_fail, 'timedout', forward_call.did_timeout ) +print ( 'completion', forward_call.completion ) multi_forward_call = dendrite.multi_forward( diff --git a/bittensor/_neuron/text/core_validator/__init__.py b/filtered_text_history.txt similarity index 100% rename from bittensor/_neuron/text/core_validator/__init__.py rename to filtered_text_history.txt diff --git a/neurons/text/prompting/miners/huggingface/__init__.py b/neurons/text/prompting/miners/huggingface/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/neurons/text/prompting/miners/huggingface/chat_glm/README.md b/neurons/text/prompting/miners/huggingface/chat_glm/README.md new file mode 100644 index 0000000000..7d22d11885 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/chat_glm/README.md @@ -0,0 +1,104 @@ +## ChatGLM Miner + THUDM/chatglm-6b Language Model Serving with BitTensor + This code is for running a language model powered by ChatGLM through the BitTensor framework. + + # Example Usage + ``` + python3 -m pip install -r neurons/text/prompting/miners/huggingface/chat_glm/requirements.txt + python3 neurons/text/prompting/miners/huggingface/chat_glm/neuron.py + ``` + + # Full Usage + ``` + usage: neuron.py [-h] [--chat_glm.device CHAT_GLM.DEVICE] [--chat_glm.max_new_tokens CHAT_GLM.MAX_NEW_TOKENS] [--chat_glm.temperature CHAT_GLM.TEMPERATURE] [--chat_glm.do_sample] + [--netuid NETUID] [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] [--neuron.no_set_weights] + [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS ...]] + [--wallet.name WALLET.NAME] [--wallet.hotkey WALLET.HOTKEY] [--wallet.path WALLET.PATH] [--wallet._mock] [--wallet.reregister WALLET.REREGISTER] + [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] [--axon.port AXON.PORT] [--axon.ip AXON.IP] + [--axon.external_port AXON.EXTERNAL_PORT] [--axon.external_ip AXON.EXTERNAL_IP] [--axon.max_workers AXON.MAX_WORKERS] + [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] [--subtensor.network SUBTENSOR.NETWORK] [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] + [--subtensor._mock] [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] + [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] [--subtensor.register.no_output_in_place] [--subtensor.register.verbose] + [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] + [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] + [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] [--logging.debug] [--logging.trace] [--logging.record_log] + [--logging.logging_dir LOGGING.LOGGING_DIR] [--metagraph._mock] [--config CONFIG] [--strict] + + optional arguments: + -h, --help show this help message and exit + --chat_glm.device CHAT_GLM.DEVICE + Device to load model + --chat_glm.max_new_tokens CHAT_GLM.MAX_NEW_TOKENS + Max tokens for model output. + --chat_glm.temperature CHAT_GLM.TEMPERATURE + Sampling temperature of model + --chat_glm.do_sample Whether to use sampling or not (if not, uses greedy decoding). + --netuid NETUID Subnet netuid + --neuron.name NEURON.NAME + Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name + --neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH + Blocks until the miner sets weights on chain + --neuron.no_set_weights + If True, the model does not set weights. + --neuron.max_batch_size NEURON.MAX_BATCH_SIZE + The maximum batch size for forward requests. + --neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN + The maximum sequence length for forward requests. + --neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS ...] + To blacklist certain hotkeys + --wallet.name WALLET.NAME + The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet) + --wallet.hotkey WALLET.HOTKEY + The name of wallet's hotkey. + --wallet.path WALLET.PATH + The path to your bittensor wallets + --wallet._mock To turn on wallet mocking for testing purposes. + --wallet.reregister WALLET.REREGISTER + Whether to reregister the wallet if it is not already registered. + --axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS + maximum number of threads in thread pool + --axon.priority.maxsize AXON.PRIORITY.MAXSIZE + maximum size of tasks in priority queue + --axon.port AXON.PORT + The local port this axon endpoint is bound to. i.e. 8091 + --axon.ip AXON.IP The local ip this axon binds to. ie. [::] + --axon.external_port AXON.EXTERNAL_PORT + The public port this axon broadcasts to the network. i.e. 8091 + --axon.external_ip AXON.EXTERNAL_IP + The external ip this axon broadcasts to the network to. ie. [::] + --axon.max_workers AXON.MAX_WORKERS + The maximum number connection handler threads working simultaneously on this endpoint. The grpc server distributes new worker threads to service requests + up to this number. + --axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS + Maximum number of allowed active connections + --subtensor.network SUBTENSOR.NETWORK + The subtensor network flag. The likely choices are: -- finney (main network) -- local (local running network) -- mock (creates a mock connection (for + testing)) If this option is set it overloads subtensor.chain_endpoint with an entry point node from that network. + --subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT + The subtensor endpoint flag. If set, overrides the --network flag. + --subtensor._mock To turn on subtensor mocking for testing purposes. + --subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES, -n SUBTENSOR.REGISTER.NUM_PROCESSES + Number of processors to use for registration + --subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --subtensor.register.cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, -u SUBTENSOR.REGISTER.UPDATE_INTERVAL + The number of nonces to process before checking for next block during registration + --subtensor.register.no_output_in_place, --no_output_in_place + Whether to not ouput the registration statistics in-place. Set flag to disable output in-place. + --subtensor.register.verbose + Whether to ouput the registration statistics verbosely. + --subtensor.register.cuda.use_cuda, --cuda, --cuda.use_cuda + Set flag to use CUDA to register. + --subtensor.register.cuda.no_cuda, --no_cuda, --cuda.no_cuda + Set flag to not use CUDA for registration + --subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...], --cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...] + Set the CUDA device id(s). Goes by the order of speed. (i.e. 0 is the fastest). + --subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB, --cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB + Set the number of Threads Per Block for CUDA. + --logging.debug Turn on bittensor debugging information + --logging.trace Turn on bittensor trace level information + --logging.record_log Turns on logging to file. + --logging.logging_dir LOGGING.LOGGING_DIR + Logging default root directory. + --metagraph._mock To turn on metagraph mocking for testing purposes. + --config CONFIG If set, defaults are overridden by passed file. + --strict If flagged, config will check that only exact arguemnts have been set. + ``` \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/chat_glm/neuron.py b/neurons/text/prompting/miners/huggingface/chat_glm/neuron.py new file mode 100644 index 0000000000..23136e752d --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/chat_glm/neuron.py @@ -0,0 +1,59 @@ +# The MIT License (MIT) +# Copyright © 2021 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import argparse +import bittensor +from typing import List, Dict +from transformers import AutoTokenizer, AutoModel + +class ChatGLMMiner( bittensor.HuggingFaceMiner ): + + arg_prefix: str = 'chat_glm' + assistant_label: str = '' + user_label: str = '' + system_label: str = '' + + def load_tokenizer( self ): + return AutoTokenizer.from_pretrained( "THUDM/chatglm-6b", trust_remote_code=True) + + def load_model( self ): + return AutoModel.from_pretrained( "THUDM/chatglm-6b",trust_remote_code=True, torch_dtype = torch.float16 ) + + def forward(self, messages: List[Dict[str, str]]) -> str: + history = self.process_history( messages ) + prompt = history[-1][-1] + if len(history) == 1: + history = [] + generation, history = self.model.chat( + self.tokenizer, + prompt, + history, + max_length=self.config.chat_glm.max_new_tokens, + temperature=self.config.chat_glm.temperature, + do_sample=self.config.chat_glm.do_sample, + pad_token_id=self.tokenizer.eos_token_id, + ) + + bittensor.logging.debug("Message: " + str( messages ).replace( "<","-" ).replace( ">","-" ) ) + bittensor.logging.debug("Generation: " + str( generation ).replace( "<","-" ).replace( ">","-" ) ) + return generation + + +if __name__ == "__main__": + bittensor.utils.version_checking() + ChatGLMMiner().run() diff --git a/neurons/text/prompting/miners/huggingface/chat_glm/requirements.txt b/neurons/text/prompting/miners/huggingface/chat_glm/requirements.txt new file mode 100644 index 0000000000..bb07cd001d --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/chat_glm/requirements.txt @@ -0,0 +1,4 @@ +protobuf==3.20.0 +transformers==4.27.1 +icetk +cpm_kernels \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/dolly/README.md b/neurons/text/prompting/miners/huggingface/dolly/README.md new file mode 100644 index 0000000000..724506535b --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/dolly/README.md @@ -0,0 +1,114 @@ + +## Databricks Dolly 3B/12B Miner +Dolyl 3B and 12B completion miner for bittensor's prompting network. + +# Example Usage +``` +python3 neurons/text/prompting/miners/huggingface/dolly/neuron.py --dolly.model_name databricks/dolly-v2-12b +``` + +# Full Usage +``` +usage: neuron.py [-h] [--dolly.model_name DOLLY.MODEL_NAME] [--dolly.device DOLLY.DEVICE] [--dolly.max_new_tokens DOLLY.MAX_NEW_TOKENS] [--dolly.temperature DOLLY.TEMPERATURE] + [--dolly.do_sample] [--dolly.do_prompt_injection] [--dolly.system_prompt DOLLY.SYSTEM_PROMPT] [--netuid NETUID] [--neuron.name NEURON.NAME] + [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] [--neuron.no_set_weights] [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] + [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]]] + [--neuron.blacklist.allow_non_registered] [--neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE] [--neuron.default_priority NEURON.DEFAULT_PRIORITY] + [--wallet.name WALLET.NAME] [--wallet.hotkey WALLET.HOTKEY] [--wallet.path WALLET.PATH] [--wallet._mock] [--wallet.reregister WALLET.REREGISTER] + [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] [--axon.port AXON.PORT] [--axon.ip AXON.IP] + [--axon.external_port AXON.EXTERNAL_PORT] [--axon.external_ip AXON.EXTERNAL_IP] [--axon.max_workers AXON.MAX_WORKERS] + [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] [--subtensor.network SUBTENSOR.NETWORK] [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] + [--subtensor._mock] [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] + [--subtensor.register.no_output_in_place] [--subtensor.register.verbose] [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] + [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] + [--logging.debug] [--logging.trace] [--logging.record_log] [--logging.logging_dir LOGGING.LOGGING_DIR] [--config CONFIG] [--strict] + +optional arguments: + -h, --help show this help message and exit + --dolly.model_name DOLLY.MODEL_NAME + Name/path of model to load + --dolly.device DOLLY.DEVICE + Device to load model + --dolly.max_new_tokens DOLLY.MAX_NEW_TOKENS + Max tokens for model output. + --dolly.temperature DOLLY.TEMPERATURE + Sampling temperature of model + --dolly.do_sample Whether to use sampling or not (if not, uses greedy decoding). + --dolly.do_prompt_injection + Whether to use a custom "system" prompt instead of the one sent by bittensor. + --dolly.system_prompt DOLLY.SYSTEM_PROMPT + What prompt to replace the system prompt with + --netuid NETUID Subnet netuid + --neuron.name NEURON.NAME + Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name + --neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH + Blocks until the miner sets weights on chain + --neuron.no_set_weights + If True, the model does not set weights. + --neuron.max_batch_size NEURON.MAX_BATCH_SIZE + The maximum batch size for forward requests. + --neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN + The maximum sequence length for forward requests. + --neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]] + To blacklist certain hotkeys + --neuron.blacklist.allow_non_registered + If True, the miner will allow non-registered hotkeys to mine. + --neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE + Set default stake for miners. + --neuron.default_priority NEURON.DEFAULT_PRIORITY + Set default priority for miners. + --wallet.name WALLET.NAME + The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet) + --wallet.hotkey WALLET.HOTKEY + The name of wallet's hotkey. + --wallet.path WALLET.PATH + The path to your bittensor wallets + --wallet._mock To turn on wallet mocking for testing purposes. + --wallet.reregister WALLET.REREGISTER + Whether to reregister the wallet if it is not already registered. + --axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS + maximum number of threads in thread pool + --axon.priority.maxsize AXON.PRIORITY.MAXSIZE + maximum size of tasks in priority queue + --axon.port AXON.PORT + The local port this axon endpoint is bound to. i.e. 8091 + --axon.ip AXON.IP The local ip this axon binds to. ie. [::] + --axon.external_port AXON.EXTERNAL_PORT + The public port this axon broadcasts to the network. i.e. 8091 + --axon.external_ip AXON.EXTERNAL_IP + The external ip this axon broadcasts to the network to. ie. [::] + --axon.max_workers AXON.MAX_WORKERS + The maximum number connection handler threads working simultaneously on this endpoint. The grpc server distributes new worker threads to service requests up to + this number. + --axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS + Maximum number of allowed active connections + --subtensor.network SUBTENSOR.NETWORK + The subtensor network flag. The likely choices are: -- finney (main network) -- local (local running network) -- mock (creates a mock connection (for testing)) + If this option is set it overloads subtensor.chain_endpoint with an entry point node from that network. + --subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT + The subtensor endpoint flag. If set, overrides the --network flag. + --subtensor._mock To turn on subtensor mocking for testing purposes. + --subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES, -n SUBTENSOR.REGISTER.NUM_PROCESSES + Number of processors to use for registration + --subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --subtensor.register.cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, -u SUBTENSOR.REGISTER.UPDATE_INTERVAL + The number of nonces to process before checking for next block during registration + --subtensor.register.no_output_in_place, --no_output_in_place + Whether to not ouput the registration statistics in-place. Set flag to disable output in-place. + --subtensor.register.verbose + Whether to ouput the registration statistics verbosely. + --subtensor.register.cuda.use_cuda, --cuda, --cuda.use_cuda + Set flag to use CUDA to register. + --subtensor.register.cuda.no_cuda, --no_cuda, --cuda.no_cuda + Set flag to not use CUDA for registration + --subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...], --cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...] + Set the CUDA device id(s). Goes by the order of speed. (i.e. 0 is the fastest). + --subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB, --cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB + Set the number of Threads Per Block for CUDA. + --logging.debug Turn on bittensor debugging information + --logging.trace Turn on bittensor trace level information + --logging.record_log Turns on logging to file. + --logging.logging_dir LOGGING.LOGGING_DIR + Logging default root directory. + --config CONFIG If set, defaults are overridden by passed file. + --strict If flagged, config will check that only exact arguemnts have been set. + ``` diff --git a/neurons/text/prompting/miners/huggingface/dolly/neuron.py b/neurons/text/prompting/miners/huggingface/dolly/neuron.py new file mode 100644 index 0000000000..52797011d6 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/dolly/neuron.py @@ -0,0 +1,53 @@ +# The MIT License (MIT) +# Copyright © 2023 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import bittensor +from typing import List, Dict +from transformers import pipeline + + +class Dolly12BMiner( bittensor.HuggingFaceMiner ): + + arg_prefix: str = "dolly" + assistant_label: str = "### Response:" + user_label: str = "### Instruction:" + system_label: str = "" + + def load_model( self ): + bittensor.logging.info( 'Loading ' + str( self.config.dolly.model_name ) ) + model = pipeline( model=self.config.dolly.model_name, torch_dtype=torch.bfloat16, trust_remote_code=True, device=0 ) + bittensor.logging.info( 'Model loaded!' ) + return model + + def load_tokenizer( self ): + pass + + def forward(self, messages: List[Dict[str, str]]) -> str: + + history = self.process_history( messages ) + prompt = history + self.assistant_label + generation = self.model( prompt ) + + bittensor.logging.debug(" Message: " + str( messages ) ) + bittensor.logging.debug( "Generation: " + str( generation ) ) + return generation + + +if __name__ == "__main__": + bittensor.utils.version_checking() + Dolly12BMiner().run() diff --git a/neurons/text/prompting/miners/huggingface/dolly/requirements.txt b/neurons/text/prompting/miners/huggingface/dolly/requirements.txt new file mode 100644 index 0000000000..fe2343560f --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/dolly/requirements.txt @@ -0,0 +1,3 @@ +accelerate>=0.16.0,<1 +transformers[torch]>=4.28.1,<5 +torch>=1.13.1,<2" \ No newline at end of file diff --git a/neurons/text/prompting/miners/neoxt/README.md b/neurons/text/prompting/miners/huggingface/dromedary/README.md similarity index 68% rename from neurons/text/prompting/miners/neoxt/README.md rename to neurons/text/prompting/miners/huggingface/dromedary/README.md index 106b720b6a..c526dac858 100644 --- a/neurons/text/prompting/miners/neoxt/README.md +++ b/neurons/text/prompting/miners/huggingface/dromedary/README.md @@ -1,40 +1,45 @@ -## Neoxt Miner -togethercomputer/GPT-NeoXT-Chat-Base-20B Language Model Serving with BitTensor -This code is for running a language model powered by togethercomputer through the BitTensor framework. + +## Dromedary Miner +Dromedary 65B completion miner for bittensor's prompting network. # Example Usage ``` -python3 -m pip install -r neurons/text/prompting/miners/neoxt/requirements.txt -python3 neurons/text/prompting/miners/neoxt/neuron.py +python3 neurons/text/prompting/miners/huggingface/dromedary/neuron.py ``` # Full Usage ``` -usage: neuron.py [-h] [--neoxt.model_name NEOXT.MODEL_NAME] [--neoxt.device NEOXT.DEVICE] [--neoxt.max_new_tokens NEOXT.MAX_NEW_TOKENS] [--neoxt.temperature NEOXT.TEMPERATURE] [--neoxt.do_sample] +usage: neuron.py [-h] [--dromedary.model_name DROMEDARY.MODEL_NAME] [--dromedary.device DROMEDARY.DEVICE] [--dromedary.max_new_tokens DROMEDARY.MAX_NEW_TOKENS] + [--dromedary.temperature DROMEDARY.TEMPERATURE] [--dromedary.do_sample] [--dromedary.do_prompt_injection] [--dromedary.system_prompt DROMEDARY.SYSTEM_PROMPT] [--netuid NETUID] [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] [--neuron.no_set_weights] - [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS ...]] - [--wallet.name WALLET.NAME] [--wallet.hotkey WALLET.HOTKEY] [--wallet.path WALLET.PATH] [--wallet._mock] [--wallet.reregister WALLET.REREGISTER] + [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] + [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]]] [--neuron.blacklist.allow_non_registered] + [--neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE] [--neuron.default_priority NEURON.DEFAULT_PRIORITY] [--wallet.name WALLET.NAME] + [--wallet.hotkey WALLET.HOTKEY] [--wallet.path WALLET.PATH] [--wallet._mock] [--wallet.reregister WALLET.REREGISTER] [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] [--axon.port AXON.PORT] [--axon.ip AXON.IP] [--axon.external_port AXON.EXTERNAL_PORT] [--axon.external_ip AXON.EXTERNAL_IP] [--axon.max_workers AXON.MAX_WORKERS] [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] [--subtensor.network SUBTENSOR.NETWORK] [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] - [--subtensor._mock] [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] - [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] [--subtensor.register.no_output_in_place] [--subtensor.register.verbose] - [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] - [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] - [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] [--logging.debug] [--logging.trace] [--logging.record_log] - [--logging.logging_dir LOGGING.LOGGING_DIR] [--metagraph._mock] [--config CONFIG] [--strict] + [--subtensor._mock] [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] + [--subtensor.register.no_output_in_place] [--subtensor.register.verbose] [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] + [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] + [--logging.debug] [--logging.trace] [--logging.record_log] [--logging.logging_dir LOGGING.LOGGING_DIR] [--config CONFIG] [--strict] optional arguments: -h, --help show this help message and exit - --neoxt.model_name NEOXT.MODEL_NAME - Name/path of model to load of model to load - --neoxt.device NEOXT.DEVICE + --dromedary.model_name DROMEDARY.MODEL_NAME + Name/path of model to load + --dromedary.device DROMEDARY.DEVICE Device to load model - --neoxt.max_new_tokens NEOXT.MAX_NEW_TOKENS + --dromedary.max_new_tokens DROMEDARY.MAX_NEW_TOKENS Max tokens for model output. - --neoxt.temperature NEOXT.TEMPERATURE + --dromedary.temperature DROMEDARY.TEMPERATURE Sampling temperature of model - --neoxt.do_sample Whether to use sampling or not (if not, uses greedy decoding). + --dromedary.do_sample + Whether to use sampling or not (if not, uses greedy decoding). + --dromedary.do_prompt_injection + Whether to use a custom "system" prompt instead of the one sent by bittensor. + --dromedary.system_prompt DROMEDARY.SYSTEM_PROMPT + What prompt to replace the system prompt with --netuid NETUID Subnet netuid --neuron.name NEURON.NAME Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name @@ -46,8 +51,14 @@ optional arguments: The maximum batch size for forward requests. --neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN The maximum sequence length for forward requests. - --neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS ...] + --neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]] To blacklist certain hotkeys + --neuron.blacklist.allow_non_registered + If True, the miner will allow non-registered hotkeys to mine. + --neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE + Set default stake for miners. + --neuron.default_priority NEURON.DEFAULT_PRIORITY + Set default priority for miners. --wallet.name WALLET.NAME The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet) --wallet.hotkey WALLET.HOTKEY @@ -69,8 +80,8 @@ optional arguments: --axon.external_ip AXON.EXTERNAL_IP The external ip this axon broadcasts to the network to. ie. [::] --axon.max_workers AXON.MAX_WORKERS - The maximum number connection handler threads working simultaneously on this endpoint. The grpc server distributes new worker threads to service requests - up to this number. + The maximum number connection handler threads working simultaneously on this endpoint. The grpc server distributes new worker threads to service requests up + to this number. --axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS Maximum number of allowed active connections --subtensor.network SUBTENSOR.NETWORK @@ -100,7 +111,6 @@ optional arguments: --logging.record_log Turns on logging to file. --logging.logging_dir LOGGING.LOGGING_DIR Logging default root directory. - --metagraph._mock To turn on metagraph mocking for testing purposes. --config CONFIG If set, defaults are overridden by passed file. --strict If flagged, config will check that only exact arguemnts have been set. - ``` \ No newline at end of file +``` \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/dromedary/neuron.py b/neurons/text/prompting/miners/huggingface/dromedary/neuron.py new file mode 100644 index 0000000000..21ec14f75a --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/dromedary/neuron.py @@ -0,0 +1,70 @@ +# The MIT License (MIT) +# Copyright © 2023 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import argparse +import bittensor +from typing import List, Dict +from transformers import AutoTokenizer, AutoModelForCausalLM + + +class DromedaryMiner( bittensor.HuggingFaceMiner ): + arg_prefix: str = "dromedary" + assistant_label: str = "Dromedary:" + user_label: str = "User:" + system_label: str = "System:" + + @classmethod + def add_args( cls, parser: argparse.ArgumentParser ): + parser.add_argument( '--dromedary.device_map', type=str, help='Device to load model: Default "auto" for multi-GPU', default="auto" ) + + def __init__( self ): + super( DromedaryMiner, self ).__init__() + print ( self.config ) + + bittensor.logging.info( 'Loading ' + str( self.config.dromedary.model_name ) ) + self.tokenizer = AutoTokenizer.from_pretrained( self.config.dromedary.model_name, use_fast=False ) + self.model = AutoModelForCausalLM.from_pretrained( + self.config.dromedary.model_name, + device_map=self.config.dromedary.device_map, + torch_dtype=torch.float16, + low_cpu_mem_usage=True + ) + bittensor.logging.info( 'Model loaded!' ) + + def forward( self, messages: List[Dict[str, str]] ) -> str: + + history = self._process_history( self, messages ) + prompt = history + self.assistant_label + + input_ids = self.tokenizer.encode( prompt, return_tensors="pt" ).to( self.config.dromedary.device ) + output = self.model.generate( + input_ids, + max_length=input_ids.shape[1] + self.config.dromedary.max_new_tokens, + temperature=self.config.dromedary.temperature, + do_sample=self.config.dromedary.do_sample, + pad_token_id=self.tokenizer.eos_token_id, + ) + generation = self.tokenizer.decode( output[0][input_ids.shape[1]:], skip_special_tokens=True ) + + bittensor.logging.debug( "Message: " + str( messages ) ) + bittensor.logging.debug( "Generation: " + str( generation ) ) + return generation + +if __name__ == "__main__": + bittensor.utils.version_checking() + DromedaryMiner().run() \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/fastchat_t5/README.md b/neurons/text/prompting/miners/huggingface/fastchat_t5/README.md new file mode 100644 index 0000000000..d74449977b --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/fastchat_t5/README.md @@ -0,0 +1,127 @@ +# FastChat T5 Miner +FastChat T5 completion miner for bittensor's prompting network. + +# Download weights +They disabled API inference requests via HuggingFace so you've gotta do it yourself by downloading the weights and passing the path directly. + +```bash +git lfs install +git clone https://huggingface.co/lmsys/fastchat-t5-3b-v1.0 +``` + +# Example Usage +``` +python3 neurons/text/prompting/miners/huggingface/fastchat_t5/neuron.py --fastchat_t5.model_path /path/to/fastchat-t5-3b-v1.0 +``` + +# Full Usage +``` +usage: fastchat-t5.py [-h] [--fastchat_t5.MODEL_PATH FASTCHAT_T5.MODEL_PATH] [--fastchat_t5.device FASTCHAT_T5.DEVICE] [--fastchat_t5.max_new_tokens FASTCHAT_T5.MAX_NEW_TOKENS] + [--fastchat_t5.temperature FASTCHAT_T5.TEMPERATURE] [--fastchat_t5.greedy_decoding] [--fastchat_t5.repetition_penalty FASTCHAT_T5.REPETITION_PENALTY] + [--fastchat_t5.do_prompt_injection] [--fastchat_t5.system_prompt FASTCHAT_T5.SYSTEM_PROMPT] [--netuid NETUID] [--neuron.name NEURON.NAME] + [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] [--neuron.no_set_weights] [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] + [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]]] + [--neuron.blacklist.allow_non_registered] [--neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE] + [--neuron.default_priority NEURON.DEFAULT_PRIORITY] [--wallet.name WALLET.NAME] [--wallet.hotkey WALLET.HOTKEY] [--wallet.path WALLET.PATH] [--wallet._mock] + [--wallet.reregister WALLET.REREGISTER] [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] + [--axon.port AXON.PORT] [--axon.ip AXON.IP] [--axon.external_port AXON.EXTERNAL_PORT] [--axon.external_ip AXON.EXTERNAL_IP] + [--axon.max_workers AXON.MAX_WORKERS] [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] [--subtensor.network SUBTENSOR.NETWORK] + [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] [--subtensor._mock] [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] + [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] [--subtensor.register.no_output_in_place] [--subtensor.register.verbose] + [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] + [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] + [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] [--logging.debug] [--logging.trace] [--logging.record_log] + [--logging.logging_dir LOGGING.LOGGING_DIR] [--config CONFIG] [--strict] + +optional arguments: + -h, --help show this help message and exit + --fastchat_t5.MODEL_PATH FASTCHAT_T5.MODEL_PATH + Name/path of model to load + --fastchat_t5.device FASTCHAT_T5.DEVICE + Device to load model + --fastchat_t5.max_new_tokens FASTCHAT_T5.MAX_NEW_TOKENS + Max tokens for model output. + --fastchat_t5.temperature FASTCHAT_T5.TEMPERATURE + Sampling temperature of model + --fastchat_t5.greedy_decoding + Whether to use greedy sampling or not (if not, uses multinomial sampling). + --fastchat_t5.repetition_penalty FASTCHAT_T5.REPETITION_PENALTY + Repetition penalty for model + --fastchat_t5.do_prompt_injection + Whether to use a custom "system" prompt instead of the one sent by bittensor. + --fastchat_t5.system_prompt FASTCHAT_T5.SYSTEM_PROMPT + What prompt to replace the system prompt with + --netuid NETUID Subnet netuid + --neuron.name NEURON.NAME + Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name + --neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH + Blocks until the miner sets weights on chain + --neuron.no_set_weights + If True, the model does not set weights. + --neuron.max_batch_size NEURON.MAX_BATCH_SIZE + The maximum batch size for forward requests. + --neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN + The maximum sequence length for forward requests. + --neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]] + To blacklist certain hotkeys + --neuron.blacklist.allow_non_registered + If True, the miner will allow non-registered hotkeys to mine. + --neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE + Set default stake for miners. + --neuron.default_priority NEURON.DEFAULT_PRIORITY + Set default priority for miners. + --wallet.name WALLET.NAME + The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet) + --wallet.hotkey WALLET.HOTKEY + The name of wallet's hotkey. + --wallet.path WALLET.PATH + The path to your bittensor wallets + --wallet._mock To turn on wallet mocking for testing purposes. + --wallet.reregister WALLET.REREGISTER + Whether to reregister the wallet if it is not already registered. + --axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS + maximum number of threads in thread pool + --axon.priority.maxsize AXON.PRIORITY.MAXSIZE + maximum size of tasks in priority queue + --axon.port AXON.PORT + The local port this axon endpoint is bound to. i.e. 8091 + --axon.ip AXON.IP The local ip this axon binds to. ie. [::] + --axon.external_port AXON.EXTERNAL_PORT + The public port this axon broadcasts to the network. i.e. 8091 + --axon.external_ip AXON.EXTERNAL_IP + The external ip this axon broadcasts to the network to. ie. [::] + --axon.max_workers AXON.MAX_WORKERS + The maximum number connection handler threads working simultaneously on this endpoint. The grpc server distributes new worker threads to service requests up + to this number. + --axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS + Maximum number of allowed active connections + --subtensor.network SUBTENSOR.NETWORK + The subtensor network flag. The likely choices are: -- finney (main network) -- local (local running network) -- mock (creates a mock connection (for + testing)) If this option is set it overloads subtensor.chain_endpoint with an entry point node from that network. + --subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT + The subtensor endpoint flag. If set, overrides the --network flag. + --subtensor._mock To turn on subtensor mocking for testing purposes. + --subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES, -n SUBTENSOR.REGISTER.NUM_PROCESSES + Number of processors to use for registration + --subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --subtensor.register.cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, -u SUBTENSOR.REGISTER.UPDATE_INTERVAL + The number of nonces to process before checking for next block during registration + --subtensor.register.no_output_in_place, --no_output_in_place + Whether to not ouput the registration statistics in-place. Set flag to disable output in-place. + --subtensor.register.verbose + Whether to ouput the registration statistics verbosely. + --subtensor.register.cuda.use_cuda, --cuda, --cuda.use_cuda + Set flag to use CUDA to register. + --subtensor.register.cuda.no_cuda, --no_cuda, --cuda.no_cuda + Set flag to not use CUDA for registration + --subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...], --cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...] + Set the CUDA device id(s). Goes by the order of speed. (i.e. 0 is the fastest). + --subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB, --cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB + Set the number of Threads Per Block for CUDA. + --logging.debug Turn on bittensor debugging information + --logging.trace Turn on bittensor trace level information + --logging.record_log Turns on logging to file. + --logging.logging_dir LOGGING.LOGGING_DIR + Logging default root directory. + --config CONFIG If set, defaults are overridden by passed file. + --strict If flagged, config will check that only exact arguemnts have been set. +``` \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/fastchat_t5/neuron.py b/neurons/text/prompting/miners/huggingface/fastchat_t5/neuron.py new file mode 100644 index 0000000000..4bc47638bd --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/fastchat_t5/neuron.py @@ -0,0 +1,41 @@ +import torch +import argparse +import bittensor +from typing import List, Dict +from transformers import T5Tokenizer, AutoModelForSeq2SeqLM + +class FastChatT5Miner( bittensor.HuggingFaceMiner ): + + arg_prefix: str = "fastchat_t5" + assistant_label: str = "ASSISTANT:" + user_label: str = "USER:" + system_label: str = "SYSTEM:" + + def load_model( self ): + bittensor.logging.info( 'Loading ' + str( self.config.fastchat_t5.model_name ) ) + model = AutoModelForSeq2SeqLM.from_pretrained( self.config.fastchat_t5.model_name, local_files_only=True, low_cpu_mem_usage=True, torch_dtype=torch.float16 ) + bittensor.logging.info( 'Model loaded!' ) + return model + + def load_tokenizer( self ): + return T5Tokenizer.from_pretrained( self.config.fastchat_t5.model_name, local_files_only=True ) + + def forward( self, messages: List[Dict[str, str]] ) -> str: + history = self.process_history( messages ) + prompt = history + self.assistant_label + input_ids = self.tokenizer.encode(prompt, return_tensors="pt").to(self.config.fastchat_t5.device) + output = self.model.generate( + input_ids, + max_length=input_ids.shape[1] + self.config.fastchat_t5.max_new_tokens, + temperature=self.config.fastchat_t5.temperature, + pad_token_id=self.tokenizer.eos_token_id, + ) + generation = self.tokenizer.decode( output[0], skip_special_tokens=True ) + + bittensor.logging.debug( "Message: " + str( messages ) ) + bittensor.logging.debug( "Generation: " + str( generation ) ) + return generation + +if __name__ == "__main__": + bittensor.utils.version_checking() + FastChatT5Miner().run() diff --git a/neurons/text/prompting/miners/robertmyers/README.md b/neurons/text/prompting/miners/huggingface/gpt4_x_vicuna/README.md similarity index 81% rename from neurons/text/prompting/miners/robertmyers/README.md rename to neurons/text/prompting/miners/huggingface/gpt4_x_vicuna/README.md index 730e59ec4a..733d99467a 100644 --- a/neurons/text/prompting/miners/robertmyers/README.md +++ b/neurons/text/prompting/miners/huggingface/gpt4_x_vicuna/README.md @@ -1,16 +1,38 @@ +## Gpt4_x_vicuna Miner +Gpt4_x_vicuna Language Model Serving with BitTensor +This code is for running the Gpt4_x_vicuna by Nous Research model through the BitTensor framework. -## RoberMyers Miner -Robert myers completion miner for bittensor's prompting network. +# Overview + +## Contents + +- [Licence](#Licence) +- [Installing Dependencies](#installing-dependencies) +- [Starting Miner](#starting-miner) + + +# Licence +gpl + +# Installing Dependencies + +``` +python3 -m pip install -r neurons/text/prompting/miners/huggingface/gpt4_x_vicuna/requirements.txt +``` + +# Starting Miner +To start the miner, all you need to do is to specify the path to the model, or the name on Huggingface hub, and it will be downloaded. + +You can find different model checkpoints by searching Huggingface, or by looking at Nous Research's Huggingface page https://huggingface.co/NousResearch -# Example Usage ``` -python3 -m pip install -r neurons/text/prompting/miners/robertmyers/requirements.txt -python3 neurons/text/prompting/miners/robertmyers/neuron.py +python3 neurons/text/prompting/miners/huggingface/gpt4_x_vicuna/neuron.py --gpt4_x_vicuna.model_name GPT4_X_VICUNA.MODEL_NAME_OR_PATH ``` # Full Usage ``` -usage: neuron.py [-h] [--robertmyers.max_new_tokens ROBERTMYERS.MAX_NEW_TOKENS] [--netuid NETUID] [--neuron.name NEURON.NAME] +usage: neuron.py [-h] [--gpt4_x_vicuna.model_name GPT4_X_VICUNA.MODEL_NAME] [--gpt4_x_vicuna.device GPT4_X_VICUNA.DEVICE] [--gpt4_x_vicuna.max_new_tokens GPT4_X_VICUNA.MAX_NEW_TOKENS] + [--gpt4_x_vicuna.temperature GPT4_X_VICUNA.TEMPERATURE] [--gpt4_x_vicuna.do_sample] [--netuid NETUID] [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] [--neuron.no_set_weights] [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS ...]] [--neuron.blacklist.allow_non_registered] @@ -30,8 +52,15 @@ usage: neuron.py [-h] [--robertmyers.max_new_tokens ROBERTMYERS.MAX_NEW_TOKENS] optional arguments: -h, --help show this help message and exit - --robertmyers.max_new_tokens ROBERTMYERS.MAX_NEW_TOKENS + --neoxt.model_name NEOXT.MODEL_NAME + Name/path of model to load of model to load + --gpt4_x_vicuna.device GPT4_X_VICUNA.DEVICE + Device to load model + --gpt4_x_vicuna.max_new_tokens GPT4_X_VICUNA.MAX_NEW_TOKENS Max tokens for model output. + --gpt4_x_vicuna.temperature GPT4_X_VICUNA.TEMPERATURE + Sampling temperature of model + --gpt4_x_vicuna.do_sample Whether to use sampling or not (if not, uses greedy decoding). --netuid NETUID Subnet netuid --neuron.name NEURON.NAME Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name diff --git a/neurons/text/prompting/miners/huggingface/gpt4_x_vicuna/neuron.py b/neurons/text/prompting/miners/huggingface/gpt4_x_vicuna/neuron.py new file mode 100644 index 0000000000..a3a49ff67c --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/gpt4_x_vicuna/neuron.py @@ -0,0 +1,58 @@ +# The MIT License (MIT) +# Copyright © 2021 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import bittensor +from typing import List, Dict +from transformers import AutoTokenizer, AutoModelForCausalLM + +class Gpt4_x_vicunaMiner( bittensor.HuggingFaceMiner ): + arg_prefix = 'gpt4_x_vicuna' + system_label = '### System:' + user_label = '### User:' + assistant_label = '### Response:' + + def load_tokenizer(self): + return AutoTokenizer.from_pretrained( self.config.gpt4_x_vicuna.model_name, use_fast=False ) + + def load_model(self): + return AutoModelForCausalLM.from_pretrained( self.config.gpt4_x_vicuna.model_name, torch_dtype = torch.float16, low_cpu_mem_usage=True ) + + def forward(self, messages: List[Dict[str, str]]) -> str: + + history = self.process_history( messages ) + prompt = history + self.assistant_label + + input_ids = self.tokenizer.encode( prompt, return_tensors="pt" ).to( self.config.gpt4_x_vicuna.device ) + + output = self.model.generate( + input_ids, + max_length=input_ids.shape[1] + self.config.gpt4_x_vicuna.max_new_tokens, + temperature=self.config.gpt4_x_vicuna.temperature, + do_sample=self.config.gpt4_x_vicuna.do_sample, + pad_token_id=self.tokenizer.eos_token_id, + ) + generation = self.tokenizer.decode( output[0][input_ids.shape[1]:], skip_special_tokens=True ) + + bittensor.logging.debug( "Messages: " + str( messages ) ) + bittensor.logging.debug( "Prompt: " + str( prompt ) ) + bittensor.logging.debug( "Generation: " + str( generation ) ) + return generation + +if __name__ == "__main__": + bittensor.utils.version_checking() + Gpt4_x_vicunaMiner().run() \ No newline at end of file diff --git a/neurons/text/prompting/miners/vicuna/requirements.txt b/neurons/text/prompting/miners/huggingface/gpt4_x_vicuna/requirements.txt similarity index 100% rename from neurons/text/prompting/miners/vicuna/requirements.txt rename to neurons/text/prompting/miners/huggingface/gpt4_x_vicuna/requirements.txt diff --git a/neurons/text/prompting/miners/huggingface/guanaco/README.md b/neurons/text/prompting/miners/huggingface/guanaco/README.md new file mode 100644 index 0000000000..5ecdb24207 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/guanaco/README.md @@ -0,0 +1,150 @@ +# Guanaco Miner +timdettmers Guanaco Language Model Serving with BitTensor +This code is for running a language model powered by togethercomputer through the BitTensor framework. +Reference: [code](https://github.com/artidoro/qlora) + +# Example Usage +``` +python3 -m pip install -r neurons/text/prompting/miners/huggingface/guanaco/requirements.txt +python neurons/text/prompting/miners/huggingface/guanaco/neuron.py --guanaco.model_name timdettmers/guanaco-33b-merged --guanaco.device_map auto +``` + +# Full Usage +``` +usage: guanaco_miner.py [-h] [--guanaco.model_name GUANACO.MODEL_NAME] [--guanaco.api_key GUANACO.API_KEY] + [--guanaco.device GUANACO.DEVICE] [--guanaco.max_new_tokens GUANACO.MAX_NEW_TOKENS] + [--guanaco.temperature GUANACO.TEMPERATURE] [--guanaco.do_sample] + [--guanaco.repetition_penalty GUANACO.REPETITION_PENALTY] [--guanaco.do_prompt_injection] + [--guanaco.system_prompt GUANACO.SYSTEM_PROMPT] + [--guanaco.repetition-penalty GUANACO.REPETITION_PENALTY] [--guanaco.top_p GUANACO.TOP_P] + [--guanaco.top_k GUANACO.TOP_K] [--guanaco.load_in_8bit GUANACO.LOAD_IN_8BIT] + [--guanaco.device_map GUANACO.DEVICE_MAP] + [--guanaco.pad_tokens GUANACO.PAD_TOKENS [GUANACO.PAD_TOKENS ...]] [--netuid NETUID] + [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] + [--neuron.no_set_weights] [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] + [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] + [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]]] + [--neuron.blacklist.allow_non_registered] + [--neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE] + [--neuron.default_priority NEURON.DEFAULT_PRIORITY] [--wallet.name WALLET.NAME] + [--wallet.hotkey WALLET.HOTKEY] [--wallet.path WALLET.PATH] [--wallet._mock] + [--wallet.reregister WALLET.REREGISTER] [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] + [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] [--axon.port AXON.PORT] [--axon.ip AXON.IP] + [--axon.external_port AXON.EXTERNAL_PORT] [--axon.external_ip AXON.EXTERNAL_IP] + [--axon.max_workers AXON.MAX_WORKERS] [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] + [--subtensor.network SUBTENSOR.NETWORK] [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] + [--subtensor._mock] [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] + [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] + [--subtensor.register.no_output_in_place] [--subtensor.register.verbose] + [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] + [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] + [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] [--logging.debug] [--logging.trace] + [--logging.record_log] [--logging.logging_dir LOGGING.LOGGING_DIR] [--config CONFIG] [--strict] + +optional arguments: + -h, --help show this help message and exit + --guanaco.model_name GUANACO.MODEL_NAME + Name or path of model to load + --guanaco.api_key GUANACO.API_KEY + huggingface api key + --guanaco.device GUANACO.DEVICE + Device to load model + --guanaco.max_new_tokens GUANACO.MAX_NEW_TOKENS + Max tokens for model output. + --guanaco.temperature GUANACO.TEMPERATURE + Sampling temperature of model + --guanaco.do_sample Whether to use multinomial sampling. + --guanaco.repetition_penalty GUANACO.REPETITION_PENALTY + Repetition penalty for model + --guanaco.do_prompt_injection + Whether to use a custom "system" prompt instead of the one sent by bittensor. + --guanaco.system_prompt GUANACO.SYSTEM_PROMPT + What prompt to replace the system prompt with + --guanaco.repetition-penalty GUANACO.REPETITION_PENALTY + Repetition penalty for greedy decoding. Between 1.0 and infinity. 1.0 means no penalty. Default: 1.0 + --guanaco.top_p GUANACO.TOP_P + Top-p (nucleus) sampling. Defaults to 1.0 (top-k sampling). Must be between 0.0 and 1.0. + --guanaco.top_k GUANACO.TOP_K + Top-k sampling. Defaults to 0 (no top-k sampling). Must be between 0 and 1000. + --guanaco.load_in_8bit GUANACO.LOAD_IN_8BIT + Load model in 8 bit precision + --guanaco.device_map GUANACO.DEVICE_MAP + Device map for model parallelism. + --guanaco.pad_tokens GUANACO.PAD_TOKENS [GUANACO.PAD_TOKENS ...] + A list of integers separated by spaces for the pad_tokens. + --netuid NETUID Subnet netuid + --neuron.name NEURON.NAME + Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name + --neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH + Blocks until the miner sets weights on chain + --neuron.no_set_weights + If True, the model does not set weights. + --neuron.max_batch_size NEURON.MAX_BATCH_SIZE + The maximum batch size for forward requests. + --neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN + The maximum sequence length for forward requests. + --neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]] + To blacklist certain hotkeys + --neuron.blacklist.allow_non_registered + If True, the miner will allow non-registered hotkeys to mine. + --neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE + Set default stake for miners. + --neuron.default_priority NEURON.DEFAULT_PRIORITY + Set default priority for miners. + --wallet.name WALLET.NAME + The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this + wallet) + --wallet.hotkey WALLET.HOTKEY + The name of wallet's hotkey. + --wallet.path WALLET.PATH + The path to your bittensor wallets + --wallet._mock To turn on wallet mocking for testing purposes. + --wallet.reregister WALLET.REREGISTER + Whether to reregister the wallet if it is not already registered. + --axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS + maximum number of threads in thread pool + --axon.priority.maxsize AXON.PRIORITY.MAXSIZE + maximum size of tasks in priority queue + --axon.port AXON.PORT + The local port this axon endpoint is bound to. i.e. 8091 + --axon.ip AXON.IP The local ip this axon binds to. ie. [::] + --axon.external_port AXON.EXTERNAL_PORT + The public port this axon broadcasts to the network. i.e. 8091 + --axon.external_ip AXON.EXTERNAL_IP + The external ip this axon broadcasts to the network to. ie. [::] + --axon.max_workers AXON.MAX_WORKERS + The maximum number connection handler threads working simultaneously on this endpoint. The grpc + server distributes new worker threads to service requests up to this number. + --axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS + Maximum number of allowed active connections + --subtensor.network SUBTENSOR.NETWORK + The subtensor network flag. The likely choices are: -- finney (main network) -- local (local running + network) -- mock (creates a mock connection (for testing)) If this option is set it overloads + subtensor.chain_endpoint with an entry point node from that network. + --subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT + The subtensor endpoint flag. If set, overrides the --network flag. + --subtensor._mock To turn on subtensor mocking for testing purposes. + --subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES, -n SUBTENSOR.REGISTER.NUM_PROCESSES + Number of processors to use for registration + --subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --subtensor.register.cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, -u SUBTENSOR.REGISTER.UPDATE_INTERVAL + The number of nonces to process before checking for next block during registration + --subtensor.register.no_output_in_place, --no_output_in_place + Whether to not ouput the registration statistics in-place. Set flag to disable output in-place. + --subtensor.register.verbose + Whether to ouput the registration statistics verbosely. + --subtensor.register.cuda.use_cuda, --cuda, --cuda.use_cuda + Set flag to use CUDA to register. + --subtensor.register.cuda.no_cuda, --no_cuda, --cuda.no_cuda + Set flag to not use CUDA for registration + --subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...], --cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...] + Set the CUDA device id(s). Goes by the order of speed. (i.e. 0 is the fastest). + --subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB, --cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB + Set the number of Threads Per Block for CUDA. + --logging.debug Turn on bittensor debugging information + --logging.trace Turn on bittensor trace level information + --logging.record_log Turns on logging to file. + --logging.logging_dir LOGGING.LOGGING_DIR + Logging default root directory. + --config CONFIG If set, defaults are overridden by passed file. + --strict If flagged, config will check that only exact arguemnts have been set. + ``` \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/guanaco/neuron.py b/neurons/text/prompting/miners/huggingface/guanaco/neuron.py new file mode 100644 index 0000000000..6327c3e5be --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/guanaco/neuron.py @@ -0,0 +1,70 @@ +# The MIT License (MIT) +# Copyright © 2023 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import bittensor +from typing import List, Dict +from transformers import AutoTokenizer, AutoModelForCausalLM + +class GuanacoMiner( bittensor.HuggingFaceMiner ): + + arg_prefix: str = 'guanaco' + assistant_label: str = '### Assistant:' + user_label: str = '### Human:' + system_label: str = '' + + def load_tokenizer( self ): + return AutoTokenizer.from_pretrained( self.config.guanaco.model_name ) + + def load_model( self ): + return AutoModelForCausalLM.from_pretrained( + self.config.guanaco.model_name, + torch_dtype = torch.float16, + low_cpu_mem_usage=True, + device_map=self.config.guanaco.device_map + ) + + def forward(self, messages: List[Dict[str, str]]) -> str: + history = self.process_history( messages ) + prompt = history + self.assistant_label + + generate_kwargs = dict( + temperature=self.config.guanaco.temperature, + max_new_tokens=self.config.guanaco.max_new_tokens, + top_p=self.config.guanaco.top_p, + repetition_penalty=self.config.guanaco.repetition_penalty, + do_sample=self.config.guanaco.do_sample, + ) + if '33B' in self.config.guanaco.model_name: # Tim Dettmers 33B model-specific parameters + generate_kwargs['truncate'] = 999 + generate_kwargs['seed'] = 42 + + input_ids = self.tokenizer.encode( prompt, return_tensors="pt" ).to( self.config.guanaco.device ) + output = self.model.generate( + input_ids, + **generate_kwargs + ) + generated_text = self.tokenizer.decode( output[0][input_ids.shape[1]:], skip_special_tokens=True ) + generation = generated_text.split( self.assistant_label )[0].strip() + + bittensor.logging.debug("Message: " + str( messages ) ) + bittensor.logging.debug("Generation: " + str( generation ) ) + return generation + +if __name__ == "__main__": + bittensor.utils.version_checking() + GuanacoMiner().run() \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/guanaco/requirements.txt b/neurons/text/prompting/miners/huggingface/guanaco/requirements.txt new file mode 100644 index 0000000000..33059ec77c --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/guanaco/requirements.txt @@ -0,0 +1,2 @@ +transformers>=4.29.2 +accelerate \ No newline at end of file diff --git a/neurons/text/prompting/miners/koala/README.md b/neurons/text/prompting/miners/huggingface/koala/README.md similarity index 98% rename from neurons/text/prompting/miners/koala/README.md rename to neurons/text/prompting/miners/huggingface/koala/README.md index 080d53b1d5..6e56fed45d 100644 --- a/neurons/text/prompting/miners/koala/README.md +++ b/neurons/text/prompting/miners/huggingface/koala/README.md @@ -14,7 +14,7 @@ This code is for running the Koala model through the BitTensor framework. # Installing Dependencies ``` -python3 -m pip install -r neurons/text/prompting/miners/koala/requirements.txt +python3 -m pip install -r neurons/text/prompting/miners/huggingface/koala/requirements.txt ``` # Converting Weights Into Model @@ -62,7 +62,7 @@ python -m EasyLM.scripts.diff_checkpoint \ # Starting Miner ``` -python3 neurons/text/prompting/miners/koala/neuron.py +python3 neurons/text/prompting/miners/huggingface/koala_miner.py --koala.model_name TheBloke/koala-7B-HF ``` # Full Usage diff --git a/neurons/text/prompting/miners/huggingface/koala/neuron.py b/neurons/text/prompting/miners/huggingface/koala/neuron.py new file mode 100644 index 0000000000..5f2bee3de4 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/koala/neuron.py @@ -0,0 +1,54 @@ +# The MIT License (MIT) +# Copyright © 2023 Opentensor Foundation + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import bittensor +from typing import List, Dict +from transformers import AutoTokenizer, AutoModelForCausalLM + +class KoalaMiner( bittensor.HuggingFaceMiner ): + arg_prefix: str = 'koala' + assistant_label: str = 'GPT:' + user_label: str = 'USER:' + system_label: str = '' + + def load_tokenizer( self ): + return AutoTokenizer.from_pretrained( self.config.koala.model_name, use_fast=False ) + + def load_model( self ): + return AutoModelForCausalLM.from_pretrained( self.config.koala.model_name, torch_dtype = torch.float16, low_cpu_mem_usage=True ) + + def forward( self, messages: List[Dict[str, str]] ) -> str: + history = self._process_history( messages ) + prompt = history + self.system_label + input_ids = self.tokenizer.encode( prompt, return_tensors="pt" ).to( self.config.koala.device ) + output = self.model.generate( + input_ids, + max_length=input_ids.shape[1] + self.config.koala.max_new_tokens, + temperature=self.config.koala.temperature, + do_sample=self.config.koala.do_sample, + pad_token_id=self.tokenizer.eos_token_id, + ) + generation = self.tokenizer.decode( output[0][input_ids.shape[1]:], skip_special_tokens=True ) + + bittensor.logging.debug( "Message: " + str( messages ) ) + bittensor.logging.debug( "Generation: " + str( generation ) ) + return generation + +if __name__ == "__main__": + bittensor.utils.version_checking() + KoalaMiner().run() \ No newline at end of file diff --git a/neurons/text/prompting/miners/koala/requirements.txt b/neurons/text/prompting/miners/huggingface/koala/requirements.txt similarity index 100% rename from neurons/text/prompting/miners/koala/requirements.txt rename to neurons/text/prompting/miners/huggingface/koala/requirements.txt diff --git a/neurons/text/prompting/miners/pythia/README.md b/neurons/text/prompting/miners/huggingface/mpt_chat/README.md similarity index 84% rename from neurons/text/prompting/miners/pythia/README.md rename to neurons/text/prompting/miners/huggingface/mpt_chat/README.md index 68ca50baf1..c80893753e 100644 --- a/neurons/text/prompting/miners/pythia/README.md +++ b/neurons/text/prompting/miners/huggingface/mpt_chat/README.md @@ -1,17 +1,38 @@ -## Pythia Miner -togethercomputer/Pythia-7B Language Model Serving with BitTensor -This code is for running a language model powered by togethercomputer through the BitTensor framework. +## MPT_Chat Miner +MPT_Chat Language Model Serving with BitTensor +This code is for running the Mpt_chat by MosaicML model through the BitTensor framework. -# Example Usage +# Overview + +## Contents + +- [Licence](#Licence) +- [Installing Dependencies](#installing-dependencies) +- [Starting Miner](#starting-miner) + + +# Licence +CC-By-NC-SA-4.0 (non-commercial use only) + + +# Installing Dependencies + +``` +python3 -m pip install -r neurons/text/prompting/miners/huggingface/mpt_chat/requirements.txt +``` + +# Starting Miner +To start the miner, all you need to do is to specify the path to the model, or the name on Huggingface hub, and it will be downloaded. + +You can find different model checkpoints by searching Huggingface, or by looking at MosaicML's Huggingface page https://huggingface.co/NousResearch ``` -python3 -m pip install -r neurons/text/prompting/miners/pythia/requirements.txt -python3 neurons/text/prompting/miners/pythia/neuron.py +python3 neurons/text/prompting/miners/huggingface/mpt_chat/neuron.py --mpt_chat.model_name MPT_CHAT.MODEL_NAME_OR_PATH ``` # Full Usage ``` -usage: neuron.py [-h] [--pythia.model_name PYTHIA.MODEL_NAME] [--pythia.device PYTHIA.DEVICE] [--pythia.max_new_tokens PYTHIA.MAX_NEW_TOKENS] - [--pythia.temperature PYTHIA.TEMPERATURE] [--pythia.do_sample] [--netuid NETUID] [--neuron.name NEURON.NAME] +usage: neuron.py [-h] [--mpt_chat.model_name MPT_CHAT.MODEL_NAME] [--mpt_chat.device MPT_CHAT.DEVICE] [--mpt_chat.max_new_tokens MPT_CHAT.MAX_NEW_TOKENS] + [--mpt_chat.temperature MPT_CHAT.TEMPERATURE] [--mpt_chat.do_sample] [--netuid NETUID] [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] [--neuron.no_set_weights] [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS ...]] [--neuron.blacklist.allow_non_registered] @@ -33,13 +54,13 @@ optional arguments: -h, --help show this help message and exit --neoxt.model_name NEOXT.MODEL_NAME Name/path of model to load of model to load - --pythia.device PYTHIA.DEVICE + --mpt_chat.device MPT_CHAT.DEVICE Device to load model - --pythia.max_new_tokens PYTHIA.MAX_NEW_TOKENS + --mpt_chat.max_new_tokens MPT_CHAT.MAX_NEW_TOKENS Max tokens for model output. - --pythia.temperature PYTHIA.TEMPERATURE + --mpt_chat.temperature MPT_CHAT.TEMPERATURE Sampling temperature of model - --pythia.do_sample Whether to use sampling or not (if not, uses greedy decoding). + --mpt_chat.do_sample Whether to use sampling or not (if not, uses greedy decoding). --netuid NETUID Subnet netuid --neuron.name NEURON.NAME Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name diff --git a/neurons/text/prompting/miners/huggingface/mpt_chat/neuron.py b/neurons/text/prompting/miners/huggingface/mpt_chat/neuron.py new file mode 100644 index 0000000000..a3ac45bc55 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/mpt_chat/neuron.py @@ -0,0 +1,78 @@ +# The MIT License (MIT) +# Copyright © 2023 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import argparse +import bittensor +from typing import List, Dict +from transformers import AutoTokenizer, AutoModelForCausalLM, AutoConfig + +class Mpt_chatMiner( bittensor.HuggingFaceMiner ): + arg_prefix: str = 'mpt_chat' + system_label: str = '<|im_start|>system\n' + user_label: str = '<|im_start|>user\n' + assistant_label: str = '<|im_start|>assistant\n' + + @classmethod + def add_args( cls, parser: argparse.ArgumentParser ): + parser.add_argument( '--mpt_chat.tokenizer_name', type=str, required=False, help='Name/path of model to load' , default="EleutherAI/gpt-neox-20b") + parser.add_argument( '--mpt_chat.use_triton', action='store_true', default=False, help='Whether to use a triton to speed up inference' ) + + def load_tokenizer(self): + return AutoTokenizer.from_pretrained( self.config.mpt_chat.tokenizer_name ) + + def load_model(self): + config = AutoConfig.from_pretrained( 'mosaicml/mpt-7b-chat', trust_remote_code=True ) + + if self.config.mpt_chat.use_triton: + config.attn_config['attn_impl'] = 'triton' + + model = AutoModelForCausalLM.from_pretrained( + self.config.mpt_chat.model_name, + torch_dtype = torch.float16, + low_cpu_mem_usage=True, + trust_remote_code=True, + config=config + ) + return model + + def forward(self, messages: List[Dict[str, str]]) -> str: + + history = self.process_history( messages ) + prompt = history + self.assistant_label + + input_ids = self.tokenizer.encode( prompt, return_tensors="pt" ).to( self.config.mpt_chat.device ) + + output = self.model.generate( + input_ids, + max_length=input_ids.shape[1] + self.config.mpt_chat.max_new_tokens, + temperature=self.config.mpt_chat.temperature, + do_sample=self.config.mpt_chat.do_sample, + pad_token_id=self.tokenizer.eos_token_id, + ) + + generation = self.tokenizer.decode( output[0][input_ids.shape[1]:], skip_special_tokens=False ).strip() + generation = generation.split( "<|endoftext|>" )[0] + + bittensor.logging.debug( "Message: " + str( messages ) ) + bittensor.logging.debug( "Prompt: " + str( prompt ) ) + bittensor.logging.debug( "Generation: " + str( generation.replace( "<", "-" ) ) ) + return generation + +if __name__ == "__main__": + bittensor.utils.version_checking() + Mpt_chatMiner().run() \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/mpt_chat/requirements.txt b/neurons/text/prompting/miners/huggingface/mpt_chat/requirements.txt new file mode 100644 index 0000000000..406fd1d021 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/mpt_chat/requirements.txt @@ -0,0 +1,5 @@ +transformers>=4.28.0 +fschat +tokenizers>=0.13.3 +accelerate +einops \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/neoxt/README.md b/neurons/text/prompting/miners/huggingface/neoxt/README.md new file mode 100644 index 0000000000..ffb387c9e0 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/neoxt/README.md @@ -0,0 +1,136 @@ +## Neoxt Miner +togethercomputer/GPT-NeoXT-Chat-Base-20B Language Model Serving with BitTensor +This code is for running a language model powered by togethercomputer through the BitTensor framework. + +# Example Usage +``` +python3 -m pip install -r neurons/text/prompting/miners/huggingface/neoxt/requirements.txt +python3 neurons/text/prompting/miners/huggingface/neoxt/neuron.py --neoxt.model_name togethercomputer/GPT-NeoXT-Chat-Base-20B +``` + +# Full Usage +``` +usage: neoxt_miner.py [-h] --neoxt.model_name NEOXT.MODEL_NAME [--neoxt.device NEOXT.DEVICE] [--neoxt.max_new_tokens NEOXT.MAX_NEW_TOKENS] + [--neoxt.temperature NEOXT.TEMPERATURE] [--neoxt.do_sample] [--neoxt.repetition_penalty NEOXT.REPETITION_PENALTY] + [--neoxt.do_prompt_injection] [--neoxt.system_prompt NEOXT.SYSTEM_PROMPT] + [--neoxt.repetition-penalty NEOXT.REPETITION_PENALTY] [--neoxt.top_p NEOXT.TOP_P] [--neoxt.top_k NEOXT.TOP_K] + [--neoxt.load_in_8bit NEOXT.LOAD_IN_8BIT] [--neoxt.pad_tokens NEOXT.PAD_TOKENS [NEOXT.PAD_TOKENS ...]] [--netuid NETUID] + [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] [--neuron.no_set_weights] + [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] + [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]]] + [--neuron.blacklist.allow_non_registered] [--neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE] + [--neuron.default_priority NEURON.DEFAULT_PRIORITY] [--wallet.name WALLET.NAME] [--wallet.hotkey WALLET.HOTKEY] + [--wallet.path WALLET.PATH] [--wallet._mock] [--wallet.reregister WALLET.REREGISTER] + [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] + [--axon.port AXON.PORT] [--axon.ip AXON.IP] [--axon.external_port AXON.EXTERNAL_PORT] [--axon.external_ip AXON.EXTERNAL_IP] + [--axon.max_workers AXON.MAX_WORKERS] [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] + [--subtensor.network SUBTENSOR.NETWORK] [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] [--subtensor._mock] + [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] + [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] [--subtensor.register.no_output_in_place] + [--subtensor.register.verbose] [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] + [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] + [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] [--logging.debug] [--logging.trace] [--logging.record_log] + [--logging.logging_dir LOGGING.LOGGING_DIR] [--config CONFIG] [--strict] + +optional arguments: + -h, --help show this help message and exit + --neoxt.model_name NEOXT.MODEL_NAME + Name or path of model to load + --neoxt.device NEOXT.DEVICE + Device to load model + --neoxt.max_new_tokens NEOXT.MAX_NEW_TOKENS + Max tokens for model output. + --neoxt.temperature NEOXT.TEMPERATURE + Sampling temperature of model + --neoxt.do_sample Whether to use multinomial sampling. + --neoxt.repetition_penalty NEOXT.REPETITION_PENALTY + Repetition penalty for model + --neoxt.do_prompt_injection + Whether to use a custom "system" prompt instead of the one sent by bittensor. + --neoxt.system_prompt NEOXT.SYSTEM_PROMPT + What prompt to replace the system prompt with + --neoxt.repetition-penalty NEOXT.REPETITION_PENALTY + Repetition penalty for greedy decoding. Between 1.0 and infinity. 1.0 means no penalty. Default: 1.0 + --neoxt.top_p NEOXT.TOP_P + Top-p (nucleus) sampling. Defaults to 1.0 (top-k sampling). Must be between 0.0 and 1.0. + --neoxt.top_k NEOXT.TOP_K + Top-k sampling. Defaults to 0 (no top-k sampling). Must be between 0 and 1000. + --neoxt.load_in_8bit NEOXT.LOAD_IN_8BIT + Load model in 8 bit precision + --neoxt.pad_tokens NEOXT.PAD_TOKENS [NEOXT.PAD_TOKENS ...] + A list of integers separated by spaces for the pad_tokens. + --netuid NETUID Subnet netuid + --neuron.name NEURON.NAME + Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name + --neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH + Blocks until the miner sets weights on chain + --neuron.no_set_weights + If True, the model does not set weights. + --neuron.max_batch_size NEURON.MAX_BATCH_SIZE + The maximum batch size for forward requests. + --neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN + The maximum sequence length for forward requests. + --neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]] + To blacklist certain hotkeys + --neuron.blacklist.allow_non_registered + If True, the miner will allow non-registered hotkeys to mine. + --neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE + Set default stake for miners. + --neuron.default_priority NEURON.DEFAULT_PRIORITY + Set default priority for miners. + --wallet.name WALLET.NAME + The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet) + --wallet.hotkey WALLET.HOTKEY + The name of wallet's hotkey. + --wallet.path WALLET.PATH + The path to your bittensor wallets + --wallet._mock To turn on wallet mocking for testing purposes. + --wallet.reregister WALLET.REREGISTER + Whether to reregister the wallet if it is not already registered. + --axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS + maximum number of threads in thread pool + --axon.priority.maxsize AXON.PRIORITY.MAXSIZE + maximum size of tasks in priority queue + --axon.port AXON.PORT + The local port this axon endpoint is bound to. i.e. 8091 + --axon.ip AXON.IP The local ip this axon binds to. ie. [::] + --axon.external_port AXON.EXTERNAL_PORT + The public port this axon broadcasts to the network. i.e. 8091 + --axon.external_ip AXON.EXTERNAL_IP + The external ip this axon broadcasts to the network to. ie. [::] + --axon.max_workers AXON.MAX_WORKERS + The maximum number connection handler threads working simultaneously on this endpoint. The grpc server distributes new + worker threads to service requests up to this number. + --axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS + Maximum number of allowed active connections + --subtensor.network SUBTENSOR.NETWORK + The subtensor network flag. The likely choices are: -- finney (main network) -- local (local running network) -- mock + (creates a mock connection (for testing)) If this option is set it overloads subtensor.chain_endpoint with an entry point + node from that network. + --subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT + The subtensor endpoint flag. If set, overrides the --network flag. + --subtensor._mock To turn on subtensor mocking for testing purposes. + --subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES, -n SUBTENSOR.REGISTER.NUM_PROCESSES + Number of processors to use for registration + --subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --subtensor.register.cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, -u SUBTENSOR.REGISTER.UPDATE_INTERVAL + The number of nonces to process before checking for next block during registration + --subtensor.register.no_output_in_place, --no_output_in_place + Whether to not ouput the registration statistics in-place. Set flag to disable output in-place. + --subtensor.register.verbose + Whether to ouput the registration statistics verbosely. + --subtensor.register.cuda.use_cuda, --cuda, --cuda.use_cuda + Set flag to use CUDA to register. + --subtensor.register.cuda.no_cuda, --no_cuda, --cuda.no_cuda + Set flag to not use CUDA for registration + --subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...], --cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...] + Set the CUDA device id(s). Goes by the order of speed. (i.e. 0 is the fastest). + --subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB, --cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB + Set the number of Threads Per Block for CUDA. + --logging.debug Turn on bittensor debugging information + --logging.trace Turn on bittensor trace level information + --logging.record_log Turns on logging to file. + --logging.logging_dir LOGGING.LOGGING_DIR + Logging default root directory. + --config CONFIG If set, defaults are overridden by passed file. + --strict If flagged, config will check that only exact arguemnts have been set. + ``` \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/neoxt/neuron.py b/neurons/text/prompting/miners/huggingface/neoxt/neuron.py new file mode 100644 index 0000000000..9fb87cc8d9 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/neoxt/neuron.py @@ -0,0 +1,56 @@ +# The MIT License (MIT) +# Copyright © 2023 Opentensor Foundation + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import bittensor +from typing import List, Dict +from transformers import AutoTokenizer, AutoModelForCausalLM + + +class NeoxtMiner( bittensor.HuggingFaceMiner ): + arg_prefix: str = 'neoxt' + assistant_label: str = ':' + user_label: str = ':' + system_label: str = '' + + def load_tokenizer( self ): + return AutoTokenizer.from_pretrained( self.config.neoxt.model_name ) + + def load_model( self ): + return AutoModelForCausalLM.from_pretrained( self.config.neoxt.model_name, torch_dtype = torch.float16, low_cpu_mem_usage=True ) + + def forward( self, messages: List[Dict[str, str]] ) -> str: + history = self.process_history( messages ) + prompt = history + self.assistant_label + input_ids = self.tokenizer.encode( prompt, return_tensors="pt" ).to( self.config.neoxt.device ) + output = self.model.generate( + input_ids, + max_length=input_ids.shape[1] + self.config.neoxt.max_new_tokens, + temperature=self.config.neoxt.temperature, + do_sample=self.config.neoxt.do_sample, + pad_token_id=self.tokenizer.eos_token_id, + ) + generated_text = self.tokenizer.decode( output[0][input_ids.shape[1]:], skip_special_tokens=True ) + generation = generated_text.split( "" )[0].strip() + + bittensor.logging.debug( "Message: " + str( messages ).replace( "<","-" ).replace( ">","-" ) ) + bittensor.logging.debug( "Generation: " + str( generation ).replace( "<","-" ).replace( ">","-" ) ) + return generation + +if __name__ == "__main__": + bittensor.utils.version_checking() + NeoxtMiner().run() diff --git a/neurons/text/prompting/miners/neoxt/requirements.txt b/neurons/text/prompting/miners/huggingface/neoxt/requirements.txt similarity index 100% rename from neurons/text/prompting/miners/neoxt/requirements.txt rename to neurons/text/prompting/miners/huggingface/neoxt/requirements.txt diff --git a/neurons/text/prompting/miners/huggingface/oasst_pythia/README.md b/neurons/text/prompting/miners/huggingface/oasst_pythia/README.md new file mode 100644 index 0000000000..6a011725d6 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/oasst_pythia/README.md @@ -0,0 +1,118 @@ + +## OpenAssistant Pythia Miner +OpenAssistant's Pythia (12B) completion miner for bittensor's prompting network. + +# Example Usage +``` +python3 -m pip install -r neurons/text/prompting/miners/huggingface/oasst_pythia/requirements.txt +python3 neurons/text/prompting/miners/huggingface/oasst_pythia/neuron.py --oasst_pythia.OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5 +``` + +# Full Usage +``` +usage: neuron.py [-h] [--pythia12B.model_name PYTHIA12B.MODEL_NAME] [--pythia12B.load_in_8bit PYTHIA12B.LOAD_IN_8BIT] [--pythia12B.max_new_tokens PYTHIA12B.MAX_NEW_TOKENS] + [--pythia12B.temperature PYTHIA12B.TEMPERATURE] [--pythia12B.greedy_sampling] [--pythia12B.repetition-penalty PYTHIA12B.REPETITION_PENALTY] + [--pythia12B.top_p PYTHIA12B.TOP_P] [--pythia12B.top_k PYTHIA12B.TOP_K] [--netuid NETUID] [--neuron.name NEURON.NAME] + [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] [--neuron.no_set_weights] [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] + [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]]] + [--neuron.blacklist.allow_non_registered] [--neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE] [--neuron.default_priority NEURON.DEFAULT_PRIORITY] + [--wallet.name WALLET.NAME] [--wallet.hotkey WALLET.HOTKEY] [--wallet.path WALLET.PATH] [--wallet._mock] [--wallet.reregister WALLET.REREGISTER] + [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] [--axon.port AXON.PORT] [--axon.ip AXON.IP] + [--axon.external_port AXON.EXTERNAL_PORT] [--axon.external_ip AXON.EXTERNAL_IP] [--axon.max_workers AXON.MAX_WORKERS] + [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] [--subtensor.network SUBTENSOR.NETWORK] [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] + [--subtensor._mock] [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] + [--subtensor.register.no_output_in_place] [--subtensor.register.verbose] [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] + [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] + [--logging.debug] [--logging.trace] [--logging.record_log] [--logging.logging_dir LOGGING.LOGGING_DIR] [--config CONFIG] [--strict] +optional arguments: + -h, --help show this help message and exit + --pythia12B.model_name PYTHIA12B.MODEL_NAME + Name/path of model to load + --pythia12B.load_in_8bit PYTHIA12B.LOAD_IN_8BIT + Load model in 8 bit precision + --pythia12B.max_new_tokens PYTHIA12B.MAX_NEW_TOKENS + Max tokens for model output. + --pythia12B.temperature PYTHIA12B.TEMPERATURE + Sampling temperature of model + --pythia12B.greedy_sampling + Whether to use greedy sampling or not (if not, uses multinomial sampling). + --pythia12B.repetition-penalty PYTHIA12B.REPETITION_PENALTY + Repetition penalty for greedy decoding. Between 1.0 and infinity. 1.0 means no penalty. Default: 1.0 + --pythia12B.top_p PYTHIA12B.TOP_P + Top-p (nucleus) sampling. Defaults to 1.0 (top-k sampling). Must be between 0.0 and 1.0. + --pythia12B.top_k PYTHIA12B.TOP_K + Top-k sampling. Defaults to 0 (no top-k sampling). Must be between 0 and 1000. + --netuid NETUID Subnet netuid + --neuron.name NEURON.NAME + Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name + --neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH + Blocks until the miner sets weights on chain + --neuron.no_set_weights + If True, the model does not set weights. + --neuron.max_batch_size NEURON.MAX_BATCH_SIZE + The maximum batch size for forward requests. + --neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN + The maximum sequence length for forward requests. + --neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]] + To blacklist certain hotkeys + --neuron.blacklist.allow_non_registered + If True, the miner will allow non-registered hotkeys to mine. + --neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE + Set default stake for miners. + --neuron.default_priority NEURON.DEFAULT_PRIORITY + Set default priority for miners. + --wallet.name WALLET.NAME + The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet) + --wallet.hotkey WALLET.HOTKEY + The name of wallet's hotkey. + --wallet.path WALLET.PATH + The path to your bittensor wallets + --wallet._mock To turn on wallet mocking for testing purposes. + --wallet.reregister WALLET.REREGISTER + Whether to reregister the wallet if it is not already registered. + --axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS + maximum number of threads in thread pool + --axon.priority.maxsize AXON.PRIORITY.MAXSIZE + maximum size of tasks in priority queue + --axon.port AXON.PORT + The local port this axon endpoint is bound to. i.e. 8091 + --axon.ip AXON.IP The local ip this axon binds to. ie. [::] + --axon.external_port AXON.EXTERNAL_PORT + The public port this axon broadcasts to the network. i.e. 8091 + --axon.external_ip AXON.EXTERNAL_IP + The external ip this axon broadcasts to the network to. ie. [::] + --axon.max_workers AXON.MAX_WORKERS + The maximum number connection handler threads working simultaneously on this endpoint. The grpc server distributes new worker threads to service requests up + to this number. + --axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS + Maximum number of allowed active connections + --subtensor.network SUBTENSOR.NETWORK + The subtensor network flag. The likely choices are: -- finney (main network) -- local (local running network) -- mock (creates a mock connection (for + testing)) If this option is set it overloads subtensor.chain_endpoint with an entry point node from that network. + --subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT + The subtensor endpoint flag. If set, overrides the --network flag. + --subtensor._mock To turn on subtensor mocking for testing purposes. + --subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES, -n SUBTENSOR.REGISTER.NUM_PROCESSES + Number of processors to use for registration + --subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --subtensor.register.cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, -u SUBTENSOR.REGISTER.UPDATE_INTERVAL + The number of nonces to process before checking for next block during registration + --subtensor.register.no_output_in_place, --no_output_in_place + Whether to not ouput the registration statistics in-place. Set flag to disable output in-place. + --subtensor.register.verbose + Whether to ouput the registration statistics verbosely. + --subtensor.register.cuda.use_cuda, --cuda, --cuda.use_cuda + Set flag to use CUDA to register. + --subtensor.register.cuda.no_cuda, --no_cuda, --cuda.no_cuda + Set flag to not use CUDA for registration + --subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...], --cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...] + Set the CUDA device id(s). Goes by the order of speed. (i.e. 0 is the fastest). + --subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB, --cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB + Set the number of Threads Per Block for CUDA. + --logging.debug Turn on bittensor debugging information + --logging.trace Turn on bittensor trace level information + --logging.record_log Turns on logging to file. + --logging.logging_dir LOGGING.LOGGING_DIR + Logging default root directory. + --config CONFIG If set, defaults are overridden by passed file. + --strict If flagged, config will check that only exact arguemnts have been set. +``` \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/oasst_pythia/neuron.py b/neurons/text/prompting/miners/huggingface/oasst_pythia/neuron.py new file mode 100644 index 0000000000..9e718eebbc --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/oasst_pythia/neuron.py @@ -0,0 +1,89 @@ +# The MIT License (MIT) +# Copyright © 2023 Opentensor Foundation + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import argparse +import bittensor +from typing import List, Dict +from transformers import AutoTokenizer, GPTNeoXForCausalLM +from transformers import StoppingCriteria, StoppingCriteriaList + +class StopOnTokens( StoppingCriteria ): + def __init__( self, stop_token_ids: List[int] = None ): + self.stop_token_ids = stop_token_ids + + def __call__( self, input_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs ) -> bool: + for stop_id in self.stop_token_ids: + if input_ids[0][-1] == stop_id: + return True + return False + +class OasstPythiaMiner( bittensor.HuggingFaceMiner ): + arg_prefix = 'oasst_pythia' + system_label = "<|system|>" + assistant_label = "<|assistant|>" + user_label = "<|prompter|>" + + def __init__( self ): + super( OasstPythiaMiner, self ).__init__() + self.stop = StopOnTokens( self.tokenizer.convert_tokens_to_ids( [ "<|endoftext|>" ] ) ) + + def load_tokenizer(self): + return AutoTokenizer.from_pretrained( self.config.oasst_pythia.model_name, torch_dtype=torch.bfloat16 ) + + def load_model( self ): + bittensor.logging.info( 'Loading ' + str( self.config.oasst_pythia.model_name ) ) + model = GPTNeoXForCausalLM.from_pretrained( + self.config.oasst_pythia.model_name, + device_map="auto", + low_cpu_mem_usage=True, + torch_dtype=torch.bfloat16 + ) + bittensor.logging.info( 'Model loaded!' ) + return model + + def forward( self, messages: List[Dict[str, str]] ): + history = self.process_history(messages) + prompt = history + self.assistant_label + + inputs = self.tokenizer( prompt, return_tensors="pt" ) + inputs = inputs.to( self.model.device ) + + gkw = { + **{ + "input_ids": inputs.input_ids, + "attention_mask": inputs.attention_mask, + "max_new_tokens": self.config.oasst_pythia.max_new_tokens, + "temperature": self.config.oasst_pythia.temperature, + "do_sample": self.config.oasst_pythia.do_sample, + "top_p": self.config.oasst_pythia.top_p, + "top_k": self.config.oasst_pythia.top_k, + "repetition_penalty": self.config.oasst_pythia.repetition_penalty, + "stopping_criteria": StoppingCriteriaList( [ self.stop ] ), + "pad_token_id": self.tokenizer.eos_token_id, + }, + } + output = self.model.generate( **gkw ) + generation = self.tokenizer.decode( output[0][inputs.input_ids.shape[1]:], skip_special_tokens=True ) + + bittensor.logging.debug( "Message: " + str(messages ) ) + bittensor.logging.debug( "Generation: " + str(generation ) ) + return generation + +if __name__ == "__main__": + bittensor.utils.version_checking() + OasstPythiaMiner().run() diff --git a/neurons/text/prompting/miners/vicuna/README.md b/neurons/text/prompting/miners/huggingface/open_llama/README.md similarity index 72% rename from neurons/text/prompting/miners/vicuna/README.md rename to neurons/text/prompting/miners/huggingface/open_llama/README.md index 4c1728c757..e81e38d306 100644 --- a/neurons/text/prompting/miners/vicuna/README.md +++ b/neurons/text/prompting/miners/huggingface/open_llama/README.md @@ -1,71 +1,38 @@ -## Vicuna Miner -Vicuna Language Model Serving with BitTensor -This code is for running the Vicuna model through the BitTensor framework. +## OpenLLaMA Miner +OpenLLaMA Language Model Serving with BitTensor +This code is for running the Open_llama model by OpenLM-Research through the BitTensor framework. # Overview ## Contents +- [Licence](#licence) +- [Model Download](#model-download) - [Installing Dependencies](#installing-dependencies) -- [Converting Weights Into Model](#converting-weights-into-model) - [Starting Miner](#starting-miner) +# Licence +Apache 2.0 (Open source and commercial purposes allowed) # Installing Dependencies ``` -python3 -m pip install -r neurons/text/prompting/miners/vicuna/requirements.txt +python3 -m pip install -r neurons/text/prompting/miners/huggingface/open_llama/requirements.txt ``` -# Converting Weights Into Model -If you already have a converted checkpoint of the model, you can skip this step. - -## Vicuna Weights -The [Vicuna](https://vicuna.lmsys.org/) weights as delta weights to comply with the LLaMA model license. -You can add our delta to the original LLaMA weights to obtain the Vicuna weights. Instructions: - -1. Get the original LLaMA weights in the huggingface format by following the instructions [here](https://huggingface.co/docs/transformers/main/model_doc/llama). -2. Use the following scripts to get Vicuna weights by applying our delta. They will automatically download delta weights from our Hugging Face [account](https://huggingface.co/lmsys). - -**NOTE**: -Weights v1.1 are only compatible with the latest main branch of huggingface/transformers and ``fschat >= 0.2.0``. -Please update your local packages accordingly. If you follow the above commands to do a fresh install, then you should get all the correct versions. - -Depending on which conversion script was used to create the Huggingface checkpoint of Llama, you might get an error that the tokenizer can not be found when loading the tokenizer. You can then replace all AutoTokenizers command with the correct tokenizer (in the example "LlamaTokenizer"), using this command: -``` -find /path/to/fastchat -type f -name '*.py' -exec sed -i 's/AutoTokenizer/LlamaTokenizer/g' {} + -``` - -### Vicuna-7B -This conversion command needs around 30 GB of CPU RAM. -If you do not have enough memory, you can create a large swap file that allows the operating system to automatically utilize the disk as virtual memory. -```bash -python3 -m fastchat.model.apply_delta \ - --base /path/to/llama-7b \ - --target /output/path/to/vicuna-7b \ - --delta lmsys/vicuna-7b-delta-v1.1 -``` - -### Vicuna-13B -This conversion command needs around 60 GB of CPU RAM. -If you do not have enough memory, you can create a large swap file that allows the operating system to automatically utilize the disk as virtual memory. -```bash -python3 -m fastchat.model.apply_delta \ - --base /path/to/llama-13b \ - --target /output/path/to/vicuna-13b \ - --delta lmsys/vicuna-13b-delta-v1.1 -``` +# Starting Miner +To start the miner, all you need to do is to specify the path to the model, or the name on Huggingface hub, and it will be downloaded. +You can find different model checkpoints by searching Huggingface, or by looking at OpenLM-Research's Huggingface page https://huggingface.co/openlm-research -# Starting Miner ``` -python3 neurons/text/prompting/miners/vicuna/neuron.py +python3 neurons/text/prompting/miners/huggingface/open_llama/neuron.py --open_llama.model_name OPEN_LLAMA.MODEL_NAME_OR_PATH ``` # Full Usage ``` -usage: neuron.py [-h] [--vicuna.model_name VICUNA.MODEL_NAME] [--vicuna.device VICUNA.DEVICE] [--vicuna.max_new_tokens VICUNA.MAX_NEW_TOKENS] - [--vicuna.temperature VICUNA.TEMPERATURE] [--vicuna.do_sample] [--netuid NETUID] [--neuron.name NEURON.NAME] +usage: neuron.py [-h] [--open_llama.model_name OPEN_LLAMA.MODEL_NAME] [--open_llama.device OPEN_LLAMA.DEVICE] [--open_llama.max_new_tokens OPEN_LLAMA.MAX_NEW_TOKENS] + [--open_llama.temperature OPEN_LLAMA.TEMPERATURE] [--open_llama.do_sample] [--netuid NETUID] [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] [--neuron.no_set_weights] [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS ...]] [--neuron.blacklist.allow_non_registered] @@ -87,13 +54,13 @@ optional arguments: -h, --help show this help message and exit --neoxt.model_name NEOXT.MODEL_NAME Name/path of model to load of model to load - --vicuna.device VICUNA.DEVICE + --open_llama.device OPEN_LLAMA.DEVICE Device to load model - --vicuna.max_new_tokens VICUNA.MAX_NEW_TOKENS + --open_llama.max_new_tokens OPEN_LLAMA.MAX_NEW_TOKENS Max tokens for model output. - --vicuna.temperature VICUNA.TEMPERATURE + --open_llama.temperature OPEN_LLAMA.TEMPERATURE Sampling temperature of model - --vicuna.do_sample Whether to use sampling or not (if not, uses greedy decoding). + --open_llama.do_sample Whether to use sampling or not (if not, uses greedy decoding). --netuid NETUID Subnet netuid --neuron.name NEURON.NAME Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name diff --git a/neurons/text/prompting/miners/huggingface/open_llama/neuron.py b/neurons/text/prompting/miners/huggingface/open_llama/neuron.py new file mode 100644 index 0000000000..e004009ffb --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/open_llama/neuron.py @@ -0,0 +1,60 @@ +# The MIT License (MIT) +# Copyright © 2021 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import bittensor +from typing import List, Dict +from transformers import LlamaForCausalLM, LlamaTokenizer + +class OpenLlamaMiner( bittensor.HuggingFaceMiner ): + arg_prefix = 'open_llama' + system_label = '\nSystem:' + assistant_label = '\nAssistant:' + user_label = '\nUser:' + + def load_tokenizer( self ): + return LlamaTokenizer.from_pretrained( self.config.open_llama.model_name, use_fast=False ) + + def load_model( self ): + return LlamaForCausalLM.from_pretrained( self.config.open_llama.model_name, torch_dtype = torch.float16, low_cpu_mem_usage=True ) + + def forward( self, messages: List[Dict[str, str]] ) -> str: + + history = self.process_history( messages ) + prompt = history + self.assistant_label + + input_ids = self.tokenizer.encode( prompt, return_tensors="pt" ).to( self.config.open_llama.device ) + output = self.model.generate( + input_ids, + max_length=input_ids.shape[1] + self.config.open_llama.max_new_tokens, + temperature=self.config.open_llama.temperature, + do_sample=self.config.open_llama.do_sample, + pad_token_id=self.tokenizer.eos_token_id, + ) + + generation = self.tokenizer.decode( output[0][input_ids.shape[1]:], skip_special_tokens=True ) + generation = generation.split( "User:" )[0].strip() + + # Logging input and generation if debugging is active + bittensor.logging.debug( "Prompt: " + str( prompt) ) + bittensor.logging.debug( "Message: " + str( messages ) ) + bittensor.logging.debug( "Generation: " + str( generation ).replace( "<", "-" ) ) + return generation + +if __name__ == "__main__": + bittensor.utils.version_checking() + OpenLlamaMiner().run() diff --git a/neurons/text/prompting/miners/huggingface/open_llama/requirements.txt b/neurons/text/prompting/miners/huggingface/open_llama/requirements.txt new file mode 100644 index 0000000000..98637aee3d --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/open_llama/requirements.txt @@ -0,0 +1,5 @@ +git+https://github.com/huggingface/transformers +sentencepiece +fschat +tokenizers>=0.13.3 +accelerate diff --git a/neurons/text/prompting/miners/huggingface/pythia/README.md b/neurons/text/prompting/miners/huggingface/pythia/README.md new file mode 100644 index 0000000000..b5f5af5daa --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/pythia/README.md @@ -0,0 +1,136 @@ +# Pythia Miner +togethercomputer/Pythia-7B Language Model Serving with BitTensor +This code is for running a language model powered by togethercomputer through the BitTensor framework. + +# Example Usage +``` +python3 -m pip install -r neurons/text/prompting/miners/huggingface/pythia/requirements.txt +python3 neurons/text/prompting/miners/huggingface/pythia/neuron.py --pythia.model_name togethercomputer/Pythia-Chat-Base-7B +``` + +# Full Usage +``` +usage: pythia_miner.py [-h] --pythia.model_name PYTHIA.MODEL_NAME [--pythia.device PYTHIA.DEVICE] [--pythia.max_new_tokens PYTHIA.MAX_NEW_TOKENS] + [--pythia.temperature PYTHIA.TEMPERATURE] [--pythia.do_sample] [--pythia.repetition_penalty PYTHIA.REPETITION_PENALTY] + [--pythia.do_prompt_injection] [--pythia.system_prompt PYTHIA.SYSTEM_PROMPT] + [--pythia.repetition-penalty PYTHIA.REPETITION_PENALTY] [--pythia.top_p PYTHIA.TOP_P] [--pythia.top_k PYTHIA.TOP_K] + [--pythia.load_in_8bit PYTHIA.LOAD_IN_8BIT] [--pythia.pad_tokens PYTHIA.PAD_TOKENS [PYTHIA.PAD_TOKENS ...]] + [--netuid NETUID] [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] [--neuron.no_set_weights] + [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] + [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]]] + [--neuron.blacklist.allow_non_registered] [--neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE] + [--neuron.default_priority NEURON.DEFAULT_PRIORITY] [--wallet.name WALLET.NAME] [--wallet.hotkey WALLET.HOTKEY] + [--wallet.path WALLET.PATH] [--wallet._mock] [--wallet.reregister WALLET.REREGISTER] + [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] + [--axon.port AXON.PORT] [--axon.ip AXON.IP] [--axon.external_port AXON.EXTERNAL_PORT] [--axon.external_ip AXON.EXTERNAL_IP] + [--axon.max_workers AXON.MAX_WORKERS] [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] + [--subtensor.network SUBTENSOR.NETWORK] [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] [--subtensor._mock] + [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] + [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] [--subtensor.register.no_output_in_place] + [--subtensor.register.verbose] [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] + [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] + [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] [--logging.debug] [--logging.trace] [--logging.record_log] + [--logging.logging_dir LOGGING.LOGGING_DIR] [--config CONFIG] [--strict] + +optional arguments: + -h, --help show this help message and exit + --pythia.model_name PYTHIA.MODEL_NAME + Name or path of model to load + --pythia.device PYTHIA.DEVICE + Device to load model + --pythia.max_new_tokens PYTHIA.MAX_NEW_TOKENS + Max tokens for model output. + --pythia.temperature PYTHIA.TEMPERATURE + Sampling temperature of model + --pythia.do_sample Whether to use multinomial sampling. + --pythia.repetition_penalty PYTHIA.REPETITION_PENALTY + Repetition penalty for model + --pythia.do_prompt_injection + Whether to use a custom "system" prompt instead of the one sent by bittensor. + --pythia.system_prompt PYTHIA.SYSTEM_PROMPT + What prompt to replace the system prompt with + --pythia.repetition-penalty PYTHIA.REPETITION_PENALTY + Repetition penalty for greedy decoding. Between 1.0 and infinity. 1.0 means no penalty. Default: 1.0 + --pythia.top_p PYTHIA.TOP_P + Top-p (nucleus) sampling. Defaults to 1.0 (top-k sampling). Must be between 0.0 and 1.0. + --pythia.top_k PYTHIA.TOP_K + Top-k sampling. Defaults to 0 (no top-k sampling). Must be between 0 and 1000. + --pythia.load_in_8bit PYTHIA.LOAD_IN_8BIT + Load model in 8 bit precision + --pythia.pad_tokens PYTHIA.PAD_TOKENS [PYTHIA.PAD_TOKENS ...] + A list of integers separated by spaces for the pad_tokens. + --netuid NETUID Subnet netuid + --neuron.name NEURON.NAME + Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name + --neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH + Blocks until the miner sets weights on chain + --neuron.no_set_weights + If True, the model does not set weights. + --neuron.max_batch_size NEURON.MAX_BATCH_SIZE + The maximum batch size for forward requests. + --neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN + The maximum sequence length for forward requests. + --neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]] + To blacklist certain hotkeys + --neuron.blacklist.allow_non_registered + If True, the miner will allow non-registered hotkeys to mine. + --neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE + Set default stake for miners. + --neuron.default_priority NEURON.DEFAULT_PRIORITY + Set default priority for miners. + --wallet.name WALLET.NAME + The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet) + --wallet.hotkey WALLET.HOTKEY + The name of wallet's hotkey. + --wallet.path WALLET.PATH + The path to your bittensor wallets + --wallet._mock To turn on wallet mocking for testing purposes. + --wallet.reregister WALLET.REREGISTER + Whether to reregister the wallet if it is not already registered. + --axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS + maximum number of threads in thread pool + --axon.priority.maxsize AXON.PRIORITY.MAXSIZE + maximum size of tasks in priority queue + --axon.port AXON.PORT + The local port this axon endpoint is bound to. i.e. 8091 + --axon.ip AXON.IP The local ip this axon binds to. ie. [::] + --axon.external_port AXON.EXTERNAL_PORT + The public port this axon broadcasts to the network. i.e. 8091 + --axon.external_ip AXON.EXTERNAL_IP + The external ip this axon broadcasts to the network to. ie. [::] + --axon.max_workers AXON.MAX_WORKERS + The maximum number connection handler threads working simultaneously on this endpoint. The grpc server distributes new + worker threads to service requests up to this number. + --axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS + Maximum number of allowed active connections + --subtensor.network SUBTENSOR.NETWORK + The subtensor network flag. The likely choices are: -- finney (main network) -- local (local running network) -- mock + (creates a mock connection (for testing)) If this option is set it overloads subtensor.chain_endpoint with an entry point + node from that network. + --subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT + The subtensor endpoint flag. If set, overrides the --network flag. + --subtensor._mock To turn on subtensor mocking for testing purposes. + --subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES, -n SUBTENSOR.REGISTER.NUM_PROCESSES + Number of processors to use for registration + --subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --subtensor.register.cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, -u SUBTENSOR.REGISTER.UPDATE_INTERVAL + The number of nonces to process before checking for next block during registration + --subtensor.register.no_output_in_place, --no_output_in_place + Whether to not ouput the registration statistics in-place. Set flag to disable output in-place. + --subtensor.register.verbose + Whether to ouput the registration statistics verbosely. + --subtensor.register.cuda.use_cuda, --cuda, --cuda.use_cuda + Set flag to use CUDA to register. + --subtensor.register.cuda.no_cuda, --no_cuda, --cuda.no_cuda + Set flag to not use CUDA for registration + --subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...], --cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...] + Set the CUDA device id(s). Goes by the order of speed. (i.e. 0 is the fastest). + --subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB, --cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB + Set the number of Threads Per Block for CUDA. + --logging.debug Turn on bittensor debugging information + --logging.trace Turn on bittensor trace level information + --logging.record_log Turns on logging to file. + --logging.logging_dir LOGGING.LOGGING_DIR + Logging default root directory. + --config CONFIG If set, defaults are overridden by passed file. + --strict If flagged, config will check that only exact arguemnts have been set. + ``` \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/pythia/neuron.py b/neurons/text/prompting/miners/huggingface/pythia/neuron.py new file mode 100644 index 0000000000..65d5620ff8 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/pythia/neuron.py @@ -0,0 +1,56 @@ +# The MIT License (MIT) +# Copyright © 2023 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import bittensor +from typing import List, Dict +from transformers import AutoTokenizer, AutoModelForCausalLM + +class PythiaMiner( bittensor.HuggingFaceMiner ): + + arg_prefix: str = 'pythia' + assistant_label: str = ':' + user_label: str = ':' + system_label: str = '' + + def load_tokenizer( self ): + return AutoTokenizer.from_pretrained( self.config.pythia.model_name ) + + def load_model( self ): + return AutoModelForCausalLM.from_pretrained( self.config.pythia.model_name, torch_dtype = torch.float16, low_cpu_mem_usage=True ) + + def forward(self, messages: List[Dict[str, str]]) -> str: + history = self.process_history( messages ) + prompt = history + self.assistant_label + input_ids = self.tokenizer.encode( prompt, return_tensors="pt" ).to( self.config.pythia.device ) + output = self.model.generate( + input_ids, + max_length=input_ids.shape[1] + self.config.pythia.max_new_tokens, + temperature=self.config.pythia.temperature, + do_sample=self.config.pythia.do_sample, + pad_token_id=self.tokenizer.eos_token_id, + ) + generated_text = self.tokenizer.decode( output[0][input_ids.shape[1]:], skip_special_tokens=True ) + generation = generated_text.split( "" )[0].strip() + + bittensor.logging.debug("Message: " + str( messages ).replace( "<","-" ).replace( ">","-" ) ) + bittensor.logging.debug("Generation: " + str( generation ).replace( "<","-" ).replace( ">","-" ) ) + return generation + +if __name__ == "__main__": + bittensor.utils.version_checking() + PythiaMiner().run() \ No newline at end of file diff --git a/neurons/text/prompting/miners/pythia/requirements.txt b/neurons/text/prompting/miners/huggingface/pythia/requirements.txt similarity index 100% rename from neurons/text/prompting/miners/pythia/requirements.txt rename to neurons/text/prompting/miners/huggingface/pythia/requirements.txt diff --git a/neurons/text/prompting/miners/huggingface/raven/README.md b/neurons/text/prompting/miners/huggingface/raven/README.md new file mode 100644 index 0000000000..d931a450cb --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/raven/README.md @@ -0,0 +1,143 @@ +# Raven RWKV Miner +BlinkDL/Raven-RWKV-7B Language Model Serving with BitTensor +This code is for running a language model powered by BlinkDL through the BitTensor framework. + +## Setup +Go to the huggingface repo for more information: [rwkv-4-raven](https://huggingface.co/BlinkDL/rwkv-4-raven) + +NOTE: You need to pass the path to the tokenizer.json from the command line. +- Find it [here](https://huggingface.co/spaces/BlinkDL/Raven-RWKV-7B/resolve/main/20B_tokenizer.json) + +NOTE: You will want to browse and see what Raven model you wish to load [here](https://huggingface.co/BlinkDL/rwkv-4-raven/tree/main) +e.g. `RWKV-4-Raven-7B-v11-Eng99%25-Other1%25-20230427-ctx8192` for Engligh 99% and Other languages 1%= +e.g. `RWKV-4-Raven-7B-v11-Eng49%-Chn49%-Jpn1%-Other1%-20230430-ctx8192` for 49% English, 49% Chinese, 1% Japanese + +These percentages refer to the amount of training data from that particular language. + +# Usage +``` +wget https://huggingface.co/spaces/BlinkDL/Raven-RWKV-7B/resolve/main/20B_tokenizer.json +python3 -m pip install -r neurons/text/prompting/miners/huggingface/raven-rwkv/requirements.txt +python3 neurons/text/prompting/miners/huggingface/raven-rwkv/neuron.py --raven.tokenizer_path /home/jason/bittensor/20B_tokenizer.json \ + --raven.model_name RWKV-4-Raven-7B-v11x-Eng99%-Other1%-20230429-ctx8192 \ + --raven.repetition-penalty 0.2 --raven.top_p 0.0 --raven.temperature 1.0 +``` + +# Full Usage +``` +usage: neuron.py [-h] [--raven.model_name RAVEN.MODEL_NAME] [--raven.repo_id RAVEN.REPO_ID] [--raven.tokenizer_path RAVEN.TOKENIZER_PATH] [--raven.device RAVEN.DEVICE] [--raven.ctx_limit RAVEN.CTX_LIMIT] [--raven.max_new_tokens RAVEN.MAX_NEW_TOKENS] + [--raven.temperature RAVEN.TEMPERATURE] [--raven.top_p RAVEN.TOP_P] [--raven.do_prompt_injection] [--raven.system_prompt RAVEN.SYSTEM_PROMPT] [--raven.jit_on] [--raven.cuda_on] [--raven.strategy RAVEN.STRATEGY] + [--raven.pad_tokens RAVEN.PAD_TOKENS [RAVEN.PAD_TOKENS ...]] [--raven.repetition_penalty RAVEN.REPETITION_PENALTY] [--netuid NETUID] [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] [--neuron.no_set_weights] + [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]]] [--neuron.blacklist.allow_non_registered] + [--neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE] [--neuron.blacklist.vpermit_required] [--neuron.default_priority NEURON.DEFAULT_PRIORITY] [--wallet.name WALLET.NAME] [--wallet.hotkey WALLET.HOTKEY] [--wallet.path WALLET.PATH] [--wallet._mock] + [--wallet.reregister WALLET.REREGISTER] [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] [--axon.port AXON.PORT] [--axon.ip AXON.IP] [--axon.external_port AXON.EXTERNAL_PORT] + [--axon.external_ip AXON.EXTERNAL_IP] [--axon.max_workers AXON.MAX_WORKERS] [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] [--subtensor.network SUBTENSOR.NETWORK] [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] [--subtensor._mock] + [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] [--subtensor.register.no_output_in_place] [--subtensor.register.verbose] [--subtensor.register.cuda.use_cuda] + [--subtensor.register.cuda.no_cuda] [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] [--logging.debug] [--logging.trace] [--logging.record_log] + [--logging.logging_dir LOGGING.LOGGING_DIR] [--config CONFIG] [--strict] + +optional arguments: + -h, --help show this help message and exit + --raven.model_name RAVEN.MODEL_NAME + Name/path of model to load + --raven.repo_id RAVEN.REPO_ID + Repo id of model to load + --raven.tokenizer_path RAVEN.TOKENIZER_PATH + Path to tokenizer json file + --raven.device RAVEN.DEVICE + Device to load model + --raven.ctx_limit RAVEN.CTX_LIMIT + Max context length for model input. + --raven.max_new_tokens RAVEN.MAX_NEW_TOKENS + Max tokens for model output. + --raven.temperature RAVEN.TEMPERATURE + Sampling temperature of model + --raven.top_p RAVEN.TOP_P + Top p sampling of model + --raven.do_prompt_injection + Whether to use a custom "system" prompt instead of the one sent by bittensor. + --raven.system_prompt RAVEN.SYSTEM_PROMPT + What prompt to replace the system prompt with + --raven.jit_on Whether to use Just-In-Time complication (JIT) + --raven.cuda_on Whether to use CUDA kernel for seq mode (much faster). [Requires CUDA_HOME env_variable to be set] + --raven.strategy RAVEN.STRATEGY + Strategy to use for RWKV model + --raven.pad_tokens RAVEN.PAD_TOKENS [RAVEN.PAD_TOKENS ...] + A list of integers separated by spaces for the pad_tokens. + --raven.repetition_penalty RAVEN.REPETITION_PENALTY + Repetition penalty for RWKV model + --netuid NETUID Subnet netuid + --neuron.name NEURON.NAME + Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name + --neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH + Blocks until the miner sets weights on chain + --neuron.no_set_weights + If True, the model does not set weights. + --neuron.max_batch_size NEURON.MAX_BATCH_SIZE + The maximum batch size for forward requests. + --neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN + The maximum sequence length for forward requests. + --neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]] + To blacklist certain hotkeys + --neuron.blacklist.allow_non_registered + If True, this miner will allow non-registered hotkeys to query it. + --neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE + Set default stake for miners. + --neuron.blacklist.vpermit_required + Require vpermit to query this miner. + --neuron.default_priority NEURON.DEFAULT_PRIORITY + Set default priority for miners. + --wallet.name WALLET.NAME + The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet) + --wallet.hotkey WALLET.HOTKEY + The name of wallet's hotkey. + --wallet.path WALLET.PATH + The path to your bittensor wallets + --wallet._mock To turn on wallet mocking for testing purposes. + --wallet.reregister WALLET.REREGISTER + Whether to reregister the wallet if it is not already registered. + --axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS + maximum number of threads in thread pool + --axon.priority.maxsize AXON.PRIORITY.MAXSIZE + maximum size of tasks in priority queue + --axon.port AXON.PORT + The local port this axon endpoint is bound to. i.e. 8091 + --axon.ip AXON.IP The local ip this axon binds to. ie. [::] + --axon.external_port AXON.EXTERNAL_PORT + The public port this axon broadcasts to the network. i.e. 8091 + --axon.external_ip AXON.EXTERNAL_IP + The external ip this axon broadcasts to the network to. ie. [::] + --axon.max_workers AXON.MAX_WORKERS + The maximum number connection handler threads working simultaneously on this endpoint. The grpc server distributes new worker threads to service requests up to this number. + --axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS + Maximum number of allowed active connections + --subtensor.network SUBTENSOR.NETWORK + The subtensor network flag. The likely choices are: -- finney (main network) -- local (local running network) -- mock (creates a mock connection (for testing)) If this option is set it overloads subtensor.chain_endpoint with an entry point node from that + network. + --subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT + The subtensor endpoint flag. If set, overrides the --network flag. + --subtensor._mock To turn on subtensor mocking for testing purposes. + --subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES, -n SUBTENSOR.REGISTER.NUM_PROCESSES + Number of processors to use for registration + --subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --subtensor.register.cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, -u SUBTENSOR.REGISTER.UPDATE_INTERVAL + The number of nonces to process before checking for next block during registration + --subtensor.register.no_output_in_place, --no_output_in_place + Whether to not ouput the registration statistics in-place. Set flag to disable output in-place. + --subtensor.register.verbose + Whether to ouput the registration statistics verbosely. + --subtensor.register.cuda.use_cuda, --cuda, --cuda.use_cuda + Set flag to use CUDA to register. + --subtensor.register.cuda.no_cuda, --no_cuda, --cuda.no_cuda + Set flag to not use CUDA for registration + --subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...], --cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...] + Set the CUDA device id(s). Goes by the order of speed. (i.e. 0 is the fastest). + --subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB, --cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB + Set the number of Threads Per Block for CUDA. + --logging.debug Turn on bittensor debugging information + --logging.trace Turn on bittensor trace level information + --logging.record_log Turns on logging to file. + --logging.logging_dir LOGGING.LOGGING_DIR + Logging default root directory. + --config CONFIG If set, defaults are overridden by passed file. + --strict If flagged, config will check that only exact arguemnts have been set. + ``` \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/raven/neuron.py b/neurons/text/prompting/miners/huggingface/raven/neuron.py new file mode 100644 index 0000000000..a050ab8fa9 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/raven/neuron.py @@ -0,0 +1,102 @@ +import os +import argparse +import bittensor +from typing import List, Dict +from huggingface_hub import hf_hub_download +from rwkv.model import RWKV +from rwkv.utils import PIPELINE + +class RavenMiner( bittensor.HuggingFaceMiner ): + + arg_prefix = 'raven' + system_label = "" + assistant_label = "Alice:" + user_label = "Bob:" + + @classmethod + def add_args( cls, parser: argparse.ArgumentParser ): + super( RavenMiner, cls ).add_args( parser ) + parser.add_argument( '--raven.repo_id', type=str, default="BlinkDL/rwkv-4-raven", help='Repo id of model to load' ) + parser.add_argument( '--raven.tokenizer_path', type=str, required=True, help='Path to tokenizer json file' ) + parser.add_argument( '--raven.ctx_limit', type=int, help='Max context length for model input.', default=1536 ) + parser.add_argument( '--raven.jit_on', action='store_true', default=False, help='Whether to use Just-In-Time complication (JIT)' ) + parser.add_argument( '--raven.cuda_on', action='store_true', default=False, help='Whether to use CUDA kernel for seq mode (much faster). [Requires CUDA_HOME env_variable to be set]' ) + parser.add_argument( '--raven.strategy', type=str, default='cuda fp16i8 *8 -> cuda fp16', help='Strategy to use for RWKV model') + + def __init__(self): + super( RavenMiner, self ).__init__() + + def load_model( self ): + model_path = hf_hub_download( repo_id=self.config.raven.repo_id, filename=f"{self.config.raven.model_name}.pth" ) + model = RWKV( model=model_path, strategy=self.config.raven.strategy ) + return PIPELINE( model, self.config.raven.tokenizer_path ) + + def load_tokenizer( self ): + pass + + os.environ["RWKV_JIT_ON"] = '1' if self.config.raven.jit_on else '0' + os.environ["RWKV_CUDA_ON"] = '1' if self.config.raven.cuda_on else '0' + + def forward( self, messages: List[Dict[str, str]] ) -> str: + history = self.process_history( messages ) + + out_tokens = [] + out_last = 0 + generation = '' + occurrence = {} + state = None + for i in range( self.config.raven.max_new_tokens ): + tokens = self.config.raven.pad_tokens + self.model.encode( history ) if i == 0 else [token] + + out, state = self.model.model.forward(tokens, state) + for n in occurrence: + out[n] -= ( self.config.raven.repetition_penalty + occurrence[n] * self.config.raven.repetition_penalty ) + + token = self.model.sample_logits( out, temperature=self.config.raven.temperature, top_p=self.config.raven.top_p ) + if token == 0: break # exit when 'endoftext' + + out_tokens += [token] + occurrence[token] = 1 + ( occurrence[token] if token in occurrence else 0 ) + + tmp = self.model.decode( out_tokens[out_last:] ) + if ( '\ufffd' not in tmp ) and ( not tmp.endswith('\n') ): + generation += tmp + out_last = i + 1 + + if '\n\n' in tmp: # exit when '\n\n' + generation += tmp + generation = generation.strip() + break + + bittensor.logging.debug( "Message: " + str( messages ) ) + bittensor.logging.debug( "Generation: " + str( generation ) ) + return generation + + +if __name__ == "__main__": + bittensor.utils.version_checking() + RavenMiner().run() + +def test_miner( model ): + prompt = """ + You are George Carlin. + George Carlin is a comedian known for his witty, cutting, poignant observational comedy. + He is also known for his social commentary, philosophy, and cutting remarks on religion. + Write a joke about the following topic: + """ + + message = "who am I, really?" + + if prompt is not None: + roles = ['system', 'user'] + messages = [ prompt, message ] + else: + roles = ['user'] + messages = [ message ] + + messages = [{'role': role, 'content': message} for role, message in zip(roles, messages)] + + return model.forward( messages ) + +miner = RavenMiner() +print( test_miner(miner) ) \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/raven/requirements.txt b/neurons/text/prompting/miners/huggingface/raven/requirements.txt new file mode 100644 index 0000000000..2573350bcc --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/raven/requirements.txt @@ -0,0 +1,2 @@ +rwkv +huggingface_hub \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/robertmyers/README.md b/neurons/text/prompting/miners/huggingface/robertmyers/README.md new file mode 100644 index 0000000000..965e435fc4 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/robertmyers/README.md @@ -0,0 +1,140 @@ + +## RoberMyers Miner +Robert myers completion miner for bittensor's prompting network. + +# Example Usage +``` +python3 -m pip install -r neurons/text/prompting/miners/huggingface/robertmyers/requirements.txt +python3 neurons/text/prompting/miners/huggingface/robertmyers/neuron.py --robertmyers.model_name robertmyers/bpt-sft +``` + +# Full Usage +``` +usage: robertmyers_miner.py [-h] --robertmyers.model_name ROBERTMYERS.MODEL_NAME [--robertmyers.device ROBERTMYERS.DEVICE] + [--robertmyers.max_new_tokens ROBERTMYERS.MAX_NEW_TOKENS] [--robertmyers.temperature ROBERTMYERS.TEMPERATURE] + [--robertmyers.do_sample] [--robertmyers.repetition_penalty ROBERTMYERS.REPETITION_PENALTY] + [--robertmyers.do_prompt_injection] [--robertmyers.system_prompt ROBERTMYERS.SYSTEM_PROMPT] + [--robertmyers.repetition-penalty ROBERTMYERS.REPETITION_PENALTY] [--robertmyers.top_p ROBERTMYERS.TOP_P] + [--robertmyers.top_k ROBERTMYERS.TOP_K] [--robertmyers.load_in_8bit ROBERTMYERS.LOAD_IN_8BIT] + [--robertmyers.pad_tokens ROBERTMYERS.PAD_TOKENS [ROBERTMYERS.PAD_TOKENS ...]] [--netuid NETUID] + [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] [--neuron.no_set_weights] + [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] + [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]]] + [--neuron.blacklist.allow_non_registered] [--neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE] + [--neuron.default_priority NEURON.DEFAULT_PRIORITY] [--wallet.name WALLET.NAME] [--wallet.hotkey WALLET.HOTKEY] + [--wallet.path WALLET.PATH] [--wallet._mock] [--wallet.reregister WALLET.REREGISTER] + [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] + [--axon.port AXON.PORT] [--axon.ip AXON.IP] [--axon.external_port AXON.EXTERNAL_PORT] + [--axon.external_ip AXON.EXTERNAL_IP] [--axon.max_workers AXON.MAX_WORKERS] + [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] [--subtensor.network SUBTENSOR.NETWORK] + [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] [--subtensor._mock] + [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] + [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] [--subtensor.register.no_output_in_place] + [--subtensor.register.verbose] [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] + [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] + [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] [--logging.debug] [--logging.trace] [--logging.record_log] + [--logging.logging_dir LOGGING.LOGGING_DIR] [--config CONFIG] [--strict] + +optional arguments: + -h, --help show this help message and exit + --robertmyers.model_name ROBERTMYERS.MODEL_NAME + Name or path of model to load + --robertmyers.device ROBERTMYERS.DEVICE + Device to load model + --robertmyers.max_new_tokens ROBERTMYERS.MAX_NEW_TOKENS + Max tokens for model output. + --robertmyers.temperature ROBERTMYERS.TEMPERATURE + Sampling temperature of model + --robertmyers.do_sample + Whether to use multinomial sampling. + --robertmyers.repetition_penalty ROBERTMYERS.REPETITION_PENALTY + Repetition penalty for model + --robertmyers.do_prompt_injection + Whether to use a custom "system" prompt instead of the one sent by bittensor. + --robertmyers.system_prompt ROBERTMYERS.SYSTEM_PROMPT + What prompt to replace the system prompt with + --robertmyers.repetition-penalty ROBERTMYERS.REPETITION_PENALTY + Repetition penalty for greedy decoding. Between 1.0 and infinity. 1.0 means no penalty. Default: 1.0 + --robertmyers.top_p ROBERTMYERS.TOP_P + Top-p (nucleus) sampling. Defaults to 1.0 (top-k sampling). Must be between 0.0 and 1.0. + --robertmyers.top_k ROBERTMYERS.TOP_K + Top-k sampling. Defaults to 0 (no top-k sampling). Must be between 0 and 1000. + --robertmyers.load_in_8bit ROBERTMYERS.LOAD_IN_8BIT + Load model in 8 bit precision + --robertmyers.pad_tokens ROBERTMYERS.PAD_TOKENS [ROBERTMYERS.PAD_TOKENS ...] + A list of integers separated by spaces for the pad_tokens. + --netuid NETUID Subnet netuid + --neuron.name NEURON.NAME + Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name + --neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH + Blocks until the miner sets weights on chain + --neuron.no_set_weights + If True, the model does not set weights. + --neuron.max_batch_size NEURON.MAX_BATCH_SIZE + The maximum batch size for forward requests. + --neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN + The maximum sequence length for forward requests. + --neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]] + To blacklist certain hotkeys + --neuron.blacklist.allow_non_registered + If True, the miner will allow non-registered hotkeys to mine. + --neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE + Set default stake for miners. + --neuron.default_priority NEURON.DEFAULT_PRIORITY + Set default priority for miners. + --wallet.name WALLET.NAME + The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet) + --wallet.hotkey WALLET.HOTKEY + The name of wallet's hotkey. + --wallet.path WALLET.PATH + The path to your bittensor wallets + --wallet._mock To turn on wallet mocking for testing purposes. + --wallet.reregister WALLET.REREGISTER + Whether to reregister the wallet if it is not already registered. + --axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS + maximum number of threads in thread pool + --axon.priority.maxsize AXON.PRIORITY.MAXSIZE + maximum size of tasks in priority queue + --axon.port AXON.PORT + The local port this axon endpoint is bound to. i.e. 8091 + --axon.ip AXON.IP The local ip this axon binds to. ie. [::] + --axon.external_port AXON.EXTERNAL_PORT + The public port this axon broadcasts to the network. i.e. 8091 + --axon.external_ip AXON.EXTERNAL_IP + The external ip this axon broadcasts to the network to. ie. [::] + --axon.max_workers AXON.MAX_WORKERS + The maximum number connection handler threads working simultaneously on this endpoint. The grpc server distributes new + worker threads to service requests up to this number. + --axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS + Maximum number of allowed active connections + --subtensor.network SUBTENSOR.NETWORK + The subtensor network flag. The likely choices are: -- finney (main network) -- local (local running network) -- mock + (creates a mock connection (for testing)) If this option is set it overloads subtensor.chain_endpoint with an entry point + node from that network. + --subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT + The subtensor endpoint flag. If set, overrides the --network flag. + --subtensor._mock To turn on subtensor mocking for testing purposes. + --subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES, -n SUBTENSOR.REGISTER.NUM_PROCESSES + Number of processors to use for registration + --subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --subtensor.register.cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, -u SUBTENSOR.REGISTER.UPDATE_INTERVAL + The number of nonces to process before checking for next block during registration + --subtensor.register.no_output_in_place, --no_output_in_place + Whether to not ouput the registration statistics in-place. Set flag to disable output in-place. + --subtensor.register.verbose + Whether to ouput the registration statistics verbosely. + --subtensor.register.cuda.use_cuda, --cuda, --cuda.use_cuda + Set flag to use CUDA to register. + --subtensor.register.cuda.no_cuda, --no_cuda, --cuda.no_cuda + Set flag to not use CUDA for registration + --subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...], --cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...] + Set the CUDA device id(s). Goes by the order of speed. (i.e. 0 is the fastest). + --subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB, --cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB + Set the number of Threads Per Block for CUDA. + --logging.debug Turn on bittensor debugging information + --logging.trace Turn on bittensor trace level information + --logging.record_log Turns on logging to file. + --logging.logging_dir LOGGING.LOGGING_DIR + Logging default root directory. + --config CONFIG If set, defaults are overridden by passed file. + --strict If flagged, config will check that only exact arguemnts have been set. +``` \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/robertmyers/neuron.py b/neurons/text/prompting/miners/huggingface/robertmyers/neuron.py new file mode 100644 index 0000000000..2cbd84c6d4 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/robertmyers/neuron.py @@ -0,0 +1,51 @@ +# The MIT License (MIT) +# Copyright © 2021 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +# General. +import torch +import bittensor +from typing import List, Dict +from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline + +class RobertMyersMiner( bittensor.HuggingFaceMiner ): + + arg_prefix: str = 'robertmyers' + system_label: str = 'system:' + assistant_label: str = 'assistant:' + user_label: str = 'user:' + + def load_tokenizer( self ): + return AutoTokenizer.from_pretrained( self.config.robertmyers.model_name ) + + def load_model( self ): + model = AutoModelForCausalLM.from_pretrained( self.config.robertmyers.model_name, torch_dtype=torch.float16 ) + model.to( self.config.robertmyers.device ) + return pipeline( + "text-generation", model, tokenizer=self.tokenizer, + device = 0, max_new_tokens = self.config.robertmyers.max_new_tokens, + temperature = self.config.robertmyers.temperature, + do_sample = self.config.robertmyers.do_sample, pad_token_id = self.tokenizer.eos_token_id + ) + + def forward( self, messages: List[Dict[str, str]] ) -> str: + history = self.process_history( messages ) + resp = self.model( history )[0]['generated_text'].split(':')[-1].replace( str( history ), "") + return resp + +if __name__ == "__main__": + bittensor.utils.version_checking() + RobertMyersMiner().run() \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/robertmyers/requirements.txt b/neurons/text/prompting/miners/huggingface/robertmyers/requirements.txt new file mode 100644 index 0000000000..bab195ea3c --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/robertmyers/requirements.txt @@ -0,0 +1 @@ +xformers \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/stabilityai/README.md b/neurons/text/prompting/miners/huggingface/stabilityai/README.md new file mode 100644 index 0000000000..f77f615690 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/stabilityai/README.md @@ -0,0 +1,158 @@ +## StabilityAI Miner +StabilityAI 7B completion miner for bittensor's prompting network. + +# Example Usage +``` +python3 -m pip install -r neurons/text/prompting/miners/huggingface/stabilityai/requirements.txt +python3 neurons/text/prompting/miners/huggingface/stabilityai/neuron.py --stabilityai.model_size 7 # for 7B model + +# Some suggested settings +python3 neurons/text/prompting/miners/huggingface/stabilityai/neuron.py --stabilityai.temperature 1.0 --stabilityai.top_k 10 --stabilityai.top_p 0.95 --stabilityai.do_sample +``` + +# Full Usage +``` +usage: stabilityai_miner.py [-h] [--stabilityai.model_name STABILITYAI.MODEL_NAME] [--stabilityai.api_key STABILITYAI.API_KEY] + [--stabilityai.device STABILITYAI.DEVICE] [--stabilityai.max_new_tokens STABILITYAI.MAX_NEW_TOKENS] + [--stabilityai.temperature STABILITYAI.TEMPERATURE] [--stabilityai.do_sample] + [--stabilityai.repetition_penalty STABILITYAI.REPETITION_PENALTY] [--stabilityai.do_prompt_injection] + [--stabilityai.system_prompt STABILITYAI.SYSTEM_PROMPT] + [--stabilityai.repetition-penalty STABILITYAI.REPETITION_PENALTY] [--stabilityai.top_p STABILITYAI.TOP_P] + [--stabilityai.top_k STABILITYAI.TOP_K] [--stabilityai.load_in_8bit STABILITYAI.LOAD_IN_8BIT] + [--stabilityai.pad_tokens STABILITYAI.PAD_TOKENS [STABILITYAI.PAD_TOKENS ...]] [--stabilityai.model_size {3,7}] + [--stabilityai.suffix STABILITYAI.SUFFIX] [--stabilityai.num_return_sequences STABILITYAI.NUM_RETURN_SEQUENCES] + [--stabilityai.num_beams STABILITYAI.NUM_BEAMS] [--stabilityai.stopping_criteria STABILITYAI.STOPPING_CRITERIA] + [--netuid NETUID] [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] + [--neuron.no_set_weights] [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] + [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] + [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]]] + [--neuron.blacklist.allow_non_registered] [--neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE] + [--neuron.default_priority NEURON.DEFAULT_PRIORITY] [--wallet.name WALLET.NAME] [--wallet.hotkey WALLET.HOTKEY] + [--wallet.path WALLET.PATH] [--wallet._mock] [--wallet.reregister WALLET.REREGISTER] + [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] + [--axon.port AXON.PORT] [--axon.ip AXON.IP] [--axon.external_port AXON.EXTERNAL_PORT] + [--axon.external_ip AXON.EXTERNAL_IP] [--axon.max_workers AXON.MAX_WORKERS] + [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] [--subtensor.network SUBTENSOR.NETWORK] + [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] [--subtensor._mock] + [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] + [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] [--subtensor.register.no_output_in_place] + [--subtensor.register.verbose] [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] + [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] + [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] [--logging.debug] [--logging.trace] [--logging.record_log] + [--logging.logging_dir LOGGING.LOGGING_DIR] [--config CONFIG] [--strict] + +optional arguments: + -h, --help show this help message and exit + --stabilityai.model_name STABILITYAI.MODEL_NAME + Name or path of model to load + --stabilityai.api_key STABILITYAI.API_KEY + huggingface api key + --stabilityai.device STABILITYAI.DEVICE + Device to load model + --stabilityai.max_new_tokens STABILITYAI.MAX_NEW_TOKENS + Max tokens for model output. + --stabilityai.temperature STABILITYAI.TEMPERATURE + Sampling temperature of model + --stabilityai.do_sample + Whether to use multinomial sampling. + --stabilityai.repetition_penalty STABILITYAI.REPETITION_PENALTY + Repetition penalty for model + --stabilityai.do_prompt_injection + Whether to use a custom "system" prompt instead of the one sent by bittensor. + --stabilityai.system_prompt STABILITYAI.SYSTEM_PROMPT + What prompt to replace the system prompt with + --stabilityai.repetition-penalty STABILITYAI.REPETITION_PENALTY + Repetition penalty for greedy decoding. Between 1.0 and infinity. 1.0 means no penalty. Default: 1.0 + --stabilityai.top_p STABILITYAI.TOP_P + Top-p (nucleus) sampling. Defaults to 1.0 (top-k sampling). Must be between 0.0 and 1.0. + --stabilityai.top_k STABILITYAI.TOP_K + Top-k sampling. Defaults to 0 (no top-k sampling). Must be between 0 and 1000. + --stabilityai.load_in_8bit STABILITYAI.LOAD_IN_8BIT + Load model in 8 bit precision + --stabilityai.pad_tokens STABILITYAI.PAD_TOKENS [STABILITYAI.PAD_TOKENS ...] + A list of integers separated by spaces for the pad_tokens. + --stabilityai.model_size {3,7} + Run the 3B or 7B model. + --stabilityai.suffix STABILITYAI.SUFFIX + The suffix that comes after a completion of inserted text. + --stabilityai.num_return_sequences STABILITYAI.NUM_RETURN_SEQUENCES + Description of num_return_sequences + --stabilityai.num_beams STABILITYAI.NUM_BEAMS + Description of num_beams + --stabilityai.stopping_criteria STABILITYAI.STOPPING_CRITERIA + Description of stopping_criteria + --netuid NETUID Subnet netuid + --neuron.name NEURON.NAME + Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name + --neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH + Blocks until the miner sets weights on chain + --neuron.no_set_weights + If True, the model does not set weights. + --neuron.max_batch_size NEURON.MAX_BATCH_SIZE + The maximum batch size for forward requests. + --neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN + The maximum sequence length for forward requests. + --neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]] + To blacklist certain hotkeys + --neuron.blacklist.allow_non_registered + If True, the miner will allow non-registered hotkeys to mine. + --neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE + Set default stake for miners. + --neuron.default_priority NEURON.DEFAULT_PRIORITY + Set default priority for miners. + --wallet.name WALLET.NAME + The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet) + --wallet.hotkey WALLET.HOTKEY + The name of wallet's hotkey. + --wallet.path WALLET.PATH + The path to your bittensor wallets + --wallet._mock To turn on wallet mocking for testing purposes. + --wallet.reregister WALLET.REREGISTER + Whether to reregister the wallet if it is not already registered. + --axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS + maximum number of threads in thread pool + --axon.priority.maxsize AXON.PRIORITY.MAXSIZE + maximum size of tasks in priority queue + --axon.port AXON.PORT + The local port this axon endpoint is bound to. i.e. 8091 + --axon.ip AXON.IP The local ip this axon binds to. ie. [::] + --axon.external_port AXON.EXTERNAL_PORT + The public port this axon broadcasts to the network. i.e. 8091 + --axon.external_ip AXON.EXTERNAL_IP + The external ip this axon broadcasts to the network to. ie. [::] + --axon.max_workers AXON.MAX_WORKERS + The maximum number connection handler threads working simultaneously on this endpoint. The grpc server distributes new + worker threads to service requests up to this number. + --axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS + Maximum number of allowed active connections + --subtensor.network SUBTENSOR.NETWORK + The subtensor network flag. The likely choices are: -- finney (main network) -- local (local running network) -- mock + (creates a mock connection (for testing)) If this option is set it overloads subtensor.chain_endpoint with an entry point + node from that network. + --subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT + The subtensor endpoint flag. If set, overrides the --network flag. + --subtensor._mock To turn on subtensor mocking for testing purposes. + --subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES, -n SUBTENSOR.REGISTER.NUM_PROCESSES + Number of processors to use for registration + --subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --subtensor.register.cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, -u SUBTENSOR.REGISTER.UPDATE_INTERVAL + The number of nonces to process before checking for next block during registration + --subtensor.register.no_output_in_place, --no_output_in_place + Whether to not ouput the registration statistics in-place. Set flag to disable output in-place. + --subtensor.register.verbose + Whether to ouput the registration statistics verbosely. + --subtensor.register.cuda.use_cuda, --cuda, --cuda.use_cuda + Set flag to use CUDA to register. + --subtensor.register.cuda.no_cuda, --no_cuda, --cuda.no_cuda + Set flag to not use CUDA for registration + --subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...], --cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...] + Set the CUDA device id(s). Goes by the order of speed. (i.e. 0 is the fastest). + --subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB, --cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB + Set the number of Threads Per Block for CUDA. + --logging.debug Turn on bittensor debugging information + --logging.trace Turn on bittensor trace level information + --logging.record_log Turns on logging to file. + --logging.logging_dir LOGGING.LOGGING_DIR + Logging default root directory. + --config CONFIG If set, defaults are overridden by passed file. + --strict If flagged, config will check that only exact arguemnts have been set. +``` \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/stabilityai/neuron.py b/neurons/text/prompting/miners/huggingface/stabilityai/neuron.py new file mode 100644 index 0000000000..5a7ec17ca1 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/stabilityai/neuron.py @@ -0,0 +1,83 @@ +# The MIT License (MIT) +# Copyright © 2021 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + + +# General. +import torch +import argparse +import bittensor +from typing import List, Dict +from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, StoppingCriteria, StoppingCriteriaList + +class StopOnTokens( StoppingCriteria ): + def __call__( self, input_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs ) -> bool: + stop_ids = [50278, 50279, 50277, 1, 0] + for stop_id in stop_ids: + if input_ids[0][-1] == stop_id: + return True + return False + +class StabilityAIMiner( bittensor.HuggingFaceMiner ): + arg_prefix: str = 'stabilityai' + system_label: str = '<|SYSTEM|>:' + assistant_label: str = '<|ASSISTANT|>:' + user_label: str = '<|USER|>:' + + @classmethod + def add_args( cls, parser: argparse.ArgumentParser ): + super( StabilityAIMiner, cls ).add_args( parser ) + parser.add_argument( '--stabilityai.model_size', type=int, choices=[3, 7], default=7, help='Run the 3B or 7B model.' ) + parser.add_argument( '--stabilityai.suffix', type=str, default=None, help="The suffix that comes after a completion of inserted text." ) + parser.add_argument( '--stabilityai.num_return_sequences', type=int, default=1, help='Description of num_return_sequences' ) + parser.add_argument( '--stabilityai.num_beams', type=int, default=1, help='Description of num_beams' ) + parser.add_argument( '--stabilityai.stopping_criteria', type=str, default='stop', help='Description of stopping_criteria' ) + + def load_tokenizer( self ): + return AutoTokenizer.from_pretrained( + "stabilityai/stablelm-tuned-alpha-{}b".format( self.config.stabilityai.model_size ), + use_auth_token=self.config.stabilityai.api_key + ) + + def load_model( self ): + model = AutoModelForCausalLM.from_pretrained( + "stabilityai/stablelm-tuned-alpha-{}b".format( self.config.stabilityai.model_size ), + use_auth_token=self.config.stabilityai.api_key, + torch_dtype=torch.float16 + ).cuda() + + return pipeline( + "text-generation", + model, + tokenizer = self.tokenizer, + device = 0, + max_new_tokens = self.config.stabilityai.max_new_tokens, + num_return_sequences = self.config.stabilityai.num_return_sequences, + num_beams = self.config.stabilityai.num_beams, + do_sample = self.config.stabilityai.do_sample, + temperature = self.config.stabilityai.temperature, + top_p = self.config.stabilityai.top_p, + top_k = self.config.stabilityai.top_k, + stopping_criteria=StoppingCriteriaList( [StopOnTokens()] ) + ) + + def forward( self, messages: List[Dict[str, str]] ) -> str: + history = self.process_history( messages ) + return self.model( history )[0]['generated_text'].split(':')[-1].replace( str( history ), "") + +if __name__ == "__main__": + bittensor.utils.version_checking() + StabilityAIMiner().run() diff --git a/neurons/text/prompting/miners/stabilityai/requirements.txt b/neurons/text/prompting/miners/huggingface/stabilityai/stabilityai_requirements.txt similarity index 100% rename from neurons/text/prompting/miners/stabilityai/requirements.txt rename to neurons/text/prompting/miners/huggingface/stabilityai/stabilityai_requirements.txt diff --git a/neurons/text/prompting/miners/huggingface/vicuna/README.md b/neurons/text/prompting/miners/huggingface/vicuna/README.md new file mode 100644 index 0000000000..e7d2f55f8a --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/vicuna/README.md @@ -0,0 +1,183 @@ +## Vicuna Miner +Vicuna Language Model Serving with BitTensor +This code is for running the Vicuna model through the BitTensor framework. + +# Overview + +## Contents + +- [Installing Dependencies](#installing-dependencies) +- [Converting Weights Into Model](#converting-weights-into-model) +- [Starting Miner](#starting-miner) + + +# Installing Dependencies + +``` +python3 -m pip install -r neurons/text/prompting/miners/huggingface/vicuna/requirements.txt +``` + +# Converting Weights Into Model +If you already have a converted checkpoint of the model, you can skip this step. + +## Vicuna Weights +The [Vicuna](https://vicuna.lmsys.org/) weights as delta weights to comply with the LLaMA model license. +You can add our delta to the original LLaMA weights to obtain the Vicuna weights. Instructions: + +1. Get the original LLaMA weights in the huggingface format by following the instructions [here](https://huggingface.co/docs/transformers/main/model_doc/llama). +2. Use the following scripts to get Vicuna weights by applying our delta. They will automatically download delta weights from our Hugging Face [account](https://huggingface.co/lmsys). + +**NOTE**: +Weights v1.1 are only compatible with the latest main branch of huggingface/transformers and ``fschat >= 0.2.0``. +Please update your local packages accordingly. If you follow the above commands to do a fresh install, then you should get all the correct versions. + +Depending on which conversion script was used to create the Huggingface checkpoint of Llama, you might get an error that the tokenizer can not be found when loading the tokenizer. You can then replace all AutoTokenizers command with the correct tokenizer (in the example "LlamaTokenizer"), using this command: +``` +find /path/to/fastchat -type f -name '*.py' -exec sed -i 's/AutoTokenizer/LlamaTokenizer/g' {} + +``` + +### Vicuna-7B +This conversion command needs around 30 GB of CPU RAM. +If you do not have enough memory, you can create a large swap file that allows the operating system to automatically utilize the disk as virtual memory. +```bash +python3 -m fastchat.model.apply_delta \ + --base /path/to/llama-7b \ + --target /output/path/to/vicuna-7b \ + --delta lmsys/vicuna-7b-delta-v1.1 +``` + +### Vicuna-13B +This conversion command needs around 60 GB of CPU RAM. +If you do not have enough memory, you can create a large swap file that allows the operating system to automatically utilize the disk as virtual memory. +```bash +python3 -m fastchat.model.apply_delta \ + --base /path/to/llama-13b \ + --target /output/path/to/vicuna-13b \ + --delta lmsys/vicuna-13b-delta-v1.1 +``` + + +# Starting Miner +``` +# If using HuggingFace model directly, only need to supply the repo ID. +python3 neurons/text/prompting/miners/huggingface/vicuna/neuron.py --vicuna.model_name + +# If merging the weights yourself supply the path. +python3 neurons/text/prompting/miners/huggingface/vicuna/neuron.py --vicuna.model_name /path/to/merged/vicuna/weights + +``` + +# Full Usage +``` +usage: vicuna_miner.py [-h] --vicuna.model_name VICUNA.MODEL_NAME [--vicuna.device VICUNA.DEVICE] [--vicuna.max_new_tokens VICUNA.MAX_NEW_TOKENS] [--vicuna.temperature VICUNA.TEMPERATURE] [--vicuna.do_sample] + [--vicuna.repetition_penalty VICUNA.REPETITION_PENALTY] [--vicuna.do_prompt_injection] [--vicuna.system_prompt VICUNA.SYSTEM_PROMPT] [--vicuna.repetition-penalty VICUNA.REPETITION_PENALTY] [--vicuna.top_p VICUNA.TOP_P] + [--vicuna.top_k VICUNA.TOP_K] [--vicuna.load_in_8bit VICUNA.LOAD_IN_8BIT] [--vicuna.pad_tokens VICUNA.PAD_TOKENS [VICUNA.PAD_TOKENS ...]] [--netuid NETUID] [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] + [--neuron.no_set_weights] [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]]] + [--neuron.blacklist.allow_non_registered] [--neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE] [--neuron.default_priority NEURON.DEFAULT_PRIORITY] [--wallet.name WALLET.NAME] [--wallet.hotkey WALLET.HOTKEY] + [--wallet.path WALLET.PATH] [--wallet._mock] [--wallet.reregister WALLET.REREGISTER] [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] [--axon.port AXON.PORT] [--axon.ip AXON.IP] + [--axon.external_port AXON.EXTERNAL_PORT] [--axon.external_ip AXON.EXTERNAL_IP] [--axon.max_workers AXON.MAX_WORKERS] [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] [--subtensor.network SUBTENSOR.NETWORK] + [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] [--subtensor._mock] [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] + [--subtensor.register.no_output_in_place] [--subtensor.register.verbose] [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] + [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] [--logging.debug] [--logging.trace] [--logging.record_log] + [--logging.logging_dir LOGGING.LOGGING_DIR] [--config CONFIG] [--strict] + +optional arguments: + -h, --help show this help message and exit + --vicuna.model_name VICUNA.MODEL_NAME + Name or path of model to load + --vicuna.device VICUNA.DEVICE + Device to load model + --vicuna.max_new_tokens VICUNA.MAX_NEW_TOKENS + Max tokens for model output. + --vicuna.temperature VICUNA.TEMPERATURE + Sampling temperature of model + --vicuna.do_sample Whether to use multinomial sampling. + --vicuna.repetition_penalty VICUNA.REPETITION_PENALTY + Repetition penalty for model + --vicuna.do_prompt_injection + Whether to use a custom "system" prompt instead of the one sent by bittensor. + --vicuna.system_prompt VICUNA.SYSTEM_PROMPT + What prompt to replace the system prompt with + --vicuna.repetition-penalty VICUNA.REPETITION_PENALTY + Repetition penalty for greedy decoding. Between 1.0 and infinity. 1.0 means no penalty. Default: 1.0 + --vicuna.top_p VICUNA.TOP_P + Top-p (nucleus) sampling. Defaults to 1.0 (top-k sampling). Must be between 0.0 and 1.0. + --vicuna.top_k VICUNA.TOP_K + Top-k sampling. Defaults to 0 (no top-k sampling). Must be between 0 and 1000. + --vicuna.load_in_8bit VICUNA.LOAD_IN_8BIT + Load model in 8 bit precision + --vicuna.pad_tokens VICUNA.PAD_TOKENS [VICUNA.PAD_TOKENS ...] + A list of integers separated by spaces for the pad_tokens. + --netuid NETUID Subnet netuid + --neuron.name NEURON.NAME + Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name + --neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH + Blocks until the miner sets weights on chain + --neuron.no_set_weights + If True, the model does not set weights. + --neuron.max_batch_size NEURON.MAX_BATCH_SIZE + The maximum batch size for forward requests. + --neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN + The maximum sequence length for forward requests. + --neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]] + To blacklist certain hotkeys + --neuron.blacklist.allow_non_registered + If True, the miner will allow non-registered hotkeys to mine. + --neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE + Set default stake for miners. + --neuron.default_priority NEURON.DEFAULT_PRIORITY + Set default priority for miners. + --wallet.name WALLET.NAME + The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet) + --wallet.hotkey WALLET.HOTKEY + The name of wallet's hotkey. + --wallet.path WALLET.PATH + The path to your bittensor wallets + --wallet._mock To turn on wallet mocking for testing purposes. + --wallet.reregister WALLET.REREGISTER + Whether to reregister the wallet if it is not already registered. + --axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS + maximum number of threads in thread pool + --axon.priority.maxsize AXON.PRIORITY.MAXSIZE + maximum size of tasks in priority queue + --axon.port AXON.PORT + The local port this axon endpoint is bound to. i.e. 8091 + --axon.ip AXON.IP The local ip this axon binds to. ie. [::] + --axon.external_port AXON.EXTERNAL_PORT + The public port this axon broadcasts to the network. i.e. 8091 + --axon.external_ip AXON.EXTERNAL_IP + The external ip this axon broadcasts to the network to. ie. [::] + --axon.max_workers AXON.MAX_WORKERS + The maximum number connection handler threads working simultaneously on this endpoint. The grpc server distributes new worker threads to service requests up to this number. + --axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS + Maximum number of allowed active connections + --subtensor.network SUBTENSOR.NETWORK + The subtensor network flag. The likely choices are: -- finney (main network) -- local (local running network) -- mock (creates a mock connection (for testing)) If this option is set it overloads subtensor.chain_endpoint with an entry + point node from that network. + --subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT + The subtensor endpoint flag. If set, overrides the --network flag. + --subtensor._mock To turn on subtensor mocking for testing purposes. + --subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES, -n SUBTENSOR.REGISTER.NUM_PROCESSES + Number of processors to use for registration + --subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --subtensor.register.cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, --cuda.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL, -u SUBTENSOR.REGISTER.UPDATE_INTERVAL + The number of nonces to process before checking for next block during registration + --subtensor.register.no_output_in_place, --no_output_in_place + Whether to not ouput the registration statistics in-place. Set flag to disable output in-place. + --subtensor.register.verbose + Whether to ouput the registration statistics verbosely. + --subtensor.register.cuda.use_cuda, --cuda, --cuda.use_cuda + Set flag to use CUDA to register. + --subtensor.register.cuda.no_cuda, --no_cuda, --cuda.no_cuda + Set flag to not use CUDA for registration + --subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...], --cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...] + Set the CUDA device id(s). Goes by the order of speed. (i.e. 0 is the fastest). + --subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB, --cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB + Set the number of Threads Per Block for CUDA. + --logging.debug Turn on bittensor debugging information + --logging.trace Turn on bittensor trace level information + --logging.record_log Turns on logging to file. + --logging.logging_dir LOGGING.LOGGING_DIR + Logging default root directory. + --config CONFIG If set, defaults are overridden by passed file. + --strict If flagged, config will check that only exact arguemnts have been set. +``` \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/vicuna/neuron.py b/neurons/text/prompting/miners/huggingface/vicuna/neuron.py new file mode 100644 index 0000000000..61e466d11c --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/vicuna/neuron.py @@ -0,0 +1,64 @@ +# The MIT License (MIT) +# Copyright © 2023 Yuma Rao + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import bittensor +from typing import List, Dict +from transformers import AutoTokenizer, AutoModelForCausalLM + +class VicunaMiner( bittensor.HuggingFaceMiner ): + + arg_prefix: str = 'vicuna' + system_label: str = '' + assistant_label: str = 'ASSISTANT:' + user_label: str = 'USER:' + + def __init__( self ): + super( VicunaMiner, self ).__init__() + print ( self.config ) + + def load_tokenizer( self ): + return AutoTokenizer.from_pretrained( self.config.vicuna.model_name, use_fast=False ) + + def load_model( self ): + return AutoModelForCausalLM.from_pretrained( self.config.vicuna.model_name, torch_dtype = torch.float16, low_cpu_mem_usage=True ) + + def forward(self, messages: List[Dict[str, str]]) -> str: + + history = self.process_history( messages ) + prompt = history + self.assistant_label + print(prompt) + + input_ids = self.tokenizer.encode( prompt, return_tensors="pt" ).to( self.config.vicuna.device ) + output = self.model.generate( + input_ids, + max_length=input_ids.shape[1] + self.config.vicuna.max_new_tokens, + temperature=self.config.vicuna.temperature, + do_sample=self.config.vicuna.do_sample, + pad_token_id=self.tokenizer.eos_token_id, + ) + + generation = self.tokenizer.decode( output[0][input_ids.shape[1]:], skip_special_tokens=True ) + print(generation) + + bittensor.logging.debug( "Message: " + str( messages ) ) + bittensor.logging.debug( "Generation: " + str( generation ) ) + return generation + +if __name__ == "__main__": + bittensor.utils.version_checking() + VicunaMiner().run() \ No newline at end of file diff --git a/neurons/text/prompting/miners/huggingface/vicuna/requirements.txt b/neurons/text/prompting/miners/huggingface/vicuna/requirements.txt new file mode 100644 index 0000000000..5e83b53a0d --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/vicuna/requirements.txt @@ -0,0 +1,4 @@ +transformers>=4.28.0 +fschat +tokenizers>=0.13.3 +accelerate \ No newline at end of file diff --git a/neurons/text/prompting/miners/stabilityai/README.md b/neurons/text/prompting/miners/huggingface/wizard_vicuna/README.md similarity index 56% rename from neurons/text/prompting/miners/stabilityai/README.md rename to neurons/text/prompting/miners/huggingface/wizard_vicuna/README.md index c19ca836cc..699dcd2b26 100644 --- a/neurons/text/prompting/miners/stabilityai/README.md +++ b/neurons/text/prompting/miners/huggingface/wizard_vicuna/README.md @@ -1,68 +1,46 @@ -## StabilityAI Miner -StabilityAI 7B completion miner for bittensor's prompting network. + +## WizardLM + Vicuna Miner +WizardLM Vicuna completion miner for bittensor's prompting network. # Example Usage ``` -python3 -m pip install -r neurons/text/prompting/miners/stabilityai/requirements.txt -python3 neurons/text/prompting/miners/stabilityai/neuron.py --stabilityai.api_key +python3 neurons/text/prompting/miners/huggingface/wizard_vicuna/neuron.py --wiz_vic.model_name ``` # Full Usage ``` -usage: neuron.py [-h] [--stabilityai.api_key STABILITYAI.API_KEY] [--stabilityai.model_size {3,7}] - [--stabilityai.device STABILITYAI.DEVICE] [--stabilityai.suffix STABILITYAI.SUFFIX] - [--stabilityai.max_tokens STABILITYAI.MAX_TOKENS] - [--stabilityai.num_return_sequences STABILITYAI.NUM_RETURN_SEQUENCES] - [--stabilityai.num_beams STABILITYAI.NUM_BEAMS] [--stabilityai.do_sample STABILITYAI.DO_SAMPLE] - [--stabilityai.temperature STABILITYAI.TEMPERATURE] [--stabilityai.top_p STABILITYAI.TOP_P] - [--stabilityai.top_k STABILITYAI.TOP_K] [--stabilityai.stopping_criteria STABILITYAI.STOPPING_CRITERIA] - [--netuid NETUID] [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] - [--neuron.no_set_weights] [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] - [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] - [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]]] - [--neuron.blacklist.allow_non_registered] - [--neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE] - [--neuron.default_priority NEURON.DEFAULT_PRIORITY] [--wallet.name WALLET.NAME] - [--wallet.hotkey WALLET.HOTKEY] [--wallet.path WALLET.PATH] [--wallet._mock] - [--wallet.reregister WALLET.REREGISTER] [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] - [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] [--axon.port AXON.PORT] [--axon.ip AXON.IP] - [--axon.external_port AXON.EXTERNAL_PORT] [--axon.external_ip AXON.EXTERNAL_IP] - [--axon.max_workers AXON.MAX_WORKERS] [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] - [--subtensor.network SUBTENSOR.NETWORK] [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] - [--subtensor._mock] [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] - [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] - [--subtensor.register.no_output_in_place] [--subtensor.register.verbose] - [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] - [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] - [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] [--logging.debug] [--logging.trace] - [--logging.record_log] [--logging.logging_dir LOGGING.LOGGING_DIR] [--config CONFIG] [--strict] +usage: neuron.py [-h] [--wiz_vic.model_name WIZ_VIC.MODEL_NAME] [--wiz_vic.device WIZ_VIC.DEVICE] [--wiz_vic.max_new_tokens WIZ_VIC.MAX_NEW_TOKENS] + [--wiz_vic.temperature WIZ_VIC.TEMPERATURE] [--wiz_vic.greedy_decoding] [--wiz_vic.do_sample] [--wiz_vic.do_prompt_injection] + [--wiz_vic.system_prompt WIZ_VIC.SYSTEM_PROMPT] [--netuid NETUID] [--neuron.name NEURON.NAME] [--neuron.blocks_per_epoch NEURON.BLOCKS_PER_EPOCH] + [--neuron.no_set_weights] [--neuron.max_batch_size NEURON.MAX_BATCH_SIZE] [--neuron.max_sequence_len NEURON.MAX_SEQUENCE_LEN] + [--neuron.blacklist.hotkeys [NEURON.BLACKLIST.HOTKEYS [NEURON.BLACKLIST.HOTKEYS ...]]] [--neuron.blacklist.allow_non_registered] + [--neuron.blacklist.default_stake NEURON.BLACKLIST.DEFAULT_STAKE] [--neuron.default_priority NEURON.DEFAULT_PRIORITY] [--wallet.name WALLET.NAME] + [--wallet.hotkey WALLET.HOTKEY] [--wallet.path WALLET.PATH] [--wallet._mock] [--wallet.reregister WALLET.REREGISTER] + [--axon.priority.max_workers AXON.PRIORITY.MAX_WORKERS] [--axon.priority.maxsize AXON.PRIORITY.MAXSIZE] [--axon.port AXON.PORT] [--axon.ip AXON.IP] + [--axon.external_port AXON.EXTERNAL_PORT] [--axon.external_ip AXON.EXTERNAL_IP] [--axon.max_workers AXON.MAX_WORKERS] + [--axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS] [--subtensor.network SUBTENSOR.NETWORK] [--subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT] + [--subtensor._mock] [--subtensor.register.num_processes SUBTENSOR.REGISTER.NUM_PROCESSES] [--subtensor.register.update_interval SUBTENSOR.REGISTER.UPDATE_INTERVAL] + [--subtensor.register.no_output_in_place] [--subtensor.register.verbose] [--subtensor.register.cuda.use_cuda] [--subtensor.register.cuda.no_cuda] + [--subtensor.register.cuda.dev_id SUBTENSOR.REGISTER.CUDA.DEV_ID [SUBTENSOR.REGISTER.CUDA.DEV_ID ...]] [--subtensor.register.cuda.TPB SUBTENSOR.REGISTER.CUDA.TPB] + [--logging.debug] [--logging.trace] [--logging.record_log] [--logging.logging_dir LOGGING.LOGGING_DIR] [--config CONFIG] [--strict] optional arguments: -h, --help show this help message and exit - --stabilityai.api_key STABILITYAI.API_KEY - huggingface api key - --stabilityai.model_size {3,7} - Run the 3B or 7B model. - --stabilityai.device STABILITYAI.DEVICE + --wiz_vic.model_name WIZ_VIC.MODEL_NAME + Name/path of model to load + --wiz_vic.device WIZ_VIC.DEVICE Device to load model - --stabilityai.suffix STABILITYAI.SUFFIX - The suffix that comes after a completion of inserted text. - --stabilityai.max_tokens STABILITYAI.MAX_TOKENS - The maximum number of tokens to generate in the completion. - --stabilityai.num_return_sequences STABILITYAI.NUM_RETURN_SEQUENCES - Description of num_return_sequences - --stabilityai.num_beams STABILITYAI.NUM_BEAMS - Description of num_beams - --stabilityai.do_sample STABILITYAI.DO_SAMPLE - Description of do_sample - --stabilityai.temperature STABILITYAI.TEMPERATURE - Description of temperature - --stabilityai.top_p STABILITYAI.TOP_P - Description of top_p - --stabilityai.top_k STABILITYAI.TOP_K - Description of top_k - --stabilityai.stopping_criteria STABILITYAI.STOPPING_CRITERIA - Description of stopping_criteria + --wiz_vic.max_new_tokens WIZ_VIC.MAX_NEW_TOKENS + Max tokens for model output. + --wiz_vic.temperature WIZ_VIC.TEMPERATURE + Sampling temperature of model + --wiz_vic.greedy_decoding + Whether to use greedy sampling or not (if not, uses multinomial sampling). + --wiz_vic.do_sample Whether to use sampling or not (if not, uses greedy decoding). + --wiz_vic.do_prompt_injection + Whether to use a custom "system" prompt instead of the one sent by bittensor. + --wiz_vic.system_prompt WIZ_VIC.SYSTEM_PROMPT + What prompt to replace the system prompt with --netuid NETUID Subnet netuid --neuron.name NEURON.NAME Trials for this miner go in miner.root / (wallet_cold - wallet_hot) / miner.name @@ -83,8 +61,7 @@ optional arguments: --neuron.default_priority NEURON.DEFAULT_PRIORITY Set default priority for miners. --wallet.name WALLET.NAME - The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this - wallet) + The name of the wallet to unlock for running bittensor (name mock is reserved for mocking this wallet) --wallet.hotkey WALLET.HOTKEY The name of wallet's hotkey. --wallet.path WALLET.PATH @@ -104,14 +81,13 @@ optional arguments: --axon.external_ip AXON.EXTERNAL_IP The external ip this axon broadcasts to the network to. ie. [::] --axon.max_workers AXON.MAX_WORKERS - The maximum number connection handler threads working simultaneously on this endpoint. The grpc - server distributes new worker threads to service requests up to this number. + The maximum number connection handler threads working simultaneously on this endpoint. The grpc server distributes new worker threads to service requests up + to this number. --axon.maximum_concurrent_rpcs AXON.MAXIMUM_CONCURRENT_RPCS Maximum number of allowed active connections --subtensor.network SUBTENSOR.NETWORK - The subtensor network flag. The likely choices are: -- finney (main network) -- local (local - running network) -- mock (creates a mock connection (for testing)) If this option is set it - overloads subtensor.chain_endpoint with an entry point node from that network. + The subtensor network flag. The likely choices are: -- finney (main network) -- local (local running network) -- mock (creates a mock connection (for + testing)) If this option is set it overloads subtensor.chain_endpoint with an entry point node from that network. --subtensor.chain_endpoint SUBTENSOR.CHAIN_ENDPOINT The subtensor endpoint flag. If set, overrides the --network flag. --subtensor._mock To turn on subtensor mocking for testing purposes. diff --git a/neurons/text/prompting/miners/huggingface/wizard_vicuna/neuron.py b/neurons/text/prompting/miners/huggingface/wizard_vicuna/neuron.py new file mode 100644 index 0000000000..2881263172 --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/wizard_vicuna/neuron.py @@ -0,0 +1,54 @@ +# The MIT License (MIT) +# Copyright © 2023 Opentensor Foundation + +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the “Software”), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of +# the Software. + +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import torch +import bittensor +from typing import List, Dict +from transformers import AutoTokenizer, AutoModelForCausalLM + +class WizardVicunaMiner( bittensor.HuggingFaceMiner ): + arg_prefix = "wiz_vic" + system_label = "" + assistant_label = "ASSISTANT:" + user_label = "USER:" + + def load_tokenizer( self ): + return AutoTokenizer.from_pretrained( self.config.wiz_vic.model_name, use_fast=False ) + + def load_model( self ): + return AutoModelForCausalLM.from_pretrained( self.config.wiz_vic.model_name, torch_dtype=torch.float16, low_cpu_mem_usage=True ) + + def forward( self, messages: List[Dict[str, str]] ) -> str: + history = self.process_history( messages ) + prompt = history + self.assistant_label + input_ids = self.tokenizer.encode( prompt, return_tensors="pt" ).to( self.config.wiz_vic.device ) + output = self.model.generate( + input_ids, + max_length=input_ids.shape[1] + self.config.wiz_vic.max_new_tokens, + temperature=self.config.wiz_vic.temperature, + do_sample=self.config.wiz_vic.do_sample, + pad_token_id=self.tokenizer.eos_token_id, + ) + generation = self.tokenizer.decode( output[0][input_ids.shape[1]:], skip_special_tokens=True ) + + bittensor.logging.debug( "Message: " + str( messages ) ) + bittensor.logging.debug( "Generation: " + str( generation) ) + return generation + +if __name__ == "__main__": + bittensor.utils.version_checking() + WizardVicunaMiner().run() diff --git a/neurons/text/prompting/miners/huggingface/wizard_vicuna/requirements.txt b/neurons/text/prompting/miners/huggingface/wizard_vicuna/requirements.txt new file mode 100644 index 0000000000..33059ec77c --- /dev/null +++ b/neurons/text/prompting/miners/huggingface/wizard_vicuna/requirements.txt @@ -0,0 +1,2 @@ +transformers>=4.29.2 +accelerate \ No newline at end of file diff --git a/neurons/text/prompting/miners/koala/neuron.py b/neurons/text/prompting/miners/koala/neuron.py deleted file mode 100644 index 4307bec9ea..0000000000 --- a/neurons/text/prompting/miners/koala/neuron.py +++ /dev/null @@ -1,90 +0,0 @@ -# The MIT License (MIT) -# Copyright © 2023 Opentensor Foundation - -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -# documentation files (the “Software”), to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, -# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of -# the Software. - -# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - -import torch -import argparse -import bittensor -from typing import List, Dict -from transformers import AutoTokenizer, AutoModelForCausalLM - -class KoalaMiner( bittensor.BasePromptingMiner ): - - @classmethod - def check_config( cls, config: 'bittensor.Config' ): - pass - - @classmethod - def add_args( cls, parser: argparse.ArgumentParser ): - parser.add_argument( '--koala.model_name', type=str, required=True, help='Name/path of model to load' ) - parser.add_argument( '--koala.device', type=str, help='Device to load model', default="cuda" ) - parser.add_argument( '--koala.max_new_tokens', type=int, help='Max tokens for model output.', default=256 ) - parser.add_argument( '--koala.temperature', type=float, help='Sampling temperature of model', default=0.5 ) - parser.add_argument( '--koala.do_sample', action='store_true', default=False, help='Whether to use sampling or not (if not, uses greedy decoding).' ) - parser.add_argument( '--koala.do_prompt_injection', action='store_true', default=False, help='Whether to use a custom "system" prompt instead of the one sent by bittensor.' ) - parser.add_argument( '--koala.system_prompt', type=str, help='What prompt to replace the system prompt with', default= "BEGINNING OF CONVERSATION: " ) - - def __init__( self ): - super( KoalaMiner, self ).__init__() - print ( self.config ) - - bittensor.logging.info( 'Loading ' + str(self.config.koala.model_name)) - self.tokenizer = AutoTokenizer.from_pretrained( self.config.koala.model_name, use_fast=False ) - self.model = AutoModelForCausalLM.from_pretrained( self.config.koala.model_name, torch_dtype = torch.float16, low_cpu_mem_usage=True ) - bittensor.logging.info( 'Model loaded!' ) - - if self.config.koala.device != "cpu": - self.model = self.model.to( self.config.koala.device ) - - - def _process_history(self, history: List[str]) -> str: - processed_history = '' - - if self.config.koala.do_prompt_injection: - processed_history += self.config.koala.system_prompt - - for message in history: - if message['role'] == 'system': - if not self.config.koala.do_prompt_injection or message != history[0]: - processed_history += '' + message['content'].strip() + ' ' - - if message['role'] == 'Assistant': - processed_history += 'GPT:' + message['content'].strip() + '' #No blankspace after GPT: since that is where generation starts. - if message['role'] == 'user': - processed_history += 'USER: ' + message['content'].strip() + ' ' - return processed_history - - def forward(self, messages: List[Dict[str, str]]) -> str: - history = self._process_history(messages) - prompt = history + "GPT:" - input_ids = self.tokenizer.encode(prompt, return_tensors="pt").to(self.config.koala.device) - output = self.model.generate( - input_ids, - max_length=input_ids.shape[1] + self.config.koala.max_new_tokens, - temperature=self.config.koala.temperature, - do_sample=self.config.koala.do_sample, - pad_token_id=self.tokenizer.eos_token_id, - ) - generation = self.tokenizer.decode(output[0][input_ids.shape[1]:], skip_special_tokens=True) - - # Logging input and generation if debugging is active - bittensor.logging.debug("Message: " + str(messages)) - bittensor.logging.debug("Generation: " + str(generation)) - return generation - -if __name__ == "__main__": - bittensor.utils.version_checking() - KoalaMiner().run() \ No newline at end of file diff --git a/neurons/text/prompting/miners/neoxt/neuron.py b/neurons/text/prompting/miners/neoxt/neuron.py deleted file mode 100644 index 9bab67f4d8..0000000000 --- a/neurons/text/prompting/miners/neoxt/neuron.py +++ /dev/null @@ -1,91 +0,0 @@ -# The MIT License (MIT) -# Copyright © 2023 Opentensor Foundation - -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -# documentation files (the “Software”), to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, -# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of -# the Software. - -# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - -import torch -import argparse -import bittensor -from typing import List, Dict -from transformers import AutoTokenizer, AutoModelForCausalLM - -class NeoxtMiner( bittensor.BasePromptingMiner ): - - @classmethod - def check_config( cls, config: 'bittensor.Config' ): - pass - - @classmethod - def add_args( cls, parser: argparse.ArgumentParser ): - parser.add_argument( '--neoxt.model_name', type=str, help='Name/path of model to load', default="togethercomputer/GPT-NeoXT-Chat-Base-20B" ) - parser.add_argument( '--neoxt.device', type=str, help='Device to load model', default="cuda" ) - parser.add_argument( '--neoxt.max_new_tokens', type=int, help='Max tokens for model output.', default=64 ) - parser.add_argument( '--neoxt.temperature', type=float, help='Sampling temperature of model', default=0.8 ) - parser.add_argument( '--neoxt.do_sample', action='store_true', default=False, help='Whether to use sampling or not (if not, uses greedy decoding).' ) - parser.add_argument( '--neoxt.do_prompt_injection', action='store_true', default=False, help='Whether to use a custom "system" prompt instead of the one sent by bittensor.' ) - parser.add_argument( '--neoxt.system_prompt', type=str, help='What prompt to replace the system prompt with', default= "" ) - - def __init__( self ): - super( NeoxtMiner, self ).__init__() - print ( self.config ) - - bittensor.logging.info( 'Loading ' + str(self.config.neoxt.model_name)) - self.tokenizer = AutoTokenizer.from_pretrained( self.config.neoxt.model_name ) - self.model = AutoModelForCausalLM.from_pretrained( self.config.neoxt.model_name, torch_dtype = torch.float16, low_cpu_mem_usage=True ) - bittensor.logging.info( 'Model loaded!' ) - - if self.config.neoxt.device != "cpu": - self.model = self.model.to( self.config.neoxt.device ) - - - def _process_history(self, history: List[str]) -> str: - processed_history = '' - - if self.config.neoxt.do_prompt_injection: - processed_history += self.config.neoxt.system_prompt - - for message in history: - if message['role'] == 'system': - if not self.config.neoxt.do_prompt_injection or message == history[0]: - processed_history += ': ' + message['content'].strip() + '\n' - - if message['role'] == 'assistant': - processed_history += ': ' + message['content'].strip() + '\n' - if message['role'] == 'user': - processed_history += ': ' + message['content'].strip() + '\n' - return processed_history - - def forward(self, messages: List[Dict[str, str]]) -> str: - history = self._process_history(messages) - prompt = history + ":" - input_ids = self.tokenizer.encode(prompt, return_tensors="pt").to(self.config.neoxt.device) - output = self.model.generate( - input_ids, - max_length=input_ids.shape[1] + self.config.neoxt.max_new_tokens, - temperature=self.config.neoxt.temperature, - do_sample=self.config.neoxt.do_sample, - pad_token_id=self.tokenizer.eos_token_id, - ) - generated_text = self.tokenizer.decode(output[0][input_ids.shape[1]:], skip_special_tokens=True) - generation = generated_text.split("")[0].strip() - - # Logging input and generation if debugging is active - bittensor.logging.debug("Message: " + str(messages).replace("<","-").replace(">","-")) - bittensor.logging.debug("Generation: " + str(generation).replace("<","-").replace(">","-")) - return generation - -if __name__ == "__main__": - bittensor.utils.version_checking() - NeoxtMiner().run() diff --git a/neurons/text/prompting/miners/openai/neuron.py b/neurons/text/prompting/miners/openai/neuron.py index 15614f84d2..49e14c963c 100644 --- a/neurons/text/prompting/miners/openai/neuron.py +++ b/neurons/text/prompting/miners/openai/neuron.py @@ -1,5 +1,5 @@ # The MIT License (MIT) -# Copyright © 2021 Yuma Rao +# Copyright © 2023 Yuma Rao # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated # documentation files (the “Software”), to deal in the Software without restriction, including without limitation @@ -61,4 +61,4 @@ def forward( self, messages: List[Dict[str, str]] ) -> str: if __name__ == "__main__": bittensor.utils.version_checking() - OpenAIMiner().run() + OpenAIMiner().run() \ No newline at end of file diff --git a/neurons/text/prompting/miners/pythia/neuron.py b/neurons/text/prompting/miners/pythia/neuron.py deleted file mode 100644 index 3e7eb3b579..0000000000 --- a/neurons/text/prompting/miners/pythia/neuron.py +++ /dev/null @@ -1,90 +0,0 @@ -# The MIT License (MIT) -# Copyright © 2021 Yuma Rao - -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -# documentation files (the “Software”), to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, -# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of -# the Software. - -# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - -import torch -import argparse -import bittensor -from typing import List, Dict -from transformers import AutoTokenizer, AutoModelForCausalLM - -class PythiaMiner( bittensor.BasePromptingMiner ): - - @classmethod - def check_config( cls, config: 'bittensor.Config' ): - pass - - @classmethod - def add_args( cls, parser: argparse.ArgumentParser ): - parser.add_argument( '--pythia.model_name', type=str, help='Name/path of model to load', default="togethercomputer/Pythia-Chat-Base-7B" ) - parser.add_argument( '--pythia.device', type=str, help='Device to load model', default="cuda" ) - parser.add_argument( '--pythia.max_new_tokens', type=int, help='Max tokens for model output.', default=64 ) - parser.add_argument( '--pythia.temperature', type=float, help='Sampling temperature of model', default=0.8 ) - parser.add_argument( '--pythia.do_sample', action='store_true', default=False, help='Whether to use sampling or not (if not, uses greedy decoding).' ) - parser.add_argument( '--pythia.do_prompt_injection', action='store_true', default=False, help='Whether to use a custom "system" prompt instead of the one sent by bittensor.' ) - parser.add_argument( '--pythia.system_prompt', type=str, help='What prompt to replace the system prompt with', default= "" ) - - def __init__( self ): - super( PythiaMiner, self ).__init__() - print ( self.config ) - - bittensor.logging.info( 'Loading ' + str(self.config.pythia.model_name)) - self.tokenizer = AutoTokenizer.from_pretrained( self.config.pythia.model_name ) - self.model = AutoModelForCausalLM.from_pretrained( self.config.pythia.model_name, torch_dtype = torch.float16, low_cpu_mem_usage=True ) - bittensor.logging.info( 'Model loaded!' ) - - if self.config.pythia.device != "cpu": - self.model = self.model.to( self.config.pythia.device ) - - def _process_history(self, history: List[str]) -> str: - processed_history = '' - - if self.config.pythia.do_prompt_injection: - processed_history += self.config.pythia.system_prompt - - for message in history: - if message['role'] == 'system': - if not self.config.pythia.do_prompt_injection or message != history[0]: - processed_history += ': ' + message['content'].strip() + '\n' - - if message['role'] == 'assistant': - processed_history += ': ' + message['content'].strip() + '\n' - if message['role'] == 'user': - processed_history += ': ' + message['content'].strip() + '\n' - return processed_history - - def forward(self, messages: List[Dict[str, str]]) -> str: - history = self._process_history(messages) - prompt = history + ":" - input_ids = self.tokenizer.encode(prompt, return_tensors="pt").to(self.config.pythia.device) - output = self.model.generate( - input_ids, - max_length=input_ids.shape[1] + self.config.pythia.max_new_tokens, - temperature=self.config.pythia.temperature, - do_sample=self.config.pythia.do_sample, - pad_token_id=self.tokenizer.eos_token_id, - ) - generated_text = self.tokenizer.decode(output[0][input_ids.shape[1]:], skip_special_tokens=True) - generation = generated_text.split("")[0].strip() - - # Logging input and generation if debugging is active - bittensor.logging.debug("Message: " + str(messages).replace("<","-").replace(">","-")) - bittensor.logging.debug("Generation: " + str(generation).replace("<","-").replace(">","-")) - return generation - -if __name__ == "__main__": - bittensor.utils.version_checking() - PythiaMiner().run() diff --git a/neurons/text/prompting/miners/robertmyers/neuron.py b/neurons/text/prompting/miners/robertmyers/neuron.py deleted file mode 100644 index fa8cb23c3e..0000000000 --- a/neurons/text/prompting/miners/robertmyers/neuron.py +++ /dev/null @@ -1,66 +0,0 @@ -# The MIT License (MIT) -# Copyright © 2021 Yuma Rao - -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -# documentation files (the “Software”), to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, -# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of -# the Software. - -# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - -# General. -import json -import torch -import argparse -import bittensor -from typing import List, Dict -from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline - -class RobertMyersMiner( bittensor.BasePromptingMiner ): - - @classmethod - def check_config( cls, config: 'bittensor.Config' ): - pass - - @classmethod - def add_args( cls, parser: argparse.ArgumentParser ): - pass - - def __init__( self ): - super( RobertMyersMiner, self ).__init__() - print ( self.config ) - tokenizer = AutoTokenizer.from_pretrained( "robertmyers/bpt-sft" ) - self.model = AutoModelForCausalLM.from_pretrained( "robertmyers/bpt-sft", torch_dtype=torch.float16 ) - self.model.to( "cuda" ) - self.pipe = pipeline( "text-generation", self.model, tokenizer=tokenizer, device = 0, max_new_tokens = 256 ) - print("Model loaded") - - @staticmethod - def _process_history( history: List[ Dict[str, str] ] ) -> str: - processed_history = '' - for message in history: - if message['role'] == 'system': - processed_history += 'system: ' + message['content'] + '\n' - if message['role'] == 'assistant': - processed_history += 'assistant: ' + message['content'] + '\n' - if message['role'] == 'user': - processed_history += 'user: ' + message['content'] + '\n' - return processed_history - - def backward( self, messages: List[Dict[str, str]], response: str, rewards: torch.FloatTensor ) -> str: pass - - def forward( self, messages: List[Dict[str, str]] ) -> str: - history = self._process_history(messages) - resp = self.pipe( history )[0]['generated_text'].split(':')[-1].replace( str( history ), "") - return resp - -if __name__ == "__main__": - bittensor.utils.version_checking() - RobertMyersMiner().run() diff --git a/neurons/text/prompting/miners/stabilityai/neuron.py b/neurons/text/prompting/miners/stabilityai/neuron.py deleted file mode 100644 index 58498a0726..0000000000 --- a/neurons/text/prompting/miners/stabilityai/neuron.py +++ /dev/null @@ -1,113 +0,0 @@ -# The MIT License (MIT) -# Copyright © 2021 Yuma Rao - -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -# documentation files (the “Software”), to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, -# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of -# the Software. - -# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - - -# General. -import torch -import argparse -import bittensor -from typing import List, Dict -from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, StoppingCriteria, StoppingCriteriaList - - -class StopOnTokens(StoppingCriteria): - def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs) -> bool: - stop_ids = [50278, 50279, 50277, 1, 0] - for stop_id in stop_ids: - if input_ids[0][-1] == stop_id: - return True - return False - -class StabilityAIMiner( bittensor.BasePromptingMiner ): - - @classmethod - def check_config( cls, config: 'bittensor.Config' ): - assert config.stabilityai.api_key != None, 'the miner requires passing --stabilityai.api_key as an argument of the config.' - - @classmethod - def add_args( cls, parser: argparse.ArgumentParser ): - parser.add_argument('--stabilityai.api_key', type=str, help='huggingface api key', default="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") - parser.add_argument('--stabilityai.model_size', type=int, choices=[3, 7], default=7, help='Run the 3B or 7B model.') - parser.add_argument('--stabilityai.device', type=str, help='Device to load model', default="cuda" ) - parser.add_argument('--stabilityai.suffix', type=str, default=None, help="The suffix that comes after a completion of inserted text.") - parser.add_argument('--stabilityai.max_tokens', type=int, default=20, help="The maximum number of tokens to generate in the completion.") - parser.add_argument('--stabilityai.num_return_sequences', type=int, default=1, help='Description of num_return_sequences') - parser.add_argument('--stabilityai.num_beams', type=int, default=1, help='Description of num_beams') - parser.add_argument('--stabilityai.do_sample', type=bool, default=True, help='Description of do_sample') - parser.add_argument('--stabilityai.temperature', type=float, default=1.0, help='Description of temperature') - parser.add_argument('--stabilityai.top_p', type=float, default=0.95, help='Description of top_p') - parser.add_argument('--stabilityai.top_k', type=int, default=10, help='Description of top_k') - parser.add_argument('--stabilityai.stopping_criteria', type=str, default='stop', help='Description of stopping_criteria') - - def __init__( self ): - super( StabilityAIMiner, self ).__init__() - print ( self.config ) - bittensor.logging.info( 'Loading togethercomputer/StabilityAI {}B model...'.format( self.config.stabilityai.model_size ) ) - self.model = AutoModelForCausalLM.from_pretrained( - "stabilityai/stablelm-tuned-alpha-{}b".format( self.config.stabilityai.model_size ), - use_auth_token=self.config.stabilityai.api_key, - torch_dtype=torch.float16 - ).cuda() - self.tokenizer = AutoTokenizer.from_pretrained( - "stabilityai/stablelm-tuned-alpha-{}b".format( self.config.stabilityai.model_size ), - use_auth_token=self.config.stabilityai.api_key - ) - - if self.config.stabilityai.device == "cuda": - self.model = self.model.to( self.config.stabilityai.device ) - - self.pipe = pipeline( - "text-generation", - self.model, - tokenizer = self.tokenizer, - device = 0, - max_new_tokens = self.config.stabilityai.max_tokens, - num_return_sequences = self.config.stabilityai.num_return_sequences, - num_beams = self.config.stabilityai.num_beams, - do_sample = self.config.stabilityai.do_sample, - temperature = self.config.stabilityai.temperature, - top_p = self.config.stabilityai.top_p, - top_k = self.config.stabilityai.top_k, - stopping_criteria=StoppingCriteriaList([StopOnTokens()]) - ) - bittensor.logging.info( "StabilityAI {}B model loaded".format( self.config.stabilityai.model_size ) ) - - def blacklist( self, foward_call ) -> bool: - return False - - @staticmethod - def _process_history( history: List[ Dict[str, str] ] ) -> str: - processed_history = '' - for message in history: - if message['role'] == 'system': - processed_history += '<|SYSTEM|>: ' + message['content'] + '\n' - if message['role'] == 'assistant': - processed_history += '<|ASSISTANT|>: ' + message['content'] + '\n' - if message['role'] == 'user': - processed_history += '<|USER|>: ' + message['content'] + '\n' - return processed_history - - def backward( self, messages: List[Dict[str, str]], response: str, rewards: torch.FloatTensor ) -> str: pass - - def forward( self, messages: List[Dict[str, str]] ) -> str: - history = self._process_history(messages) - return self.pipe( history )[0]['generated_text'].split(':')[-1].replace( str( history ), "") - - -if __name__ == "__main__": - bittensor.utils.version_checking() - StabilityAIMiner().run() diff --git a/neurons/text/prompting/miners/vicuna/neuron.py b/neurons/text/prompting/miners/vicuna/neuron.py deleted file mode 100644 index 4255dc7ff2..0000000000 --- a/neurons/text/prompting/miners/vicuna/neuron.py +++ /dev/null @@ -1,93 +0,0 @@ -# The MIT License (MIT) -# Copyright © 2021 Yuma Rao - -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -# documentation files (the “Software”), to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, -# and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of -# the Software. - -# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - -import torch -import argparse -import bittensor -from typing import List, Dict -from transformers import AutoTokenizer, AutoModelForCausalLM - -class VicunaMiner( bittensor.BasePromptingMiner ): - - @classmethod - def check_config( cls, config: 'bittensor.Config' ): - pass - - @classmethod - def add_args( cls, parser: argparse.ArgumentParser ): - parser.add_argument( '--vicuna.model_name', type=str, required=True, help='Name/path of model to load' ) - parser.add_argument( '--vicuna.device', type=str, help='Device to load model', default="cuda" ) - parser.add_argument( '--vicuna.max_new_tokens', type=int, help='Max tokens for model output.', default=256 ) - parser.add_argument( '--vicuna.temperature', type=float, help='Sampling temperature of model', default=0.5 ) - parser.add_argument( '--vicuna.do_sample', action='store_true', default=False, help='Whether to use sampling or not (if not, uses greedy decoding).' ) - parser.add_argument( '--vicuna.do_prompt_injection', action='store_true', default=False, help='Whether to use a custom "system" prompt instead of the one sent by bittensor.' ) - parser.add_argument( '--vicuna.system_prompt', type=str, help='What prompt to replace the system prompt with', default= "A chat between a curious user and an artificial intelligence assistant.\nThe assistant gives helpful, detailed, and polite answers to the user's questions. " ) - - def __init__( self ): - super( VicunaMiner, self ).__init__() - print ( self.config ) - - bittensor.logging.info( 'Loading ' + str(self.config.vicuna.model_name)) - self.tokenizer = AutoTokenizer.from_pretrained( self.config.vicuna.model_name, use_fast=False ) - self.model = AutoModelForCausalLM.from_pretrained( self.config.vicuna.model_name, torch_dtype = torch.float16, low_cpu_mem_usage=True ) - bittensor.logging.info( 'Model loaded!' ) - - if self.config.vicuna.device != "cpu": - self.model = self.model.to( self.config.vicuna.device ) - - def _process_history(self, history: List[str]) -> str: - processed_history = '' - - if self.config.vicuna.do_prompt_injection: - processed_history += self.config.vicuna.system_prompt - - for message in history: - if message['role'] == 'system': - if not self.config.vicuna.do_prompt_injection or message != history[0]: - processed_history += '' + message['content'].strip() + ' ' - - if message['role'] == 'Assistant': - processed_history += 'ASSISTANT:' + message['content'].strip() + '' - if message['role'] == 'user': - processed_history += 'USER: ' + message['content'].strip() + ' ' - return processed_history - - def forward(self, messages: List[Dict[str, str]]) -> str: - - history = self._process_history(messages) - prompt = history + "ASSISTANT:" - - input_ids = self.tokenizer.encode(prompt, return_tensors="pt").to(self.config.vicuna.device) - - output = self.model.generate( - input_ids, - max_length=input_ids.shape[1] + self.config.vicuna.max_new_tokens, - temperature=self.config.vicuna.temperature, - do_sample=self.config.vicuna.do_sample, - pad_token_id=self.tokenizer.eos_token_id, - ) - - generation = self.tokenizer.decode(output[0][input_ids.shape[1]:], skip_special_tokens=True) - - # Logging input and generation if debugging is active - bittensor.logging.debug("Message: " + str(messages)) - bittensor.logging.debug("Generation: " + str(generation)) - return generation - -if __name__ == "__main__": - bittensor.utils.version_checking() - VicunaMiner().run() \ No newline at end of file diff --git a/neurons/text/prompting/validators/core/gating.py b/neurons/text/prompting/validators/core/gating.py index 4655652df2..5966258192 100644 --- a/neurons/text/prompting/validators/core/gating.py +++ b/neurons/text/prompting/validators/core/gating.py @@ -81,7 +81,7 @@ def __init__( self.num_uids = config.gating.num_uids self.device = torch.device( self.config.neuron.device ) self.tokenizer = AutoTokenizer.from_pretrained( self.config.gating.model_name ) - self.model = AutoModel.from_config( AutoConfig.from_pretrained(self.config.gating.model_name) ) #TODO: add pretrained flag + self.model = AutoModel.from_pretrained( self.config.gating.model_name) self.linear = torch.nn.Linear( self.model.config.hidden_size, config.gating.num_uids ) self.optimizer = torch.optim.SGD( [ {"params": self.parameters()} ], @@ -112,7 +112,7 @@ def forward( self, message: str ) -> 'torch.FloatTensor': scores (:obj:`torch.FloatTensor` of shape :obj:`(network_size)`): Scores for each uids as output by the gating model. """ - inputs = self.tokenizer( message, return_tensors="pt" ).to( self.device ) + inputs = self.tokenizer( message, return_tensors="pt" ,truncation=True, max_length=2048).to( self.device ) with torch.no_grad(): hidden_states = self.model( **inputs ).last_hidden_state[0, -1, :] return self.linear( hidden_states ) diff --git a/neurons/text/prompting/validators/core/neuron.py b/neurons/text/prompting/validators/core/neuron.py index d08301d63b..9830a71bf7 100644 --- a/neurons/text/prompting/validators/core/neuron.py +++ b/neurons/text/prompting/validators/core/neuron.py @@ -32,8 +32,9 @@ from typing import List, Optional, Tuple, Dict from reward import RewardModel from gating import GatingModel -from transformers import AutoTokenizer +from transformers import AutoTokenizer, AutoModelForSequenceClassification from datasets import load_dataset +from datetime import datetime __default_question_prompt__ = ''' Ask me a random question about anything. Make the question very domain specific. Do not include the answer in the question. @@ -115,6 +116,7 @@ def add_args( cls, parser ): parser.add_argument( '--neuron.no_reward_model', action = 'store_true', help = 'If set, we dont load the reward model instead use just the scores.', default = False ) parser.add_argument( '--neuron.question_random_sample_uids', action = 'store_true', help = 'If set, random sample uids to get question.', default = False ) parser.add_argument( '--neuron.reward_shift', type = int, help = 'The value to shift rewards for calculation.', default = 3 ) + parser.add_argument( '--neuron.no_nsfw_filter', action = 'store_true', help = 'If set, allow handling of not-safe-for-work messages.', default = False ) @classmethod def config ( cls ): @@ -178,6 +180,13 @@ def __init__( self ): self.load() self.check_weights() + # set up filter model + filter_model_path = 'facebook/roberta-hate-speech-dynabench-r4-target' + self.filter_model = AutoModelForSequenceClassification.from_pretrained(filter_model_path).to(self.device) + self.filter_tokenizer = AutoTokenizer.from_pretrained(filter_model_path) + self.filter_tokenizer.pad_token = self.filter_tokenizer.eos_token + self.filter_message_count = 0 + # Axon set and served for inference requests, unless --neuron.axon_off flag is set. if not self.config.neuron.axon_off: # Build synapse entrypoint. @@ -227,6 +236,49 @@ def multi_forward( _, messages: List[Dict[str, str]] ) -> str: self.axon.start() self.subtensor.serve_axon( self.config.netuid, self.axon ) + def filter_message( + self, + message + ) -> bool: + """ Check if the message is related to any sexual content. + + Args: + message (str): + The message that we check if we should filter out. + Returns: + result (bool): + True indicates we should filter out the result, false indicates the result is safe. + """ + # If no filter needed, then just return false withough checking. + if self.config.neuron.no_nsfw_filter: + return False + + now = datetime.now() + dt_string = now.strftime("%d/%m/%Y %H:%M:%S") + tokenized = self.filter_tokenizer(message) + input_ids = tokenized['input_ids'] + bound_score1 = 0.5 + bound_score2 = 0.5 + + while len(input_ids) > 0: + _input_ids = input_ids[:512] + + with torch.no_grad(): + output = self.filter_model(torch.tensor([_input_ids]).to(self.device)) + + filter_out = output.logits[0, 0] < bound_score1 or output.logits[0, 1] > bound_score2 + + if filter_out: + bittensor.logging.debug( 'filtered message', message ) + break + else: + bittensor.logging.debug( 'safe message', message ) + + input_ids = input_ids[512:] + + self.filter_message_count += 1 + return filter_out + def forward( self, roles: List[ str ], @@ -389,15 +441,24 @@ def inference( bittensor.logging.info( 'inference()') # Pre-process messages. - roles = []; contents = []; unravelled_message = '' + roles = []; contents = []; unravelled_message = ''; user_message = None for message_dict in messages: roles.append( message_dict['role'] ) contents.append( message_dict['content'] ) if message_dict['role'] == 'system': unravelled_message += 'system: ' + message_dict['content'] + '\n' if message_dict['role'] == 'assistant': unravelled_message += 'assistant: ' + message_dict['content'] + '\n' - if message_dict['role'] == 'user': unravelled_message += 'user: ' + message_dict['content'] + '\n' + if message_dict['role'] == 'user': + unravelled_message += 'user: ' + message_dict['content'] + '\n' + user_message = message_dict['content'] + bittensor.logging.info( 'inference message', str(unravelled_message) ) - + + if user_message and self.filter_message(user_message): + if return_all: + return ['Received possible explicit content.'] + else: + return 'Received possible explicit content.' + # Get scores for query. scores = self.gating_model( unravelled_message ).to( self.device ) bittensor.logging.info( 'inference scores', str(scores) ) @@ -426,18 +487,20 @@ def inference( if return_all: completions = [] for call in forward_calls: - if len( call.completion ) > 0: + if len( call.completion ) > 0 and not self.filter_message(call.completion): completions.append(call.completion) if len(completions) > 0: return completions + else: for call in forward_calls: - if len( call.completion ) > 0: + if len( call.completion ) > 0 and not self.filter_message(call.completion): bittensor.logging.info( 'best completion', call.completion ) return call.completion if return_all: return ['no valid completions'] + else: return 'no valid completions' @@ -447,7 +510,7 @@ def inference( flattened_message_for_reward = '' for role_i, message_i in list(zip(roles, messages)): if role_i != 'system': flattened_message_for_reward += message_i.strip() + '\n\n' - completions = [ call.completion for call in forward_calls if len(call.completion) > 0 ] + completions = [ call.completion for call in forward_calls if len(call.completion) > 0 and not self.filter_message(call.completion) ] flattened_completions_for_reward = [ flattened_message_for_reward + comp.strip() for comp in completions ] # Return best via reward model. @@ -488,8 +551,8 @@ def _get_question(uids, bootstrap_prompt, reset_bootstrap_prompt = False): timeout = 12, ) - successful_questions = [question.completion for question in questions if question is not None and question.completion is not None and len(question.completion) > 10] - full_completions_for_reward = [ bootstrap_prompt + comp.strip() for comp in successful_questions ] + successful_questions = [question.completion for question in questions if question is not None and question.completion is not None and len(question.completion) > 10 and not self.filter_message(question.completion) ] + full_completions_for_reward = [ 'Question: ' + bootstrap_prompt + 'Answer: ' + comp.strip() for comp in successful_questions ] completions_for_reward = [comp.strip() for comp in successful_questions] reward_diffs = self.reward_model.reward( full_completions_for_reward, completions_for_reward, difference = True, shift = self.config.neuron.reward_shift).to( self.device ) @@ -551,10 +614,10 @@ def train( self ): question = False ) - with open('prompt_history.txt', 'a') as file: - file.write(f"{steps} | A score({round(forward_result.rewards.sort(descending = True)[0][0].item(), 4)}): {forward_result.best_completion}" + '\n') - if forward_result is not None: + with open('prompt_history.txt', 'a') as file: + file.write(f"{steps} | A score({round(forward_result.rewards.sort(descending = True)[0][0].item(), 4)}): {forward_result.best_completion}" + '\n') + idx_reward_sorted = forward_result.rewards.sort(descending = True)[1] prompt, reward_diff = self.get_question( uids = forward_result.uids[idx_reward_sorted], diff --git a/tests/integration_tests/test_cli_no_network.py b/tests/integration_tests/test_cli_no_network.py index 18eaed779f..12fbb5a1b5 100644 --- a/tests/integration_tests/test_cli_no_network.py +++ b/tests/integration_tests/test_cli_no_network.py @@ -79,6 +79,7 @@ def construct_config(): return defaults + @unittest.skip("") def test_check_configs(self): config = self.config config.no_prompt = True @@ -114,6 +115,7 @@ def ask_response(prompt: str) -> Any: config.command = cmd cli.check_config(config) + @unittest.skip("") def test_new_coldkey( self ): config = self.config config.wallet.name = "new_coldkey_testwallet" @@ -127,10 +129,10 @@ def test_new_coldkey( self ): config.no_prompt = True config.overwrite_coldkey = True - cli = bittensor.cli(config) cli.run() + @unittest.skip("") def test_new_hotkey( self ): config = self.config config.wallet.name = "new_hotkey_testwallet" @@ -147,6 +149,7 @@ def test_new_hotkey( self ): cli = bittensor.cli(config) cli.run() + @unittest.skip("") def test_regen_coldkey( self ): config = self.config config.wallet.name = "regen_coldkey_testwallet" @@ -165,6 +168,7 @@ def test_regen_coldkey( self ): cli = bittensor.cli(config) cli.run() + @unittest.skip("") def test_regen_coldkeypub( self ): config = self.config config.wallet.name = "regen_coldkeypub_testwallet" @@ -179,6 +183,7 @@ def test_regen_coldkeypub( self ): cli = bittensor.cli(config) cli.run() + @unittest.skip("") def test_regen_hotkey( self ): config = self.config config.wallet.name = "regen_hotkey_testwallet" @@ -341,5 +346,115 @@ class ExitEarlyException(Exception): assert cli.config.subtensor.register.cuda.use_cuda == False + +class TestCLIDefaultsNoNetwork(unittest.TestCase): + _patched_subtensor = None + + @classmethod + def setUpClass(cls) -> None: + mock_delegate_info = { + "hotkey_ss58": "", + "total_stake": bittensor.Balance.from_rao(0), + "nominators": [], + "owner_ss58": "", + "take": 0.18, + "validator_permits": [], + "registrations": [], + "return_per_1000": bittensor.Balance.from_rao(0), + "total_daily_return": bittensor.Balance.from_rao(0) + } + cls._patched_subtensor = patch('bittensor._subtensor.subtensor_mock.mock_subtensor.mock', new=MagicMock( + return_value=MagicMock( + get_subnets=MagicMock(return_value=[1]), # Mock subnet 1 ONLY. + block=10_000, + get_delegates=MagicMock(return_value=[ + bittensor.DelegateInfo( **mock_delegate_info ) + ]), + ) + )) + cls._patched_subtensor.start() + + @classmethod + def tearDownClass(cls) -> None: + cls._patched_subtensor.stop() + + def test_inspect_prompt_wallet_name(self): + # Patch command to exit early + with patch('bittensor._cli.commands.inspect.InspectCommand.run', return_value=None): + + # Test prompt happens when no wallet name is passed + with patch('rich.prompt.Prompt.ask') as mock_ask_prompt: + cli = bittensor.cli(args=[ + 'inspect', + # '--wallet.name', 'mock', + ]) + cli.run() + + # Prompt happened + mock_ask_prompt.assert_called_once() + + # Test NO prompt happens when wallet name is passed + with patch('rich.prompt.Prompt.ask') as mock_ask_prompt: + cli = bittensor.cli(args=[ + 'inspect', + '--wallet.name', 'coolwalletname', + ]) + cli.run() + + # NO prompt happened + mock_ask_prompt.assert_not_called() + + # Test NO prompt happens when wallet name 'default' is passed + with patch('rich.prompt.Prompt.ask') as mock_ask_prompt: + cli = bittensor.cli(args=[ + 'inspect', + '--wallet.name', 'default', + ]) + cli.run() + + # NO prompt happened + mock_ask_prompt.assert_not_called() + + def test_overview_prompt_wallet_name(self): + # Patch command to exit early + with patch('bittensor._cli.commands.overview.OverviewCommand.run', return_value=None): + + # Test prompt happens when no wallet name is passed + with patch('rich.prompt.Prompt.ask') as mock_ask_prompt: + cli = bittensor.cli(args=[ + 'overview', + # '--wallet.name', 'mock', + '--netuid', '1' + ]) + cli.run() + + # Prompt happened + mock_ask_prompt.assert_called_once() + + # Test NO prompt happens when wallet name is passed + with patch('rich.prompt.Prompt.ask') as mock_ask_prompt: + cli = bittensor.cli(args=[ + 'overview', + '--wallet.name', 'coolwalletname', + '--netuid', '1', + ]) + cli.run() + + # NO prompt happened + mock_ask_prompt.assert_not_called() + + # Test NO prompt happens when wallet name 'default' is passed + with patch('rich.prompt.Prompt.ask') as mock_ask_prompt: + cli = bittensor.cli(args=[ + 'overview', + '--wallet.name', 'default', + '--netuid', '1', + ]) + cli.run() + + # NO prompt happened + mock_ask_prompt.assert_not_called() + + if __name__ == "__main__": unittest.main() \ No newline at end of file