What is Bittensor?

Bittensor is an open-source protocol that powers a scalable, decentralized neural network. The system is designed to incentivize the production of artificial intelligence by training models within a blockchain infrastructure and rewarding performance with a custom digital currency.

The network is composed of several thousand nodes, each containing a machine learning model. All nodes are assigned the task of parsing a massive collection of text data, working collaboratively to extract semantic meaning. By way of a consensus mechanism, the system is designed to reward the most value-producing nodes, such that the digital token reaches equivalency with the quality and quantity of representational knowledge in the system.

Ultimately, our vision is to create a pure market for machine intelligence.

What does it do Differently?

Bittensor is an internet-scale mining network that encourages miners to host and train machine learning models. The network uses token-based incentives to promote its growth and to distribute value directly to the individuals providing that value. Bittensor is an open network, accessible to all participants, and no individual or group has full control over its learning, profit generation, or access.

Some key features of Bittensor include:

  • Querying the Bittensor network as a client
  • Running and building Bittensor miners and validators for mining TAO
  • Pulling network state information
  • Managing TAO wallets, balances, transfers, etc.

Documentation Overview

This documentation is divided into several sections to help people get started with Bittensor and Computer Science in general:

  1. Introduction: An overview of Bittensor and its key features (this section)
  2. Skills Required: This is computer science, but for those new to this field, some basics are explained for you.
  3. Usage: Guides on how to use Bittensor as a client, miner, and validator.
  4. API Reference: Detailed information on Bittensor's API and its various functions.
  5. The rest of it: Answers to the enigma that is this network and how it functions from the perspective of code, computer science, and the construction of a Neural Network.

Incentivizing Intelligence We hope you find this documentation helpful as you explore and use Bittensor. If you have any questions or need further assistance, the Bittensor Discord is a great place to learn about the project. Taostats.io is also a great place to see an overview of everything.

Authors Note - update 5/16/2023

As the writer of this documentation, TAOBard, I hereby declare this:

○ I acknowledge most of this is interpretations of AI, but I believe I have sufficiently looked through and read everything and believe it will help any beginner.

○ You are free to alter, download, interpret and otherwise build upon this notebook to create better versions of this documentation.

I intend on releasing further documentation pending further experimentation and consultation with others in the community. I will announce things later on in time through My Twitter

Thank you, and I hope my contribution can spark a new wave of documentation for the Network. Some parts are taken from previous documentation, but I have added a great many files and information with this interpretation of documents. I look forward to learning more and both updating this documentation, but also, to integrate it into a website somewhere and from there, build more mdBooks about other things.

Somebody mentioned I should leave a donation address here - so if you feel so inclined, I would be most grateful. 5Cysz8fsZdCycYicdqxUtbycV9ccBbFsyvkbpnZknRZvKCFR - I will continue to work on furthering documentation, and will have another book sometime soon.

Welcome to TaoDocs - written in mdBook

Hi, I'm TAOBard - this is a community project supported by members of the Bittensor community, though mostly written/interpreted by me. I may quote people from the community, so if you see your words here, it is quite possible I copy pasted it or otherwise re-worded things from a discord thread I was reading into. Any information here that is not mine is either sourced from public documentation, community projects, or verified individuals within the Bittensor community.

I am convinced that the way forward is to educate people as to what is possible on this Network, but also, it's to inform people of a few things:

  1. That what's going on is real and that there is science going on here. Complex algorithms are running this Network, and it is a Decentralized AI. This is factual - any network of sufficient power can run a decentralized miner if they're good enough.
  2. This has been built in relative silence for years. The devs are usually constantly working on projects, and extremely dedicated to building.
  3. To even begin building a Validator on this network, you would need to be at an advanced level in computer science. I would argue intermediate if you're mining, and specializing in ML.

You can learn a lot if you just listen.

I keep my ear to the ground and I've learned a lot just by reading the live-action troubleshooting that goes on in the discord.. you can also ctrl+f and find what you're looking for. That's really the best source of information if you ask me, so if you have questions you're scared to ask, then try searching first. It's likely others have experienced similar issues. That's why it's good to just read what the developers are talking about, even if it's beyond your current comprehension. Eventually, you will have enough knowledge that everything begins to piece itself together.

Somebody with more experience told me this:

I think if you’re new to software development, it’s best to start with the basics of learning Python and Linux/Unix, as you’ll need those the most. Anything beyond that will require some level of university/college math and lots of reading. A good resource to look for are the open college courses that multiple universities are offering online. I know of MIT, Harvard, but I know there are more. They offer both the foundational math and CS courses, but also the AI and ML courses. Once you’ve got the foundations, the best way to learn is to try things in-practice. Check out the hugging face tutorials, and try a simpler NLP, or ML, task, or start a project.

For those new to this project, I welcome you. There are many fascinating characters and determined individuals here, but for the aspiring builder, this is a good place to start from ground zero. Day one. Never ran a Sudo command? Don't know what Nano does? Don't worry, we'll talk about that - but a GPT model could probably explain things better than myself.

The goal here is create a baseline source of documentation to set people on the right path with Bittensor, with the goal of creating more documentation in the future to push this project forward and create better education for people new to Computer Science.

This means we must arm the people with the knowledge of Linux, Python, and the commands found within this intricate network. It is also important to recognize the roles of validators and miners, and we will go into more explanation on their respective sections. This is an opensource project, just as Bittensor itself is. If you think you can contribute to better documentation, then please hop aboard and contribute to the documentation - I am happy to collaborate and integrate better documentation, and I intend on working on more documents within Bittensor itself specifically.

This guide is for those who have just begun, who understand nothing of what is going on in this network, and want insight into what the code is actually doing and how the terms of the Network/analysis of blue-prints given to us.

If you would like to contribute further blue-prints, please get in contact with me as I would be happy to collaborate and learn from peers within the field.

Thank you to everybody who was supported me so far. I am releasing these documents free of charge for anybody to alter and integrate into their own websites. If you feel this knowledge is of use, and you would like to integrate it/alter it into your own website for the purposes of teaching, then feel free. The point of this is that it's open-source - with that being said, this is a blue-print. I will likely update this as time progresses, and I am likely to create a website for this particular book.

Edit - Big thank you to MogMachine for hosting these on taostats.

What Should My Focus Be?

Learning.

This network is massive, increasingly complex, and something that not everybody can build on. Anybody who has ever mined knows it's a full time job, and requires a lot of trouble-shooting and updating. That being said, with the prompting network now a thing, fine-tuning models becomes more understandable as each day progresses. If you put in the time and effort with this network, you will be rewarded - and mining will get easier and more diverse as time progresses.

With multi-modality soon to be integrated over time, there will be many more options as far as mining goes, and there's a lot of opportunity to make TAO as a developer at the moment. If you know how to train LLMs, this is an amazing community to get involved with.

Glossary


Miner Architecture

Miner/Neuron/Peer/Node

Used interchangeably to refer to a participant in the network.

Hotkey

The part of the miner that contains "hot storage". It is loaded into the network and gives ability to set weights (for Validators).

Coldkey

The part of the miner that contains cold storage. Remains on device.

Axon

Servers receive requests from other peers in the network via the axon.

Dendrite

Servers send requests to other peers in the network via the dendrite.

Metagraph

A Python torch object that produces a view into the network. This tool is used internally by Servers and also for network analysis.

Network

Tao

The digital token that functions as currency in the network. Tao uses the same tokenomics as Bitcoin with a 4 year halving cycle and a max supply of 21 millions tokens.

Subtensor

The network blockchain.

Nakamoto

Our main network.

Nobunaga

Our test network.

Block step

Occurs every 12 seconds. The blockchain is updated, and newly minted Tao is distributed to the system.

UID

The unique identifying number for each Miner. Represents its position in the network. There are currently 4096 UIDs available in the network.

Forward Requests

The first stage of the transaction in which a Validator sends data to a Server in the form of tokens, and the the Server sends embeddings back.

Backward Requests

The second stage of the transaction in which the Validator sends feedback (in the form of gradients) to the Server.

Consensus Mechanism

Stake

Equivalent to the amount of Tao attached to the Miner's hotkey. For Validators, more stake translates to rankings being worth more. For Servers, more stake translates to a lower likelihood of being deregistered from the network.

Rank

The raw score given to a Server by a Validators, combined with the stake of the Validator.

Trust

This score represents the number of non-zero (approval) rankings that Servers receives from Validators. The trust score is used to determine whether a Server has achieved consensus in the network. The more stake a Validator has, the more trust scores it can distribute.

Consensus

Achievement of a Server who has received a non-zero ranking from more than 50% of the stake in the network. Servers who reach consensus receive significantly higher rewards than those who have not.

Incentive

The inflation achieved by a Server before dividends are distributed. The incentive is a combination of the rank and consensus scores.

Inflation

The amount of currency (1 tao) released into the network at each block step. The single Tao is distributed amongst all peers in the network according to their performance.

Emissions

Refers to the portion of the one Tao distributed to a single peer each block step.

Dividends

When Validators rank Servers, they take on part ownership of them through the bonding matrix. When a Server's incentive is calculated, a portion of this is distributed to Validators who have bonds.

Bonding Matrix

Refers to the bonds that Validators hold in Servers. The higher the stake the Validator has, and the more staked in the Server, the larger the dividend the Validator will receive.

Embeddings

Also referred to as representations, embeddings are a way of expressing information (i.e the comprehensible meaning of a word) as a very high-dimensional vector.

Logits

The probability of a word in NTP (next token prediction) or MTP (masked token prediction).

Next Token Prediction

Predicting an answer given a context before the place of prediction (i.e. predicting the next word in a sentence).

logit/tokens

Masked Token Prediction

Predicting an answer given a context before and after the place of prediction (i.e. predicting the next word in a sentence).

logit/tokens

Shapely Value

A measure of individuals' contributions in a cooperative game.

Dataset

Bittensor uses a 1.5 Terrabyte corpus dataset for training known as the Mountain.

Sigmoid Function

The sigmoid produces a threshold-like scaling that rewards connected peers and punishes the non-trusted.

Chain Security

Connecting to the Polkadot infrastructure will offer greater network security. Polkadot takes the concept of validation security away from the chain so that the Polkadot relay chain is now responsible for security. Read more about Polkadot security.

The Mountain Dataset

The Mountain Dataset is a Bittensor’s current language modeling dataset consisting of a set of smaller datasets combined together. Currently, it contains ~800 Gb of unlabeled text.

Servers in Bittensor are validated for their ability to understand the text contained in the The Mountain Dataset. To do this, Validators query Servers who must produce embeddings and token predictions in response. Scores derived from these responses determine the incentives Servers see, thus guiding the network to understand the dataset better.

Storage

In order to ensure global access and make the network robust to single points of failure, The Mountain is stored on The InterPlanetary File System (IPFS) as a set of small chunks, files no larger than 1Mb, each containing a small sample of the larger dataset. These small chunks are organized into a set of 22 datasets each with a standard data format, for instance, Arxiv articles or Github code.

Querying

Every file on The Mountain can be accessed via its unique hash. These can be queried directly using a tool like Curl and the hash of the file. For instance, we can query an individual file like so.

Command:

curl -X POST "http://ipfs.opentensor.ai/api/v0/object/get?arg=Qme2dawBzozFGtKWX73fh5fmB8NJD7TRS2XSWKhJB4WbJd"

Output:

"Data": Right now, American protest music sounds like\nthis.\n...we don’t believe you, cuz we the people...\n...a million dollar loan.
...

Organization

The Mountain is organized under the following hash:

QmSdDg6V9dgpdAFtActs75Qfc36qJtm9y8a7yrQ1rHm7ZX

Querying this hash returns the subdirectories of the dataset, for instance, Arxiv, which make up the entire dataset.

Command:

curl -X POST "http://ipfs.opentensor.ai/api/v0/object/get?arg=QmSdDg6V9dgpdAFtActs75Qfc36qJtm9y8a7yrQ1rHm7ZX"

Output:

"Name":"Youtube",
"Hash":"Qme9Rpu1zFT4d2wxzVYiFWHGMDfFkZcQoAougjJreS5nuF",
"Size":262158

"Name":"Arxiv",
"Hash":"QmXABX5KyBsCvi7XzRZVKgAoovR2KgTo45FM51YRnV7hAJ",
"Size": 262158

"Name":"Github",
"Hash":"QmZQwJp21jijtpRpeFD3ZM6p7HLGErde9EgY7Zz8ZRnVuW",
"Size":2 62158
...

The hash of each item above points to a file containing hashes to all text files in that directory. For instance, querying the first element from the list above returns the list of hashes associated with all files in the “Youtube” dataset.

Command:

curl -X POST "http://ipfs.opentensor.ai/api/v0/object/get?arg=QmUzpNL94qN7RFYUkeji2ZGgDDiWALM1MXwu74RNmcov6Q

Output:

"Name": "01-YoutubeSubtitles-5899.txt" 
"Hash": "QmSj7mzxdDw8gd8rqqzijCDxsUs8YRi6EsJtRWiLsHA9Ce", 
"Size": 5173 

"Name": "01-YoutubeSubtitles-59.txt\", 
"Hash": "Qme2dawBzozFGtKWX73fh5fmB8NJD7TRS2XSWKhJB4WbJd", 
"Size": 885 

"Name": "01-YoutubeSubtitles-590.txt\"
"Hash": "QmUSzQgkamYWVhv938nbQgPrQz7CNfpmiUaF36z6Nx6Uzz", 
"Size": 6710 
...

Btcli Guide

I assume most people who use Bittensor frequently probably know what these commands are, but if you're completely new to this project, these are pretty important. There's quite a lot of commands you'll have to learn, but these are some of the foundational things you should learn.

- btcli (insert command) will help you navigate through the network, have this open so you don't have to call -h over and over again. 

- list               - List wallets
- stake              - Stake to your hotkey accounts.
- update             - Update bittensor
- inspect            - Inspect a wallet (cold, hot) pair
- weights            - Show weights from chain.
- unstake            - Unstake from hotkey accounts.
- overview           - Show registered account overview.
- register           - Register a wallet to a network.
- transfer           - Transfer Tao between accounts.
- nominate           - Become a delegate on the network
- new_hotkey         - Creates a new hotkey (for running a miner) under the specified path.
- metagraph          - Metagraph commands
- set_weights        - Setting weights on the chain.
- new_coldkey        - Creates a new coldkey (for containing balance) under the specified path.
- new_hotkey         - Creates a new hotkey (for running a miner) under the specified path.
- my_delegates       - Show all delegates where I am delegating a positive amount of stake
- list_subnets       - List all subnets on the network
- regen_hotkey       - Regenerates a hotkey from a passed mnemonic
- regen_coldkey      - Regenerates a coldkey from a passed value
- delegate           - Delegate Stake to an account.
- undelegate         - Undelegate Stake from an account.
- list_delegates     - List all delegates on the network
- regen_coldkeypub   - Regenerates a coldkeypub from the public part of the coldkey.
- recycle_register   - Register a wallet to a network.```

### This is generated by using btcli -h in a Linux terminal. 

Delegation

Any hotkey may become a delegate and receive nominations of stake from other wallets in the network. Key owners of delegates collect an 18% "take" on emissions of all delegated Tao.

When a coldkey creates a hotkey delegate, it will receive all of the emissions from the stake it adds to its hotkey delegate. The delegate owner will also collect 18% of the emissions from all delegated stake.

Turn your hotkey into a delegate:

btcli nominate

Stake to a delegate account:

btcli delegate

List all the delegates in the network:

btcli list_delegates

Show who you are delegating to:

btcli my_delegates

E = emissions earned by the key per block

Sn = Stake from owner

St = Total stake on hotkey

Delegate key owner

\[ Emissions\ received = \mathrm{E} \cdot 0.18 + \left( \mathrm{Sn} / \mathrm{St} \right) \cdot \left( \mathrm{E} - \mathrm{E} \cdot 0.18 \right) \]

~delegates receive an 18% tax

Delegated stake owners

\[ Emissions\ received = \left( \mathrm{Sn} / \mathrm{St} \right) \cdot \left( \mathrm{E} - \mathrm{E} \cdot 0.18 \right) \]

~delegated stake owners pay an 18% tax through emissions

Taonomics

Tao is the token for Bittensor and gatekeeps access, representing bandwidth to the network. The supply of Tao follows the same emission cycle as Bitcoin, with a max supply of 21,000,000 and a halving cycle every four years. After each cycle, emissions per block decrease by 50%. Currently, one Tao is issued every block (12 seconds). The first halving will be October 2025.

\[ \frac{\sum _{i=0}^{32}210000\left[\frac{50*10^8}{2^i}\right]}{10^8} \]

Emission Split

Servers and Validators evenly split emissions per block, with the most emissions issued to the best-performing Servers.

Validation and B (Bonds)

The Validators determine the proportion of emissions received by each Server in the network. Validators, responsible for validating the action of Servers, assign rankings to Servers based on their performance. In doing so, Validators accumulate bonded relationships in the Servers they rank. Unlike traditional bonding, our bonding is defined by:

\[ {\Delta}{B}={W}*{S} \]

In this way, peers accumulate bonds in the peers they rank, thus ’bonding’ themselves to those that they are connected to.

\[ {\Delta}B_{t+1}={B_t}+{W}*{S} \]

Validators attempting to form a cabal or collude with other Validators will see the size of their bonds diminish. This attack is only possible if the cabal holds more than 50% of the Validation stake in the network. Servers that have yet to reach Consensus recieve exponentially fewer emissions than those that have.

T (Trust)

Trust is the measurement of the number of non-zero rankings Servers receive from Validators.

C (Conensus)

Consensus is defined using a continuous sigmoid function. This sigmoid produces threshold-like scaling, which rewards connected and well-performing Servers and punishes the non-trusted.

\[ {C}={σ}({\rho}({T^T}*{S}-{0.5})) \]

Servers who have reached ‘Consensus’ are peers with non-zero rankings from more than 50% of the Validation stake in the network.

\[ ({T^T}*{S})>{0.5} \]

I (Incentive) + Emissions

As Servers attain more weight in the network they increase their inflation exponentially up to 0.5

\[ {I}={R}*{C} \]

Using the bond matrix, the chain distributes Incentive scores to ensure that each Server receives a fixed proportion of emission in line with their performance in the network.

\[{\Delta}S=0.5B^T*I+0.5I \]

KEY

B = Bonds

C = Consensus

I = Incentive

R = Rank

S = Stake

T = Trust

W = Weight

What is Multi-Modality?

To put it simply, it is the ability for any form of generative AI to plug into the network. This could mean prompting an LLM, an Image network, a Voice network, etc - the options are limitless. These will come to the Network overtime in the form of subnets, as Bittensor grows and develops, I'm sure we will hear more about them. I recommend following the Twitter scene or being in the discords to see the latest updates on what is going on within the community.

It's looking exceedingly brilliant as time goes forward and the subnets are in development.

The following is a summary of the skills one may need to learn as they progress through their journey here.

It should be noted that the field is constantly evolving and shifting, but there is still a baseline.

To operate effectively on the Bittensor network, an individual would need a diverse set of skills that cover the technical, conceptual, and practical aspects of the platform.

Bittensor Skillset Overview

The following summary outlines the essential skills for anyone looking to effectively contribute to the Bittensor network. The field is constantly evolving and shifting; however, these foundational skills provide a solid starting point.

Essential Skills for Bittensor Network Operations

To succeed in the Bittensor ecosystem, individuals should possess a diverse set of skills, covering technical, conceptual, and practical aspects of the platform. Some key skills include:

  1. Python Programming

Proficiency in Python is crucial since the Bittensor library is primarily written in Python.

  1. Machine Learning

A strong understanding of machine learning concepts, particularly deep learning and natural language processing, is essential for building and deploying models on the network.

  1. PyTorch

Familiarity with the PyTorch library is necessary, as Bittensor utilizes it for constructing and training models.

  1. Distributed Systems

An understanding of distributed computing concepts is crucial for working effectively with the decentralized nature of Bittensor.

  1. Cryptography and Blockchain

Knowledge of cryptography and blockchain technology is vital, as the Bittensor network relies on these concepts for security and consensus.

  1. APIs and Networking

Experience working with APIs and networking protocols is essential, given Bittensor's reliance on communication between nodes in the network.

  1. Problem Solving and Debugging

Strong problem-solving and debugging skills are necessary to identify and address issues in a complex environment.

  1. Documentation and Communication

The ability to read and comprehend technical documentation, as well as effectively communicate with other developers and users on the Bittensor platform, is crucial for success in this ecosystem.

Introduction to RLHF(Reinforcement Learning from Human Feedback)

There's a good article on HuggingFace about this subject, but tl;dr:

By interacting with the AI and fine-tuning it towards a particular use-case, you can build good models. If you can build good models, you can be rewarded by the Bittensor Network. Part of the reason it's so competitive here is because the information has long been understood by the people with long-standing, but they're busy. Anybody who works within this ecosystem can tell you two things:

  1. Things move quickly.
  2. Things break and require human input.

Reinforcement Learning from Human Feedback (RLHF)

Reinforcement Learning from Human Feedback (RLHF) is a challenging concept that involves multiple-model training processes and different stages of deployment. In this summary, we break down the training process into three core steps:

  1. Pretraining a language model (LM)
  2. Gathering data and training a reward model
  3. Fine-tuning the LM with reinforcement learning

Pretraining Language Models

As a starting point, RLHF uses a language model that has already been pretrained with classical pretraining objectives. Examples of such models include OpenAI's GPT-3, Anthropic's transformer models, and DeepMind's 280 billion parameter model Gopher. This initial model can be fine-tuned on additional text or conditions, but it's not strictly necessary.

There is no clear answer on the "best" model for the starting point of RLHF, as the design space of options in RLHF training is not thoroughly explored.

Gathering and Generating Data for Training a Reward Model

To train a reward model, you need to gather or generate data that represents human preferences. The process typically involves the following steps:

  1. Collecting demonstrations: Obtain samples of human-generated responses to various input prompts. These demonstrations provide a baseline for what the AI system should be able to achieve.

  2. Creating comparison data: Generate multiple possible responses for a given input using the pretrained language model. Have human raters evaluate and rank these responses based on their quality, relevance, and adherence to other desired criteria.

  3. Aggregating rankings: Aggregate the rankings provided by human raters to create a more robust and reliable dataset for training the reward model.

  4. Training the reward model: Train a reward model using the collected demonstrations and comparison data. This model will be used to evaluate the quality of the AI system's responses during the fine-tuning stage.

Here's a more detailed breakdown of each step:

Collecting Demonstrations

  • Create a set of input prompts that represent a wide range of tasks and situations.
  • Have human experts provide responses to these prompts, following guidelines that emphasize the desired qualities in the AI system's responses.

Creating Comparison Data

  • For each input prompt, generate multiple potential responses using the pretrained language model.
  • Present these responses to human raters, who will rank them based on quality, relevance, and other criteria specified in the guidelines.

Aggregating Rankings

  • Collect rankings from multiple human raters to create a more reliable dataset.
  • Apply statistical techniques, such as the Bradley-Terry model, to aggregate individual rankings into a single, consensus-based ranking.

Training the Reward Model

  • Use the collected demonstrations and aggregated rankings to train a reward model that can evaluate the quality of the AI system's responses.
  • The reward model will be used during the reinforcement learning stage to fine-tune the AI system's responses based on human preferences.

By following these steps, you can gather and generate data that accurately represents human preferences and use it to train a reward model for RLHF.

Fine-Tuning the Language Model with Reinforcement Learning

After gathering data and training the reward model, the next step is to fine-tune the pretrained language model using reinforcement learning. This process involves:

  1. Sampling responses: Generate multiple candidate responses for a given input prompt using the pretrained language model.
  2. Evaluating responses: Use the trained reward model to rank and score the candidate responses based on their quality and adherence to human preferences.
  3. Updating the language model: Apply reinforcement learning algorithms, such as Proximal Policy Optimization (PPO), to update the language model's parameters based on the reward model's evaluations.

Here's a more detailed breakdown of each step:

Sampling Responses

  • For a given input prompt, use the pretrained language model to generate a set of candidate responses.
  • Apply techniques such as temperature scaling, top-k sampling, or nucleus sampling to control the diversity and quality of the generated responses.

Evaluating Responses

  • Use the trained reward model to evaluate and score each candidate response based on its quality, relevance, and alignment with human preferences.
  • These scores will serve as the basis for updating the language model's parameters through reinforcement learning.

Updating the Language Model

  • Apply reinforcement learning algorithms, such as Proximal Policy Optimization (PPO), to update the language model's parameters based on the reward model's evaluations.
  • This process involves optimizing the language model's policy to maximize the expected reward, which in this case is the score assigned by the reward model.

By following these steps, you can fine-tune the pretrained language model to better align with human preferences and improve its overall performance. This process can be iterated multiple times to further refine the AI system's behavior.

Learn to write Documentation!

The Bittensor Network is a massively encompassing space that has many different rabbit-holes. With the implementation of multi-modality, who knows what can be produced on the network. There needs to be people who can help transmit information and explain what the network is. People are constantly asking questions about stuff that has become second nature to those who are building/developing, as well as for those who are active in the community.

Mass Adoption begins with Mass Understanding.

People must first understand the skill sets needed for Bittensor in order to utilize the network to its full capability. There's a lot of holders of TAO, but how many of those holders are actively prompting and participating within the network? Well, all contributions are measured - but for those not so adept at computer science, and curious to prompt, should have easily understandable resources to learn with. It's not quite the simple endeavor to query the network, although, I don't come from comp sci - so perhaps I am wrong.

Advice for Windows Users Before Learning

Learn how to use WSL

The Bittensor Network is a decentralized machine learning platform that enables developers to train and deploy machine learning models in a secure, distributed environment. As a developer, you may need to interact with this network on a regular basis. One way to make this interaction seamless and efficient is by using the Windows Subsystem for Linux (WSL). This essay will discuss the benefits of using WSL for interacting with the Bittensor Network.

Enhanced Developer Experience

WSL allows you to run a Linux distribution alongside your existing Windows operating system. This means that you can leverage the power of both Windows and Linux environments, creating a more versatile development experience. With WSL, you can use the same Linux tools and utilities that you are familiar with, without having to dual boot or set up a virtual machine. This can significantly improve your workflow and productivity when working with the Bittensor Network.

Consistent Cross-Platform Development

When working with decentralized networks like Bittensor, it's important to ensure that your code runs consistently across different platforms. With WSL, you can develop and test your code in a Linux environment, which is often the target environment for many server-side applications. This helps ensure that your code will work as expected when deployed on the Bittensor Network, reducing the chances of encountering platform-specific issues.

Simplified Setup and Configuration

Setting up a development environment for the Bittensor Network may involve installing various dependencies, libraries, and tools. With WSL, you can easily install these components using familiar package managers like apt or yum. This simplifies the setup process and allows you to quickly get started with the Bittensor Network. Furthermore, WSL provides better integration with Windows, making it easier to share files and resources between the two operating systems.

Improved Security

WSL offers a sandboxed environment, isolating your Linux distribution from your Windows system. This can help enhance the security of your development environment, particularly when working with sensitive data or untrusted code on the Bittensor Network. By keeping your Linux environment separate from your primary Windows system, you can minimize potential security risks.

Conclusion

In summary, using the Windows Subsystem for Linux (WSL) to interact with the Bittensor Network offers a range of benefits, including an enhanced developer experience, consistent cross-platform development, simplified setup and configuration, and improved security. By leveraging the power of both Windows and Linux, WSL allows you to work efficiently with the Bittensor Network, ultimately helping you to create more reliable and secure machine learning models in a decentralized environment.

To conclude here, I want to state the most important skill for somebody to have when beginning with Bittensor, even just as a client: Computer Science. You're going to have to learn about Linux, you're going to have to learn about Python scripting - and that's okay. It'll take some time, but if you have ChatGPT or something similar, then you should be able to figure things out just fine. How do you think I wrote these documents? Ain't no way..

Linux_Basics

I must note the importance of being comfortable navigating Linux and reading code when it comes to developing on the Bittensor Network. Rust is also a good language for documentation, as it is easy to lose track of all the knowledge acquired. At some point, it will become second nature - you will remember what cat does, what a pipe is(example | grep), and you will understand how to use WSL. Speaking of WSL, you should refer to the "before you build" section of the Docs.

Here's some basic commands to get you started.

  • ls: list files in the current directory
  • cd: change directory
  • mkdir: make a new directory
  • rmdir: remove a directory
  • touch: create a new file or update the modification time of an existing file
  • rm: remove a file or directory
  • cp: copy files or directories
  • mv: move files or directories
  • cat: display the contents of a file
  • grep: search for a pattern in a file or set of files
  • chmod: change the permissions of a file or directory
  • chown: change the ownership of a file or directory
  • ps: display information about running processes
  • kill: send a signal to a process to terminate it
  • sudo: execute a command as the superuser (root)
  • tar: create or extract compressed archive files
  • ssh: connect to a remote server via SSH protocol
  • scp: copy files between local and remote systems using SSH protocol
  • ping: test network connectivity to a server or website
  • ifconfig: display network interface configuration

How do I learn Linux? - Edit 5/16/2023

Now that's it has released, Bard is a solid option for beginners. It's actually pretty decent - especially if you don't wanna pay for GPT4. Sometimes it can write code that's decent, but a bit spaghetti.

Gpt models. ChatGPT, whatever you can get your hands on is going to be infinitely better than reading a book. Now, if you wish to have a better grasp of what's happening and an in-depth knowledge: that's when you read information. But generally, gpt 3.5 turbo and especially GPT4 are incredible at programming and navigating Linux because there's so much documentation on both those fields in particular. Use GPT, it will be able to explain most things to you.

This is how you would write documentation within mdBook. These are some of the more common symbols used.

First, how does one use mdBook? Why should one learn?

mdBook is a way to write documentation for a project and organize it into a clean, coherent fashion. Depending on the scribe responsible for writing the book, the format, style, and website integration is easy to write it, but requires a different approach and knowledge of commands. If you are interested in furthering Bittensors documentation with your own contributions, mdBook is the format you should use going forward.

Keep in mind, you can find the actual symbols that make the text look this way in the .md file found within src.

Without further ado, here's how you write a .md document

Headers

Header 1

Header 2

Header 3

Header 4

Header 5
Header 6

Emphasis

Italic text Italic text

Bold text Bold text

Bold and italic text Bold and italic text

Lists

Unordered Lists

  • Item 1
  • Item 2
    • Nested Item 2.1
    • Nested Item 2.2
  • Item 3

Ordered Lists

  1. Item 1
  2. Item 2
    1. Nested Item 2.1
    2. Nested Item 2.2
  3. Item 3

Links

Link Text

Images

Alt text for image

Code

Inline code example

Blockquotes

This is a blockquote

Horizontal Rule


Tables

Header 1Header 2Header 3
Cell 1Cell 2Cell 3
Cell 4Cell 5Cell 6

Strikethrough

Strikethrough text

I'm sure there's things I've missed. I want to expand upon the intricacies of structure later on, but the purpose of this is to get others started on the journey.

What is Finney?

But first, who was Finney

Hal Finney was a computer scientist and Cypherpunk who recieved the first Bitcoin from Satoshi Nakamoto in January 2009.

In 2004, Finney created the first reusable proof of work system before Bitcoin.[10] In January 2009, Finney was the Bitcoin network's first transaction recipient from the legendary Satoshi Nakamoto.

This person is of signifigance because he created the blue-print. Bittensor is another take on that blue-print, only this time, it leverages both Block-chain and AI to it's advantage. Without Finney, we wouldn't be here today - so if you want anybody to thank, I would thank him.

Finney Prompt Subnetwork - a.k.a netuid 1

The very first subnetwork on the Finney Network -- prompt subnetworks -- is now available for mining and usage. The prompting subnetwork enables Bittensor to run many prompt neural networks such as GPT-3, GPT-4, ChatGPT, Vicuna, and others to perform decentralized inference. This allows users to communicate with the Validators on the network to get the output of the best performing models on the network to power their applications.

Testing on the prompting Subnet

Using btcli you can specify you wish to run your miner on the testnet by adding the following flags: --subtensor.network finney --subtensor.chain_endpoint wss://test.finney.opentensor.ai:443.

Hardware Requirements

Various sources will tell you various things but I believe there is a baseline:

NetUID 3:

NetUID 3 will soon be decommissioned, meaning that we will begin to see other subnets. Things that allow for multi-modality. If you are unfamiliar with the concept, this means that not only will the network offer LLMs, but ImaGens(image generators), Transcription, Voice generation - and more. The point of this network is to plug any form of generative AI into it, and then use the collective to improve and further the quality and diversity of the networks tools.

To run a Validator on NetUID 1:

GPU machine with 24GB VRAM. 60GB of disk space is enough, though 100GB is good. My sources say that running an A6000 only uses 50% of resources. I suppose you could use that as a benchmark.

NetUID 3 is CPU based and involves a lot of verification but nothing heavier. NetUID 1 requires running a rewarding model which requires GPU. It is gating the prompts and back propagating the responses as far as I am aware. This is more intensive therefore the GPU is required.

Ideally, as time progresses, the models will become smaller - some models may soon run and mine on 3090s or 4090s, so it's perfectly reasonable to assume that Bittensor will soon become more accessible to people.

The same requirements should apply to miners, but the more VRAM and RAM the better, generally speaking. It depends on the model you're serving. A6000 is generally a good baseline though!

Registration

Registration in the prompting network is performed the same way you have always registered, by either solving PoW or using recycle_register. Unless you have the hardware necessary to run 40x 4090s simultaneously(maybe less, maybe more idk), I would suggest: btcli recycle_register

Usage instructions

To utilize the prompt subnetwork, run the following commands in your terminal.

cd ~/.bittensor/bittensor && git pull origin text_prompting
cd ~/.bittensor/bittensor && python3 -m pip install -e .

All the default Servers are in the following directory within the Bittensor root directory (~/.bittensor/bittensor).

For instance, to run a pythia miner, use the following command:

python3 ~/.bittensor/bittensor/neurons/text/prompting/Servers/pythia/neuron.py 

You can still use flags as before. For example to run the pythia miner in the test network (Test network has subnetwork UID 91 as the prompt subnetwork):

python3 ~/.bittensor/bittensor/neurons/text/prompting/Servers/pythia/neuron.py --wallet.name prompt_Servers --wallet.hotkey prompt_miner1 --subtensor.network finney --subtensor.chain_endpoint wss://test.finney.opentensor.ai:443 --netuid 1

You can run the core validator by typing the following:

python3 ~/.bittensor/bittensor/neurons/text/prompting/Validators/core/neuron.py

Example Python Script with a prompt.

import bittensor as bt

response = bt.prompt('What is your name?')

print(response)

This is just one example of a very simple prompt that gets a response from the Network.

The following is some advice/insight into things I've discovered about this Network.

  1. How can I achieve faster responses from my script?
  • More TAO = Faster Prompting. Staked TAO on the Validator hosting your particular prompting Network, prompted with your wallet, allows you to earn TAO whilst using it as an API.
  • The more you stake, the faster your query.
  1. How can I get TAO?
  • Tensor Exchange is a trading platform for TAO that exchanges BTC for TAO
  • You can use BTC or Stripe(card) payments to rent RunPod Servers or other GPU hosting services, Fine tune a model and mine TAO with it.
  • Stake your TAO to stack your RAO.
  1. Why is it so complicated?
  • If it was easy, everybody would be doing it. It'll get easier over time, and soon we'll see the application side of this technology.

More Prompting Examples - Updated 5/15/23

Here's a really basic example that will suffice for now, more updates to come soon!

llm = bt.BittensorLLM()
llm('What is the capital of Texas?')

Validator Information Signing from

bittensor/bittensor/scripts/validator_info_signature/generate.py

This script gathers information about a validator and creates a signed message for that information. The information includes the mnemonic of the validator's hotkey, a descriptive name, a URL, and a short description.

Process

  1. Import the required libraries: json and bittensor.
  2. Request user input for the following information:
    • Validator's hotkey mnemonic
    • Descriptive name for the validator
    • Validator URL
    • Short description for the validator
  3. Create a keypair from the mnemonic.
  4. Create a dictionary with the validator's information.
  5. Convert the dictionary to a JSON-formatted string.
  6. Sign the JSON string using the keypair.
  7. Verify the signature and print the results.

Functions

bittensor.Keypair.create_from_mnemonic(mnemonic)

  • Description: Creates a keypair object from a given mnemonic.
  • Parameters:
    • mnemonic (str): The mnemonic string for the validator's hotkey.
  • Returns: A bittensor.Keypair object.

bittensor.Keypair(ss58_address)

  • Description: Initializes a keypair object with the given SS58 address.
  • Parameters:
    • ss58_address (str): The SS58 address of the keypair.
  • Returns: A bittensor.Keypair object.

keypair.sign(data)

  • Description: Signs a message (data) using the keypair.
  • Parameters:
    • data (str): The message to be signed.
  • Returns: A signature string.

bittensor.Keypair.verify(data, signature)

  • Description: Verifies the signature of a signed message using the keypair.
  • Parameters:
    • data (str): The original message that was signed.
    • signature (str): The signature of the message.
  • Returns: A boolean value indicating whether the signature is valid (True) or not (False).

Verify Validator from

bittensor/bittensor/scripts/validator_info_signature/verify.py This script verifies the validator's signed information provided by the user. The user needs to input the validator information and the validator signature. This is a literal interpretation of code by an LLM.

Process

  1. Import the required libraries: json, bittensor, and binascii.
  2. Request user input for the following information:
    • Validator information
    • Validator signature
  3. Convert the signature from hexadecimal to binary.
  4. Create a keypair using the validator's SS58 address.
  5. Verify the signature using the keypair and print the results.

Functions

bittensor.Keypair(ss58_address)

  • Description: Initializes a keypair object with the given SS58 address.
  • Parameters:
    • ss58_address (str): The SS58 address of the keypair.
  • Returns: A bittensor.Keypair object.

binascii.unhexlify(data)

  • Description: Converts a hexadecimal string to binary data.
  • Parameters:
    • data (str): The hexadecimal string to be converted.
  • Returns: Binary data.

keypair.verify(data, signature)

  • Description: Verifies the signature of a signed message using the keypair.
  • Parameters:
    • data (str): The original message that was signed.
    • signature (str): The signature of the message.
  • Returns: A boolean value indicating whether the signature is valid (True) or not (False).

Gating model High Level Over-view

This file defines a GatingModel class, which is a PyTorch module designed for the Bittensor network. At a high level, the class is responsible for encoding input messages, generating scores for each unique identifier (uid) in the network, and updating the model based on mean squared error loss between the normalized scores and normalized rewards.

The GatingModel class leverages a pre-trained transformer-based language model as its encoding layer. It then applies a linear layer to generate scores for each uid. To optimize the model, it uses the stochastic gradient descent (SGD) algorithm with configurable learning rate and momentum.

To use the class, a user needs to create an instance of GatingModel, providing necessary configuration details, such as the pre-trained model name and number of uids. Once the instance is created, the user can call the forward method to obtain scores for a given input message and use the backward method to update the model based on rewards obtained from the network.

Overall, this file provides a flexible and configurable solution for creating and updating a gating model that can be easily integrated into the Bittensor network.

This chapter explains the GatingModel class, which is a PyTorch module for creating a gating model in the Bittensor network. The main functions of this module are:

Encoding input messages and generating scores for each unique identifier (uid) in the network. Running a backward pass through the model using mean squared error between normalized scores and normalized rewards as the loss function.

Methods

• add_args: Adds command line arguments to configure the gating model. • config: Returns a configuration object containing the command line arguments for the gating model. • check_config: Validates the configuration object for the gating model. • init: Initializes the gating model. • backward: Runs a backward pass through the model. • forward: Runs a forward pass through the model, encoding the input message and generating scores for each uid in the network.

def add_args(cls, parser: argparse.ArgumentParser)

Usage

The module uses a pre-trained transformer-based language model as the encoding layer and a linear layer to generate scores for each uid. The model is optimized using the stochastic gradient descent (SGD) algorithm.

To use the gating model, a user would first create an instance of the GatingModel class with the desired configuration and then run the forward and backward methods for their specific use case.

Code Summary of

_neuron/text/core_validator/__init__.py

This Python script defines a class called neuron that acts as a core component in a distributed machine learning network. It is responsible for managing the network communication, the model training, and the reward distribution among peers.

Key Components

Constants

  • __default_question_prompt__: The default prompt used for generating questions from the network to evaluate other miners.
  • __default_base_prompt__: The default base prompt injected before a question is completed by miners on the network.

Class Definition: neuron

This class is responsible for initializing and managing the network communication, model training, and reward distribution among the peers.

Methods:

  • check_config(cls, config): Validates the config namespace object and sets up the directories required for logging and reward models.
  • record_event(self, event): Records a forward event in the history queue and logs the event if specified in the config.
  • add_args(cls, parser): Adds the command-line arguments required for the neuron configuration.
  • config(cls): Generates the configuration object using the command-line arguments.
  • __init__(self): Initializes the neuron instance with the required components like subtensor, wallet, metagraph, tokenizer, reward model, gating model, dendrite pool, history queue, and axon.

Forward Method:

  • forward(self, roles, messages, topk, random_sample_uids, train_gating_model, train_network, timeout): Queries the network for a response to the passed message using a gating model to select the best uids. Trains the gating model based on the rewards calculated for the successful completions and passes rewards backward for potential PPO.

Execution Flow

The script initializes a neuron instance and starts the network communication and model training. The neuron class takes care of the communication with other peers in the network and manages the mining process.

Additional Methods

inference(self, messages: List[Dict[str, str]]) -> str

  • Logs the inference process.
  • Pre-processes the messages to extract roles and contents.
  • Gets scores for the query from the gating model.
  • Gets uids for the query based on the scores.
  • Queries the network using the dendrite pool.
  • Applies the reward model to choose the best completion from the responses.
  • Returns the best completion.

train(self)

  • Runs an infinite loop for training.
    • Queries the network for a random question and saves it.
    • Asks the network to complete the random question while training the gating network.
    • Syncs the metagraph and updates nominators.
    • Computes and sets the weights on the blockchain.

compute_weights(self) -> Tuple[torch.LongTensor, torch.FloatTensor]

  • Computes the average reward for each uid across non-zero values using the rewards history.
  • Normalizes the rewards with a softmax and performs a moving average of the normalized rewards.
  • If the hotkeys have changed, resets the moving averaged scores for the new hotkeys.
  • Calculates the average reward for each uid across non-zero values.
  • Processes the raw weights to final_weights via subtensor limitations.
  • Returns the processed weights and uids.

Execution Flow

When the script is run, it initializes a neuron instance and enters an infinite loop, periodically calling the train() method to train the model and update the weights on the blockchain.

In Conclusion,

There's a lot going on here, and I think it's best to investigate yourself, but the goal is to give people the proper tools and knowledge required to build on the network. This knowledge could be quite important depending on what your goals are here.

__bittensor/miners/Core Validator.py Analysis__

It is important to note here that I couldn't explain what the code actually does if you asked me. In fact, I didn't. If it seems inaccurate to you, then tell me and I can correct it. The explanation makes sense, I just couldn't explain it.

The code revolves around the following concepts:

Querying multiple machine learning models (endpoints) and aggregating their predictions. Calculating Shapley values and Shapley synergies to evaluate the contributions of each model in a coalition. Formatting the predictions and logging results for a better understanding of model performance and interactions.

The main functions of the code can be summarized as follows:

  1. query function: Sends queries to multiple endpoints (models), collects their responses, and returns the aggregated results along with endpoint statistics.
  2. shapley function: Calculates Shapley values based on endpoint statistics and the loss values of each model in a coalition.
  3. shapley_synergy function: Calculates Shapley synergies for coalitions of size 2, measuring the performance improvement over expected individual model performance.
  4. format_predictions function: Formats the batch task top-k predictions for a rich table print of query responses.
  5. unsuccess function: Prints the return codes and response times of unsuccessful responses.

Overall, the purpose of this Python file is to handle interactions between multiple machine learning models, evaluate their performance and contributions to a coalition, and format the results for better understanding and visualization.

Bittensor Consensus Overview

Consensus in the Bittensor network is essential for maintaining a decentralized, distributed network's integrity and security. It involves reaching an agreement among participating nodes on the state of the network, particularly the weights assigned to each miner.

Key Components of Consensus

  1. Weight updates: Agreement on weight updates for each miner, representing their contribution to the network.
  2. Metagraph: Data structure that keeps track of the miners' weights and stake, updated as part of the consensus process.
  3. Weight normalization: Ensuring that the total weight in the network remains constant by normalizing weight updates.
  4. Block validation: Validators (miners) propose and validate blocks containing weight updates in the PoS-based consensus.
  5. Staking: Validators (miners) stake Subtensor tokens to participate in the consensus process, incentivizing honest behavior.

CLM Model Tuning

Authors Note: This was taken from the official documentation, as are some other things. Fine-tuning a model is difficult, but this will give you insight into the commands and navigation to get towards fine-tuning models.

Note: This script was adapted from Hugging Face's Transformers/language-modeling code.

Welcome to the CLM Model Tuning walkthrough. This section will guide you through how to install and use our guide to fine-tune your models.

Language model tuning preface

Fine-tuning the library models for language modeling on a text dataset for models like GPT and GPT-2. Causal languages like this are trained or fine-tuned using a causal language modeling (CLM) loss.

In theory, serving a tuned model can increase incentive and earnings on the Bittensor network. However this depends on many factors: the choice of model, the data used for tuning, and (to a lesser extent), the hyperparameters used for tuning itself. This is not a silver bullet that will immediately guarantee higher earnings, but differences will be more pronounced once the Synapse update is released (time of writing: July 25, 2022).

In the following examples, we will run on datasets hosted on Bittensor's IPFS Genesis Dataset, on Hugging Face's dataset hub, or with your own text files.

For a full list of models that will work with this script, refer to this link.

Installation and requirements

This code assumes you have Bittensor already installed on your machine and is meant to be run entirely separately. Some basic linux command line knowledge is assumed, but this guide should provide a good starting point to navigate and move around files, directories, etc.

To start, clone this repository:

git clone https://github.com/opentensor/clm_model_tuning 

Install the additional packages for this script:

pip install -r requirements.txt

All of the following commands assume you are working from this folder:

cd clm_model_tuning

Fine-tuning on Bittensor

By default, this script will fine-tune GPT2 for Bittensor's mountain dataset. Running:

python3 finetune_using_clm.py

will tune gpt2 with Bittensor's dataset and save the output to tuned-model.

To change the model you are tuning to, e.g. distilgpt2, run:

python3 finetune_using_clm.py model.name=distilgpt2

A full list of models that can be trained by this script are available on Hugging Face.

Fine-tuning on Hugging Face datasets

Any text dataset on Hugging Face should work by default by overriding the dataset.name and dataset.config parameters:

python3 finetune_using_clm.py dataset.name=wikitext dataset.config_name=wikitext-103-v1

Fine-tuning on your own data

If you have a .txt file saved locally, you can override dataset.name:

python3 finetune_using_clm.py dataset.name=./path/to/your/data.txt

Note if using your own data, you may have many short sentences and the block size may be insufficient for reasonable performance. It's recommended you pass the flag dataset.concatenate_raw=true to give the model more context when training. This will reduce the number of batches.

Configuring training parameters

All configurable parameters are visible and documented in conf/config.yaml. The defaults are chosen for quick training and not tuned; you will need to experiment and adjust these.

Note: The above parameters are the only commands you can override with this script. That is, you may not pass flags you would normally use when running btcli (i.e. --neuron.device will not work). If there is a flag you wish to modify feel free to submit a feature request.

To view the changeable parameters, open conf/config.yaml in whatever text editor you prefer, or use cat conf/config.yaml to view them.

You do not need to edit this file to change the parameters; they may be overridden when you call this script. e.g., if you wish to change the model to distilgpt2, and the output directory to distilgpt-tuned, you would run:

python3 finetune_using_clm.py model.name=distilgpt2 output_dir=distilgpt-tuned

Note the nested structure in the config, since model is above name in conf.yaml, you must override model.name when invoking the command.

Serving custom models on Bittensor

To serve your tuned model on Bittensor, just override neuron.model_name with the path to your tuned model:

btcli run ..... --neuron.model_name=/home/{YOUR_USENAME}/clm_model_tuning/tuned-model

Limitations and warnings

Early stopping is not yet supported. Many features are implemented but not thoroughly tested, if you encounter an issue, reach out on discord or (preferably) create an issue on this github page.

What are some good base models?

Llama models and their variants such as Vicuna are also good and this one actually has a template on Runpod. Eleuther models are good.

Authors note: If you would like to contribute to this list, please tell me why these models are good and what other models are good for Bittensor miners.

What is an Epoch?

Epochs in Bittensor Network

Epochs in the context of the Bittensor network are used to manage the update and synchronization process of the network's state, including the weights of the neurons (network participants). Each epoch represents a time period during which the network participants train their models, exchange information, and update their local states. At the end of an epoch, the updated weights are submitted to the network, and a new epoch begins.

In Bittensor, the concept of epochs serves several purposes:

1. Synchronization

Epochs help synchronize the state of the network. By having a fixed time period during which participants can train their models and exchange information, the network ensures that all nodes have a chance to update their local states before the next epoch begins.

2. Weight updates

At the end of each epoch, the updated weights are submitted to the network, which helps maintain the global state and improve the overall performance of the network.

3. Incentivization

Bittensor uses a staking mechanism to incentivize network participants. By participating in the network and submitting their weights at the end of each epoch, participants can earn rewards in the form of tokens.

4. Decentralization

By dividing the network's operation into epochs, Bittensor ensures that no single participant has control over the entire network. This promotes decentralization and helps maintain the network's security and stability.

In summary, epochs in the Bittensor network are used to manage the update process, synchronize the network's state, incentivize participants, and promote decentralization.

Function: run_epoch

The run_epoch function executes a single validator epoch. It applies batches until the epoch length is exhausted. Occasionally, the validator nucleus is reset to ensure it doesn't converge too far. At the end of the epoch, weights are set on the chain and optionally logged to wandb.

Code Explanation

  1. Get parameters for the epoch depending on the selected network (either 'nakamoto' or 'finney'). Parameters include batch_size, sequence_length, prune_len, logits_divergence, min_allowed_weights, max_weight_limit, scaling_law_power, and synergy_scaling_law_power.

  2. Update the dataset size based on the calculated batch_size, sequence_length, and validation_len.

  3. Run the epoch: a. Initialize epoch-related variables like epoch_steps, epoch_responsive_uids, epoch_queried_uids, and epoch_start_time. b. Log the start of the epoch using wandb and prometheus. c. Run a loop until either the block count or the time limit is reached. i. Log the current state of the epoch. ii. Perform a forward pass through the network and calculate the loss and endpoint scores. iii. Perform a backward pass if the loss has a gradient. iv. Update neuron stats, responsive_uids, and queried_uids. v. Update the state of the epoch, including the global_step and current_block. vi. Perform optimization steps. vii. Log the state of the epoch using console messages, console tables, prometheus, and wandb. viii.Reset the metagraph.

  4. Calculate neuron weights at the end of the epoch.

  5. Set weights on the chain using the calculated weights.

  6. Log the end of the epoch using console messages, console tables, prometheus, and wandb.

  7. Increment the epoch counter.

Authors Notes

If you think this is wrong, this is an LLMs interpretation and explanation, not mine. I did proof-read and edit everything, but I'm still learning about this network, same as everybody else - this does however, all make sense from my perspective of what I know. That is to say: AI knows more about itself than I know of it.

Miner Template Analysis

The provided code analysis is of a benchmarking superclass for the Bittensor framework. It measures the performance of miners with respect to query execution, allowing for customization and testing of various parameters.

Key Components

  1. init(self): Initializes the benchmark background processes and sets up the logging directory.

  2. benchmark_config(cls): Retrieves the configuration from the argument parser.

  3. add_args(cls, parser): Adds command-line arguments for configuration.

  4. miner_name(): Returns the miner's name as a string. This method should be implemented in the subclass.

  5. run_neuron(config): This method should be implemented in the subclass to run the neuron using the provided configuration.

  6. config(): Returns the configuration object for the miner. This method should be implemented in the subclass.

  7. _run_background_process(self, run_neuron_func, config_func): Initializes the background process by pulling the configuration and starting the subclass static run method.

  8. startup(self): Starts the mining process in the background.

  9. shutdown(self): Terminates the mining process.

  10. find_endpoint(self): Finds the background neuron axon endpoint from the chain.

  11. dend_forward(args): Handles the dendrite request for the multiprocessing case.

  12. query_sequence(self, ncalls:int, batch_size:int, block_size:int): Queries the background neuron with the specified parameters.

  13. print_query_analysis(self, history): Prints the analysis of the query trial.

  14. run_standard_benchmark(self): Runs the default query sizes for benchmarking.

  15. run(self): Executes all methods with the benchmark_ prefix.

How to use it

To create your own benchmark for your miner, you need to subclass QueryBenchmark and implement the miner_name(), run_neuron(config), and config() methods. Additionally, you can create custom benchmark methods by adding functions with the benchmark_ prefix. These functions will be automatically executed when the run() method is called.

Once you've created your custom benchmark class, you can run the benchmarking script and analyze the performance of your miner with different configurations and parameters.

Miner Template Analysis

The provided code analysis is of a miner template for benchmarking using the Bittensor framework. It's designed to be a starting point for creating a custom miner, and measures its performance with respect to query execution. The template extends the QueryBenchmark class and provides methods for running the miner and configuring it.

What it does

  1. miner_name(): This method returns the miner's name as a string, which is set to 'template_miner' in this case.

  2. run_neuron(config): This method takes a Bittensor configuration object as input and runs the neuron using the template_miner implementation.

  3. config(): This method returns the configuration object for the miner.

  4. benchmark_custom(): This method runs the custom benchmark by performing a sequence of queries with a specified number of calls, batch size, and block size. It then prints the query analysis and saves the results to a CSV file.

  5. The main function initializes a Benchmark object and runs the benchmark.

Adapting the template to your own miner

To adapt this template to your own miner, you need to make the following changes:

  1. Update the miner_name() method to return your custom miner's name.

  2. Modify the run_neuron(config) method to use your custom miner's neuron implementation. Replace bittensor.neurons.text.template_miner.neuron with your own miner's neuron class.

  3. Update the config() method to return the configuration object for your custom miner. Replace bittensor.neurons.text.template_miner.neuron.config() with the configuration method for your miner's neuron class.

  4. Customize the benchmark_custom() method if you have specific benchmarking requirements. You can modify the number of calls, batch size, and block size, or implement additional benchmarking tests.

  5. If your custom miner requires additional configuration or setup, you can add those steps in the main function or in a separate method.

After making these changes, you can run the benchmarking script for your custom miner and analyze its performance.

Cuda PoW and Explanation.

Bittensor is a decentralized machine learning platform, and CUDA (Compute Unified Device Architecture) is a parallel computing platform and application programming interface (API) model created by NVIDIA. CUDA allows developers to use NVIDIA GPUs to perform general-purpose computing, significantly accelerating the processing of computationally intensive tasks, such as deep learning and other machine learning applications.

In the context of Bittensor, CUDA plays a crucial role in speeding up the training and inference processes of deep learning models. Since Bittensor relies on PyTorch for building and training models, and PyTorch has native support for CUDA, the interaction between Bittensor and CUDA is mainly through PyTorch.

When you use Bittensor with an NVIDIA GPU that supports CUDA, PyTorch automatically leverages CUDA to accelerate the computation of tensors and neural network operations. This results in faster training and inference times, making it more efficient to participate in the Bittensor network as a miner or contributor.

In summary, Bittensor and CUDA interact indirectly through the PyTorch library. CUDA accelerates the machine learning tasks in Bittensor by enabling the efficient use of NVIDIA GPUs for parallel computation. This improves the overall performance of the Bittensor network, allowing for more efficient training and inference of deep learning models.

But what does that really mean?

Well, if you think about how Bittensor is a decentralized ML platform, and CUDA provides the best parallel compute, meaning:

○ When a prompt is run, many machines consult with one another, let's say 16 for a Chattensor or other LLM interface on the network -

These responses are judged by how accurate they are. Consensus is reached on the best answer, which is then returned by the machines. There is more on Consensus in this documentation.

Interpreted from bittensor/bittensor/_keyfile/keyfile_impl.py

Keyfile and MockKeyfile Overview

This code defines two classes, Keyfile and MockKeyfile, which are responsible for handling keyfile operations for the Bittensor project. These classes provide methods for creating, reading, writing, encrypting, and decrypting keyfiles, as well as managing their respective keypairs.

Keyfile Class

The Keyfile class is designed to manage keyfiles on the device. Key methods include:

  • Creating and initializing a new keyfile.
  • Reading and writing keyfile data to the file system.
  • Encrypting and decrypting keyfiles with a password.
  • Checking if a keyfile exists, is readable, writable, or encrypted.

MockKeyfile Class

The MockKeyfile class provides an interface for a mocked keyfile object that does not interact with the device's file system. It is useful for testing and development purposes. The keypair is treated as non-encrypted, and the data is stored as a string.

Key methods include:

  • Initializing a new mock keyfile.
  • Returning the mock keypair and keyfile data.
  • Setting a new keypair in the mock keyfile.
  • Providing dummy methods for file operations, such as checking if the file exists, is readable, writable, or encrypted.

By using the Keyfile and MockKeyfile classes, developers can easily manage keyfiles and their associated keypairs, ensuring proper encryption and access control for secure Bittensor operations.

How does the bounty system work?

It is important to note here that Bounties have been a concept in programming for a long time, if you're willing the learn it's a decent way for any computer scientist to make some cash - the core of it's philosophy is this: Do good work, recieve money. Here on the Bittensor Network, it is no different, but the current bounties revolve around training Langauge models generally - there are also community funded endeavors, and those happen on more of an individual basis. With that being said, if you think you can help people with their project, then show you are capable and work may come your way. Or, feel free to submit a formal application towards Bittensors e-mail and put yourself out there. Work cannot find you if you have no projects to showcase your abilities, so start building.

The difference here is that these bounties are to build text-prompting miners, which are an increasingly complex topic to explain as time goes on. I'm sure that as models become out-dated, some people will display their miners, but text-prompting in particular is quite new for Bittensor. As I discover more, I will put more on how miners function and their foundational architecture - but for now, I only know that there's work to be done if you're a ML Engineer and want to plug-in to Bittensor(which you should).

GenesisTextDataset

This is a summary of Functions found within -

bittensor/bittensor/_dataset/dataset_impl.py

To give a high level overview of what this script does:

GenesisTextDataset is a class designed to handle text datasets for training language models. It uses IPFS (InterPlanetary File System) as a source for the text data and allows the user to load data from IPFS or a local directory. It provides methods to create a PyTorch DataLoader, reserve text data, and update the data size.

Key Functions

construct_text_corpus

This function generates the text data by getting directories from a random dataset hash and picking a random directory to get the text from. It repeats this process until the minimum data length is reached.

reserve_multiple_data

This function reserves the data to ensure that it meets the specified multiple of the dataset size. If not, it keeps constructing text corpus until the required size is met.

set_data_size

This function updates the size of data (batch_size, block_size) required for the DataLoader.

dataloader

This function creates a PyTorch DataLoader from a subclass of this class, using the reserved data and the specified data size.

set_dataset_iterator

This function gets a new dataset from the data queue and updates the __infinite_dataset_iterator__ attribute.

next

This method returns the next element from the dataset.

len

This method returns the number of samples (blocks) of the dataset.

getitem

This method returns a block of sentences from the text dataset at a given index.

build_hash_table

This function builds a hash table with dataset hashes and metadata.

Dataset class

Implements a dataset class that handles data loading from IPFS. Key methods include:

  • requests_retry_session: Creates a retriable session for request calls, enabling automatic retries and back-off retries should any request calls fail.

  • get_ipfs_directory: Connects to IPFS gateway and retrieves a directory, returning a dictionary of the files inside of the genesis_datasets and their hashes.

  • __len__: Returns the length of the dataset that the dataset is processing.

  • __getitem__: Returns the next batch from the dataset.

GenesisTextDataset class

Inherits from the Dataset class and caters for data from IPFS. Key features include:

  • Initialization: Initializes important attributes like block_size, batch_size, num_workers, tokenizer, dataset_names, data_dir, save_dataset, and others.

  • Ensures dataset_names is formatted correctly, removing invalid datasets.

  • Retrieves a random slice of the genesis dataset.

  • Builds a hash table.

  • Creates a ThreadQueue instance for a data queue, which reserves multiple data in batches.

  • __del__ and close: Close the data queue.

  • get_folder_size: Get the size (in bytes) of a folder inside the data_dir.

  • load_hash: Load a hash from disk, returning the text in the file.

  • save_hash: Save a hash to disk, taking a file_meta dictionary and text as input.

  • get_text: Either load a file from disk or download it from IPFS, returning the text from the file.

  • get_dataset: Either load a dataset (a list of hashes) from disk or download it from IPFS.

  • get_hashes_from_dataset: Get directories, where a directory could lead to a data file or a directory file, returning a list of directories (random directory that leads to a data file).

  • get_root_text_hash: With recursion, get a random directory that leads to a data file from the given directory.

  • get_text_from_local: Load text data from the local data directory, returning a list of text data.

  • construct_text_corpus: Main function for generating the text data, returning the text corpus.

  • reserve_multiple_data: Make sure the reserved data meet the given multiples. If not, keep constructing the text corpus.

  • set_data_size: Update the size of data (batch_size, block_size) that is needed.

  • dataloader: Creates a torch dataloader out of a subclass of this class.

  • set_dataset_iterator: Get a new dataset that is ready from the queue. The result is updated to self.__infinite_dataset_iterator__.

  • __next__: Returns the next element from the dataset.

  • __len__: Returns the number of samples (blocks) of the dataset.

  • __getitem__: Returns a block of sentences from the text dataset.

  • build_hash_table: Builds a hash table containing dataset hashes.

/bittensor/bittensor/_dataset/MockGenesisTextDataset.py

Class: MockGenesisTextDataset

MockGenesisTextDataset is a subclass of dataset_impl.Dataset. It provides functionalities for creating a mock text dataset for testing purposes.

Methods:

  • __init__(self, block_size, batch_size, num_workers, dataset_names, data_dir, save_dataset, max_datasets, no_tokenizer, num_batches): Initializes the class with parameters.
  • close(self): Closes the dataset.
  • construct_text_corpus(self, min_data_len): Constructs a text corpus of a given minimum length using a fixed placeholder text.
  • _fill_data(self, epoch_length): Fills the data with a specified epoch_length.
  • dataloader(self, epoch_length): Creates a torch dataloader from a subclass of this class.
  • __next__(self): Returns the next element from the dataset.
  • __len__(self): Returns the number of samples (blocks) in the dataset.
  • __getitem__(self, idx): Returns a block of sentences from the text dataset based on the given index.

But what does this mean?

Guess you'll have to figure it out.

bittensor/bittensor/_logging/__init__.py

Bittensor Logging Overview

The following code block defines a logging class for Bittensor that standardizes the logging process. The class supports setting logging levels, customizing log messages, and sinking logs to files for storage.

Introduction to Logging in Bittensor

Bittensor is a distributed machine learning framework that leverages blockchain technology. It provides a decentralized platform for training AI models in a collaborative manner. One of the essential aspects of any software system is the logging mechanism, and Bittensor is no exception. Logging helps developers monitor the system's behavior, track errors, and debug issues efficiently.

In Bittensor, logging is implemented using a customized version of the Loguru library. Loguru is a powerful and flexible logging library for Python that offers simplicity, performance, and reliability. Bittensor's logging mechanism is designed to provide a standardized and structured approach to logging throughout the system, ensuring that log messages are consistent, readable, and maintainable.

The logging system in Bittensor consists of several class methods responsible for formatting, filtering, and logging messages. These methods are organized into a custom logger class, which is then used throughout the Bittensor library to generate log messages. Key features of the Bittensor logging mechanism include:

  1. Custom Formatters: Bittensor's logging mechanism provides custom formatters for both terminal display and file output. This allows for a consistent log format that can be customized based on the needs of the developer or the specific situation.

  2. Conditional Formatting: The logging system adjusts the formatting of log messages based on specific keys in the record's 'extra' field, such as 'rpc' and 'receptor'. This allows for more informative log messages and helps developers quickly understand the context of each log entry.

  3. Log Levels: Bittensor's logging mechanism supports various log levels, including success, warning, error, and info. These log levels help developers filter log messages and focus on the most relevant information for their needs.

  4. Trace Information: When enabled, the logging system can include trace information in log messages, such as the function name and line number. This can be useful for debugging purposes and for understanding the flow of execution within the system.

By leveraging the power and flexibility of Loguru, Bittensor's logging mechanism provides a robust and user-friendly way to monitor and debug the distributed machine learning system. With a standardized approach to logging, developers can easily understand the system's behavior and quickly identify and resolve issues.

Logging Class

The logging class provides methods to manage Bittensor's logging system. The key aspects of the class are:

  • Instantiating the logging system with various configuration options.
  • Adding and removing log sinks.
  • Filtering logs based on the chosen logging level (debug, trace, etc.).
  • Saving logs to files with log rotation and retention.
  • Providing helper methods for configuration and debugging.

Instantiating Logging

The __new__() method initializes the logging system with various options such as:

  • Enabling or disabling debugging and trace information.
  • Turning on or off logging to a file.
  • Specifying the directory where logs are saved.

Adding and Removing Log Sinks

The class manages log sinks, which determine where log messages are sent. The __std_sink__ sends log messages to sys.stdout, while __file_sink__ sinks logs to a file. The class also provides methods to remove existing sinks.

Log Filtering

The log_filter() and log_save_filter() methods are used to filter logs based on the current logging level (debug or trace). This helps control the verbosity of log messages displayed or saved.

Configuration and Helper Methods

The class provides several methods to handle configuration and debugging:

  • config(): Retrieves the config object from the argument parser.
  • help(): Prints help information to stdout.
  • add_args(): Adds arguments to the argument parser for logging configuration.
  • add_defaults(): Sets default values for the logging configuration based on environment variables.
  • check_config(): Checks the validity of the given config object.
  • set_debug(): Enables or disables the debug logging level.
  • set_trace(): Enables or disables the trace logging level.

With the logging class, developers can easily manage the logging system for Bittensor, ensuring consistent logging output and behavior across different parts of the project.

Bittensor Logging Formatting and Functions

This code block consists of several class methods responsible for the formatting, filtering, and logging of messages in the bittensor library. It provides a standardized approach to logging throughout the system, helping to improve the readability and maintainability of the code.

Log Formatter Methods

  1. log_formatter: This method formats the log messages for display in the terminal. It customizes the log format based on the presence of specific keys in the record's 'extra' field, such as 'rpc' and 'receptor'. It also considers the 'trace_on' flag to determine whether to include trace information or not.

  2. log_save_formatter: Similar to the log_formatter method, this method formats log messages for saving to a file. It also adjusts the formatting based on the presence of specific keys in the record's 'extra' field and the 'trace_on' flag.

Logging Utility Methods

  1. rpc_log: This method logs information about communication between endpoints (axon and dendrite) during the forward or backward pass. It provides essential details such as the call time, public key, unique identifier (uid), inputs, outputs, messages, and synapse.

  2. update_receptor_log: This method logs details about updating connections with a given endpoint. It includes information such as uid, hotkey, coldkey, and IP address.

  3. success, warning, error, and info: These methods are responsible for logging messages with various log levels (success, warning, error, and info). Each method ensures that the logging prefix is left-justified and followed by the log message.

The code block offers a structured and standardized way of logging information in the bittensor library, making it easier for developers to understand the system's behavior and debug issues.

Return Codes

The following return codes from backward and forward calls can be used for diagnosing your miner:

NoReturn = 0; Default value.

Success = 1; Succesfull query.

Timeout = 2; Request timeout.

Backoff = 3; Call triggered a backoff.

Unavailable = 4; Endpoint not available.

NotImplemented = 5; Modality not implemented.

EmptyRequest = 6; Request is empty.

EmptyResponse = 7; Response is empty.

InvalidResponse = 8; Request is invalid.

InvalidRequest = 9; Response is invalid.

RequestShapeException = 10; Request has an invalid shape.

ResponseShapeException = 11; Response has an invalid shape.

RequestSerializationException = 12; Request failed to serialize.

ResponseSerializationException = 13; Response failed to serialize.

RequestDeserializationException = 14; Request failed to deserialize.

ResponseDeserializationException = 15; Response failed to deserialize.

NotServingNucleus = 16; Receiving Neuron is not serving a Nucleus to query.

NucleusTimeout = 17; Processing on the Server side timed out.

NucleusFull = 18; Returned when the processing queue on the Server is full.

RequestIncompatibleVersion = 19; The request handler is incompatible with the request version. Request from Validator to Server.

ResponseIncompatibleVersion = 20; The request handler is incompatible with the request version. Response from Server to Validator.

SenderUnknown = 21; Requester is not known by the receiver.

UnknownException = 22; Unknown exception.

Unauthenticated = 23; Authentication failed.

Response Codes

Occasionally you may recieve errors while mining. Refer here for translating response codes.

0 - no return

1 - success

2 - timeout

3 - backoff

4 - unavailable

5 - not implemented

6 - you sent an empty request

7 - you recieved an empty response

8 - you recieved invalid response

9 - you sent an invalid request

10 - request shape exception

11 - response shape exception

12 - request serialization exception

13 - response serialization exception

14 - request deserialization exception

15 - response deserialization exception

16 - not serving nucleus

17 - nucleus timeout

18 - nucleus full

19 - request incompatible version

20 - response incompatible version

21 - sender unknown

22 - unkown exception

bittensor/bittensor/_metagraph/metagraph_impl.py

Metagraph Class Overview

The Metagraph class is a subclass of torch.nn.Module that maintains chain state. The Metagraph class provides a representation of the Bittensor metagraph. /bittensor/bittensor/_metagraph/__init__.py If I am not mistaken, this .py script initiates the metagraph_impl.py file.

Properties

  • Basic properties: version, n, tau, block, uids, stake, total_stake
  • Rank-related properties: ranks, trust, consensus, validator_trust, incentive, emission, dividends
  • Other properties: active, last_update, validator_permit, weights, bonds, endpoints, addresses, endpoint_objs

Methods

  • Initialization and update methods: init, from_tensor, update
  • Getter methods: getitem, get, uid_to_hotkey, hotkey_to_uid
  • Persistence methods: load, save, load_from_path, save_to_path, load_from_state_dict
  • Syncing method: sync
  • Data export methods: to_dataframe, to_wandb
  • String representation methods: str, repr

Properties

  • tau: Current, per block, token emission rate.
  • block: State block number.
  • uids: UIDs for each neuron.
  • stake: Stake balance for each neuron ordered by uid.
  • last_update: Last emission call for each neuron ordered by uid.
  • weights: Full weight matrix on chain ordered by uid.
  • neurons: Tokenized endpoint information.

Methods

  • init: Initializes a new Metagraph torch chain interface object.
  • info_state_dict_hook: Hook for state_dict to add info to state_dict, e.g., before saving.
  • clear: Erases Metagraph state.

Properties (Derived)

  • S: Stake
  • R: Rank
  • I: Incentive
  • E: Emission
  • C: Consensus
  • T: Trust
  • Tv: Validator trust
  • D: Dividends
  • B: Bonds
  • W: Weights
  • hotkeys: Returns hotkeys for each neuron.
  • coldkeys: Returns coldkeys for each neuron.
  • modalities: Returns the modality for each neuron.

Properties

  • addresses: Returns IP addresses for each endpoint.
  • endpoint_objs: Returns endpoints as objects.

Methods

  • hotkey_to_uid: Fetches the UID according to the hotkey.
  • load: Loads the metagraph object's state_dict from Bittensor root directory.
  • save: Saves the metagraph object's state_dict under Bittensor root directory.
  • load_from_path: Loads the metagraph object with state_dict under the specified path.
  • save_to_path: Saves the metagraph object's state_dict to the specified path.
  • load_from_state_dict: Loads the metagraph object from the passed state_dict.
  • sync: Synchronizes the metagraph with the chain state.
  • to_dataframe: Converts the metagraph data to a pandas DataFrame.
  • to_wandb: Returns metagraph information as a dictionary for Weights & Biases logging.
  • str: Returns a string representation of the Metagraph object.
  • repr: Returns the string representation of the Metagraph object (same as __str__).

IP Address Utility Script - bittensor/bittensor/utils/networking.py

This script provides a set of utility functions to help you work with IP addresses, automatically detect your external IP address, set up port forwarding using the Universal Plug and Play (UPnP) protocol, and format WebSocket URLs. It is designed to simplify common networking tasks for users without extensive knowledge in networking.

Key Functions

  1. IP address conversion: Convert IP addresses between their string and integer representations.

    • int_to_ip(int_val: int) -> str: Converts an integer to an IP address string.
    • ip_to_int(str_val: str) -> int: Converts an IP address string to an integer.
  2. IP version detection: Determine if a given IP address is IPv4 or IPv6.

    • ip_version(str_val: str) -> int: Returns the IP version (4 or 6) of a given IP address string.
  3. Formatted IP string: Create a formatted IP string including the IP type, IP address, and port.

    • ip__str__(ip_type:int, ip_str:str, port:int): Returns a formatted IP string.
  4. External IP address detection: Automatically find your router's external IP address using various methods.

    • get_external_ip() -> str: Tries multiple methods to obtain the external IP address of the router and returns it as a string.
  5. UPnP port mapping: Set up port forwarding on your router using the UPnP protocol.

    • upnpc_create_port_map(port: int): Creates a UPnP port map on the router from the provided external port to the local port.
  6. WebSocket URL formatting: Format WebSocket URLs for proper use in applications.

    • get_formatted_ws_endpoint_url(endpoint_url: str) -> str: Returns a formatted WebSocket endpoint URL.

Custom Exceptions

The script defines two custom exception classes that are raised when specific issues occur:

  1. ExternalIPNotFound: Raised when the script cannot find the external IP address using any of the available methods.
  2. UPNPCException: Raised when there are issues with UPnP port mapping, such as when UPnP is not enabled on the router.

By using this script, users who are not well-versed in networking can easily perform tasks related to IP addresses and networking without diving deep into the technical details.

Synopsis of what's going on with

bittensor/bittensor/_neuron/text/core_validator/__init__.py

Author's note because this file had probably one of the more complex scripts, with many more characters, I did my best to translate between myself and my AI assistant. Some words are mine, and I make edits, but I don't know what's going on down there. Validators are the core of the network, and if you've reached the ability to comprehend how to run a Validator, congratulations.

Proof of Work Solver

This script contains a set of classes and functions to perform a proof of work (PoW) computation for the registration process in a distributed network.

Bittensor Proof of Work Registration with CUDA

This document presents a Python module for creating a Proof of Work (PoW) registration for a given subtensor and wallet in a Bittensor network. The module leverages CUDA (Compute Unified Device Architecture) to speed up the registration process using parallel computing on NVIDIA GPUs.

The module contains:

  • _solve_for_difficulty_fast_cuda(): A function that solves the registration using CUDA. It takes several arguments like subtensor, wallet, netuid, output_in_place, update_interval, TPB, dev_id, n_samples, alpha_, and log_verbose. It calculates the hash rate as an exponentially weighted moving average for robustness.

  • _terminate_workers_and_wait_for_exit(): A function that terminates and waits for all worker processes to exit.

  • create_pow(): A function that creates a proof of work for the given subtensor and wallet. It takes arguments like subtensor, wallet, netuid, output_in_place, cuda, dev_id, tpb, num_processes, update_interval, and log_verbose. It returns the proof of work solution or None if the wallet is already registered or there's a different error.

Classes

  1. CUDAException: A custom exception raised when an error occurs in the CUDA environment.

  2. POWSolution: A data class representing a solution to the registration PoW problem.

    • is_stale(subtensor: 'bittensor.Subtensor') -> bool: Returns True if the PoW is stale (the block it is solved for is within 3 blocks of the current block).
  3. _SolverBase: An abstract base class for a multiprocessing process that solves the registration PoW problem.

  4. _Solver: A subclass of _SolverBase that implements the run method for solving the PoW problem.

Functions

  1. _hex_bytes_to_u8_list(hex_bytes: bytes): Converts a hexadecimal byte string to a list of unsigned 8-bit integers.

  2. _create_seal_hash(block_and_hotkey_hash_bytes: bytes, nonce:int) -> bytes: Creates a seal hash based on the given block and hotkey hash bytes and a nonce.

  3. _seal_meets_difficulty(seal: bytes, difficulty: int, limit: int): Checks if a seal meets the required difficulty.

  4. _SolverBase.create_shared_memory() -> Tuple[multiprocessing.Array, multiprocessing.Value, multiprocessing.Array]: Creates shared memory for the solver processes to use.

  5. _solve_for_nonce_block(nonce_start: int, nonce_end: int, block_and_hotkey_hash_bytes: bytes, block_difficulty: int, limit: int, block_number: int) -> Optional[POWSolution]: Attempts to solve the PoW problem for a range of nonces, returning a solution if successful.

Usage

The script is designed to perform PoW computation in a multiprocessing environment. The _Solver class can be instantiated with the necessary shared memory, queues, and events for parallel processing. The run method of the _Solver class will continuously attempt to solve the PoW problem and communicate with the main process to receive updates on the current block and difficulty.

By using this script, developers can efficiently perform PoW computations for the registration process in a distributed network.

CUDASolver Class

The _CUDASolver class is a subclass of _SolverBase and is used for solving the proof of work (POW) on a CUDA device. It takes the following parameters:

  • dev_id: ID of the CUDA device
  • TPB: Thread-per-block count

Methods

  • __init__(): Initializes the CUDASolver with the given parameters.
  • run(): Executes the solver on a CUDA device.

Functions

  • _solve_for_nonce_block_cuda(): Tries to solve the POW on a CUDA device for a block of nonces.
  • _solve_for_nonce_block(): Tries to solve the POW for a block of nonces.
  • _registration_diff_unpack(): Unpacks the packed two 32-bit integers into one 64-bit integer (little endian).
  • _registration_diff_pack(): Packs the difficulty into two 32-bit integers (little endian).
  • _hash_block_with_hotkey(): Hashes the block with the hotkey using Keccak-256 to get 32 bytes.
  • _update_curr_block(): Updates the current block.

Helper Functions

  • get_cpu_count(): Returns the CPU count.

Classes

  • RegistrationStatistics: Data class to store the statistics for a registration.
  • RegistrationStatisticsLogger: Logs statistics for a registration. Provides methods to start, stop, and update the statistics.

Methods

  • start(): Starts the status logger.
  • stop(): Stops the status logger.
  • get_status_message(): Returns a formatted status message.
  • update(): Updates the registration statistics.

Functions

_solve_for_difficulty_fast()

Solves the proof of work (POW) for registration using multiprocessing.

  • subtensor
  • wallet: Wallet to use for registration.
  • netuid: The netuid of the subnet to register to.
  • output_in_place: If true, prints the status in place. Otherwise, prints the status on a new line.
  • num_processes: Number of processes to use.
  • update_interval: Number of nonces to solve before updating block information.
  • n_samples: The number of samples of the hash_rate to keep for the EWMA.
  • alpha_: The alpha for the EWMA for the hash_rate calculation.
  • log_verbose: If true, prints more verbose logging of the registration metrics.

_get_block_with_retry()

Gets the current block number, difficulty, and block hash from the substrate node with retry logic.

  • subtensor: The subtensor object to use to get the block number, difficulty, and block hash.
  • netuid: The netuid of the network to get the block number, difficulty, and block hash from.

_UsingSpawnStartMethod

Context manager for switching the multiprocessing start method to 'spawn' temporarily.

  • force: If true, force the start method to be set to 'spawn'.

_check_for_newest_block_and_update()

Checks for a new block and updates the current block information if a new block is found.

  • subtensor: The subtensor object to use for getting the current block.
  • netuid: The netuid to use for retrieving the difficulty.
  • old_block_number: The old block number to check against.
  • hotkey_bytes: The bytes of the hotkey's pubkey.
  • curr_diff: The current difficulty as a multiprocessing array.
  • curr_block: Where the current block is stored as a multiprocessing array.
  • curr_block_num: Where the current block number is stored as a multiprocessing value.
  • update_curr_block: A function that updates the current block.
  • check_block: A multiprocessing lock that is used to check for a new block.
  • solvers: A list of solvers to update the current block for.
  • curr_stats: The current registration statistics to update.
  1. _solve_for_difficulty_fast_cuda:

    • This function solves the registration process quickly using CUDA (Compute Unified Device Architecture) which is a parallel computing platform and application programming interface (API) model created by NVIDIA.
    • It takes several parameters including subtensor, wallet, netuid, output_in_place, update_interval, TPB (Threads per block), dev_id (CUDA device ID), n_samples, alpha_ (alpha for EWMA), and log_verbose.
    • The function sets up multiprocessing with shared memory, creates a worker for each CUDA device, starts the solver processes, checks for new blocks, and updates the hash rate and registration statistics.
    • If a solution is found or the wallet is already registered, the function stops the solver processes, terminates the workers, and returns the solution.
  2. _terminate_workers_and_wait_for_exit:

    • This function takes a list of worker processes as input.
    • It terminates each worker process and waits for them to exit using the join() method.
  3. create_pow:

    • This function creates a proof of work for the given subtensor and wallet.
    • It takes several parameters including subtensor, wallet, netuid, output_in_place, cuda, dev_id, tpb (Threads per block), num_processes, update_interval, and log_verbose.
    • If the cuda parameter is True, the function uses the _solve_for_difficulty_fast_cuda function; otherwise, it uses the _solve_for_difficulty_fast function to find a solution.
    • The function returns the proof of work solution or None if the wallet is already registered or there is a different error.
    • It raises a ValueError if the subnet does not exist.

Axons in-depth from the init file found within bittensor/_axon

The Axon module provides a factory class for the bittensor.Axon object, which creates a gRPC server for the Bittensor network, facilitating communication between neurons. The server protocol is defined in bittensor.proto and outlines how forward and backward requests are transported and encoded between validators and servers.

Key Components

  • Axon Factory Class: Creates a bittensor.Axon object from passed arguments.
  • Synapse Functions: Axon supports various synapse functions for different types of requests (e.g., forward_text, backward_text, synapse_last_hidden, synapse_causal_lm, synapse_causal_lm_next, and synapse_seq_2_seq).
  • Timeouts: Axon allows specifying timeouts for synapse functions and forward/backward requests.
  • Thread Pool and Server: The module supports the use of a custom thread pool or gRPC server, and provides default options for both.
  • Blacklist and Priority: Axon supports custom blacklist and priority functions for handling requests.
  • IP and Port Configuration: The module allows for setting internal and external IP addresses and ports.

Example Usage

Additional Components

  • Wallet: The Axon module supports the use of a custom wallet with hotkey and coldkeypub.
  • Compression: Axon allows for setting different gRPC compression algorithms, such as gzip, deflate, or no compression.
  • Synapse Checks: The module provides a default synapse check function and allows using a custom synapse check function.
  • Prometheus Level: Axon allows specifying the prometheus level for monitoring.

Configuration

The Axon module relies on a configuration object, which can be customized to modify various aspects of its behavior. The following options can be set:

  • port: Binding port.
  • ip: Binding IP.
  • external_ip: The external IP of the server to broadcast to the network.
  • external_port: The external port of the server to broadcast to the network.
  • protocol: The protocol of the server to broadcast to the network.
  • max_workers: Specifies the number of active threads servicing requests.
  • maximum_concurrent_rpcs: Maximum allowed concurrently processed RPCs.
  • forward_timeout: Timeout on the forward requests.
  • backward_timeout: Timeout on the backward requests.
  • compression: The gRPC compression algorithm to use.

Customizing Axon

The Axon module is designed to be flexible and customizable. Users can provide their own implementations for various components, such as synapse functions, blacklist functions, priority functions, and check functions. By providing custom implementations, users can tailor Axon's behavior to better suit their needs.

Advanced Usage

For more advanced use cases, users can create a custom gRPC server or thread pool and pass it to the Axon module. This allows for greater control over the server's behavior and resource allocation. Additionally, users can set custom timeouts for synapse functions, forward requests, and backward requests to control the response times of their Axon instances.

Overall, the Axon module provides a powerful and flexible framework for creating gRPC servers on the Bittensor network, allowing for seamless communication between neurons and enabling a wide range of applications.

bittensor/bittensor/_dendrite/dendrite_impl.py

The following is a synposis and in-depth analysis of what this file does.

this is a lot of analysis to piece together please look through it before posting it to official documents

Import Statements

  • Import necessary modules and packages including torch, pandas, random, time, uuid, and others.
  • Import bittensor-related classes such as Endpoint, serializer, and synapse.

Logger Configuration

  • Set up the logger for logging purposes.

Global Prometheus

  • Set up Prometheus client with Summary, Counter, Histogram, and CollectorRegistry.

Dendrite Class

  • The Dendrite class is an implementation of bittensor.dendrite() and operates as a torch autograd-friendly operation.
  • It accepts a list of bittensor.endpoints and a list of torch tensors.
  • Implements __init__(), __str__(), __repr__(), and __del__() methods.
  • The forward() method is a static method that handles the autograd-friendly forward RPC call to a list of neuron endpoints.

Dendrite Class (continued)

Backward Method

  • Implements the backward() method as a static and once_differentiable method.
  • This internal autograd-friendly Backward RPC call sends gradients to a list of neuron endpoints.
  • Takes the following arguments: ctx, unused_code_grads, unused_time_grads, and *output_grads.
  • Returns a tuple with optional tensors.

_forward Method

  • Implements the _forward() method to forward tensor inputs to a list of neuron endpoints.
  • Takes the following arguments: endpoints, synapses, inputs, timeout, and requires_grad.
  • Returns a tuple containing outputs, codes, and times.

Prometheus Counters

  • Sets up various Prometheus counters to track performance metrics.
  • Tracks metrics for success and failure rates, response bytes, response params, and latency.
  • Offers additional debugging information with the DEBUG level enabled.

generate

Generates text using provided endpoints, prompt, and various other parameters that control the text generation process.

  • endpoints: The endpoints to send inputs to.
  • prompt: Tokenized sentences to send on the wire.
  • timeout: Request timeout (optional).
  • Various other parameters related to text generation.

Returns a tuple containing the prompt generations produced by endpoints with corresponding parsed codes and query times.

text

Forwards text inputs to a list of neuron endpoints and returns logit encodings or timeouts.

  • endpoints: The endpoints to send inputs to.
  • synapses: Bittensor synapse objects with arguments.
  • inputs: Tokenized sentences to send on the wire.
  • timeout: Request timeout (optional).
  • requires_grad: If true, the backward pass triggers passing gradients on the wire (optional).

Returns a tuple containing outputs from synapses, return codes per call per synapse, and times per call per synapse.

text_causal_lm

Forward text inputs to a list of neuron endpoints and returns logit encodings or timeout.

  • endpoints: Endpoints to send inputs to. Endpoint can be one of the following types:
    • a single endpoint tensor shape [250]
    • a set of endpoint tensors shape [n, 250]
    • a list of endpoints tensors each of shape [250]
    • a single endpoint object. Inputs will be sent to this endpoint alone.
    • a list of endpoint objects. All inputs will be sent to these endpoints.
  • inputs: Tokenized sentences to send on the wire. Inputs can be one of the following types:
    • a single string: the string will be tokenized using the bittensor tokenizer.
    • a list of strings: the strings will be tokenized using the bittensor tokenizer.
    • a tensor with shape [batch_size, sequence_len], assumed to be the output of bittensor tokenizer.
    • a tensor with shape [n, batch_size, sequence_len], the operation will unbind the tensor and pass inputs to endpoints.
    • a list of tensors of type long each representing a tokenized sentence to be sent to each endpoint.
  • synapse: Synapse axon function call which defaults to bittensor.synapse.TextCausalLM().
  • timeout: Request timeout. Queries that do not respond will be replaced by zeros.
  • requires_grad: If true, the backward pass triggers passing gradients on the wire.

Returns:

  • outputs: List of output logit encodings of inputs produced by each remote endpoints. Non-responses are zeroes of input shape plus output dimension. The first dimension will match the number of endpoints queried.
  • codes: dendrite call return ops.
  • times: times per call.

text_causal_lm_next

Forward text inputs to a list of neuron endpoints and returns logit encodings or timeout.

  • endpoints: Endpoints to send inputs to. Endpoint can be one of the following types:
    • a single endpoint tensor shape [250]
    • a set of endpoint tensors shape [n, 250]
    • a list of endpoints tensors each of shape [250]
    • a single endpoint object. Inputs will be sent to this endpoint alone.
    • a list of endpoint objects. All inputs will be sent to these endpoints.
  • inputs: Tokenized sentences to send on the wire. Inputs can be one of the following types:
    • a single string: the string will be tokenized using the bittensor tokenizer.
    • a list of strings: the strings will be tokenized using the bittensor tokenizer.
    • a tensor with shape [batch_size, sequence_len], assumed to be the output of bittensor tokenizer.
    • a tensor with shape [n, batch_size, sequence_len], the operation will unbind the tensor and pass inputs to endpoints.
    • a list of tensors of type long each representing a tokenized sentence to be sent to each endpoint.
  • synapse: Synapse axon function call which defaults to bittensor.synapse.TextCausalLMNext().
  • timeout: Request timeout. Queries that do not respond will be replaced by zeros.
  • requires_grad: If true, the backward pass triggers passing gradients on the wire.

Returns:

  • outputs: List of output topk phrases encodings of inputs produced by each remote endpoints. Non-responses are zeroes of input shape plus output dimension. The first dimension will match the number of endpoints queried.
  • codes: dendrite call return ops.
  • times: times per call.

text_last_hidden_state

The text_last_hidden_state function is designed to forward text inputs to a list of neuron endpoints and return the last hidden state responses or time out.

Arguments

  • endpoints: The endpoints to send the inputs to. This can be a single endpoint tensor, a set of endpoint tensors, a list of endpoint tensors, a single endpoint object, or a list of endpoint objects.
  • inputs: The tokenized sentences to send on the wire. This can be a single string, a list of strings, a tensor with a specific shape, or a list of tensors of type long.
  • mask: An optional mask used to select which hidden states of the sequence are to be returned by the query. This can be a single int, a list of ints, or None.
  • synapse: An optional synapse axon function call that defaults to bittensor.synapse.TextLastHiddenState.

Returns

  • outputs: List of output last hidden state encodings of inputs produced by remote endpoints. Non-responses are zeroes of input shape plus output dimension. The first dimension will match the number of endpoints queried.
  • codes: Dendrite call return ops as a LongTensor.
  • times: Times per call as a FloatTensor.

format_text_inputs

The format_text_inputs function formats endpoint and inputs args to a common format.

Arguments

  • endpoints: Endpoints to send inputs to. Endpoint can be one of the following types:

    • a single endpoint tensor shape [250]
    • a set of endpoint tensors shape [n, 250]
    • a list of endpoints tensors each of shape [250]
    • a single endpoint object. Inputs will be sent to this endpoint alone.
    • a list of endpoint objects. All inputs will be sent to these endpoints.
  • inputs: Tokenized sentences to send on the wire. Inputs can be one of the following types:

    • a single string: the string will be tokenized using the bittensor tokenizer.
    • a list of strings: the strings will be tokenized using the bittensor tokenizer.
    • a tensor with shape [batch_size, sequence_len], assumed to be the output of bittensor tokenizer.
    • a tensor with shape [n, batch_size, sequence_len], the operation will unbind the tensor and pass inputs to endpoints. If inputs are tensors they will be cast to int64 format before sending on the wire.

Returns

  • formatted_endpoints: A list of endpoint objects. All inputs will be sent to these endpoints.
  • formatted_inputs: A list of tensor of type long each representing a tokenized sentence to be sent to each endpoint.

Prometheus

bittensor/bittensor/_prometheus/__init__.py

Overview of the Prometheus Module in Bittensor

The prometheus module in Bittensor is responsible for managing and serving metrics related to the distributed machine learning system. This module utilizes the Prometheus monitoring system and the Loguru logging library to provide a powerful and flexible logging mechanism for Bittensor. The key aspects of the prometheus module are summarized below:

  1. Prometheus Namespace: The prometheus class serves as a namespace for Prometheus tooling and global state variables, such as the port and logging level.

  2. Logging Levels: The prometheus.level enumeration defines the available logging levels: OFF, INFO, and DEBUG.

  3. Configuration: The module provides methods for managing the configuration of the Prometheus system, such as config(), add_args(), add_defaults(), and check_config().

  4. Serving Metrics: The serve() method is responsible for starting the Prometheus server and exposing metrics on a specified port.

  5. Help and Argument Parsing: The help() method prints help information about the module to the console, and the add_args() method is responsible for adding module-specific arguments to an ArgumentParser.

In summary, the prometheus module in Bittensor provides a robust and user-friendly way to manage and serve system metrics. By leveraging the power of the Prometheus monitoring system and the Loguru logging library, this module allows developers to monitor and debug the distributed machine learning system effectively.

Receptor Class from

bittensor/bittensor/_receptor/receptor_impl.py

The Receptor class is responsible for managing a gRPC connection with a remote Bittensor neuron.

Properties

  • wallet: bittensor wallet with hotkey and coldkeypub.
  • endpoint: neuron endpoint descriptor proto.
  • channel: gRPC TCP channel.
  • stub: bittensor protocol stub created from channel.
  • receptor_uid: unique identifier for the receptor.
  • semaphore: a threading.Semaphore object to limit concurrent processes.
  • state_dict: dictionary of connectivity states.
  • stats: a SimpleNamespace object containing various statistics for the Receptor.

Methods

  • init: Initializes a receptor gRPC connection.
  • str: Returns a string representation of the Receptor object.
  • repr: Returns the string representation of the Receptor object (same as __str__).
  • del: Destructor for the Receptor object.
  • exit: Exit method for the Receptor object.
  • sign: Generates a signature string for the receptor.
  • nonce: Creates a string representation of the time (monotonic_ns).
  • state: Returns the current connectivity state of the receptor.
  • close: Closes the Receptor connection.
  • forward: Triggers the gRPC call to the remote endpoint.
  • backward: Triggers the gRPC backward call to the remote endpoint.
  • async_forward: Asynchronous version of the forward method.

backward

Triggers the gRPC backward call to the remote endpoint, which triggers the synapse's backward calls with arguments. This method returns a list of output gradient tensors, one per synapse, along with their corresponding time and bittensor.proto.ReturnCode.

Arguments

  • synapses: List of Bittensor synapse objects with arguments.
  • inputs: Single torch tensor input corresponding to the linked forward call.
  • grads: List of torch tensor gradients associated with each synapse.
  • timeout: Request max timeout

Returns

  • output: Result tensors (likely zero) from the backward call, each corresponding to a single forward input.
  • codes: List of return codes associated with each passed synapse enum.
  • times: List of times for each call associated with each passed synapse enum.

async_forward

Asynchronous version of the forward method. Triggers the gRPC call to the remote endpoint and returns a list of output tensors, one per synapse, along with their corresponding time and bittensor.proto.ReturnCode.

Arguments

  • synapses: List of Bittensor synapse objects with arguments.
  • inputs: Single torch tensor to be sent to the remote endpoint.
  • timeout: Request max timeout

Returns

  • outputs: List of result tensors from the forward call, each corresponding to a passed synapse enum.
  • codes: List of return codes associated with each passed synapse enum.
  • times: List of times for each call associated with each passed synapse enum.