Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
2ebca49
Append each step into a history object and create a followup question…
Apr 16, 2024
c9af4e7
Refactor random task creation into conversation.py
Apr 16, 2024
18f33f1
Add prototype followup question
Apr 16, 2024
882a345
Initial addition of sentiment
steffencruz Apr 17, 2024
6799b40
Update task registry
steffencruz Apr 17, 2024
4628a6f
Create ordinal reward model
steffencruz Apr 17, 2024
46f7230
Merge pull request #205 from opentensor/pre-staging
bkb2135 Apr 18, 2024
131f382
Fix ordinal scoring
steffencruz Apr 18, 2024
3625819
Remove random_task
steffencruz Apr 19, 2024
a5cde41
Revert forward step to use previous design, and enfore followups to b…
steffencruz Apr 19, 2024
5a4bfed
Log turn number
steffencruz Apr 19, 2024
54dbd70
update system prompt to discourage QG+QA hallucinations
steffencruz Apr 19, 2024
115c29a
Refine followup prompt
steffencruz Apr 23, 2024
1205710
Cleanup comments
steffencruz Apr 23, 2024
b9255c4
Add roles and messages to synapse
steffencruz Apr 24, 2024
44b7c90
Merge branch 'main' into features/multiturn-conversation
p-ferreira Apr 25, 2024
12502a6
fix broken unit test
p-ferreira Apr 25, 2024
14066d6
Add new cleaning pipeline
bkb2135 Apr 25, 2024
dd757ea
sets package version
p-ferreira Apr 25, 2024
bfad7fb
Merge branch 'features/multiturn-conversation' of https://github.com/…
p-ferreira Apr 25, 2024
770e648
Add Union Typing
p-ferreira Apr 25, 2024
3c8b4b3
Remove re.replace
p-ferreira Apr 25, 2024
9db8123
initial translation task push
p-ferreira Apr 26, 2024
5ffb670
fix typing import
p-ferreira Apr 29, 2024
4e18b78
moves context dependency to prevent circular dependency
p-ferreira Apr 29, 2024
bd1927b
reorganizes translation task init
p-ferreira Apr 29, 2024
0a0a0f7
Add templates
bkb2135 Apr 30, 2024
a64fd0a
Change the math query to just the problem
bkb2135 Apr 30, 2024
e295b62
creates transalation pipeline and complements task
p-ferreira Apr 30, 2024
684bc22
fix import on context obj
p-ferreira Apr 30, 2024
e8b3d01
Merge pull request #203 from opentensor/features/sentiment-task
bkb2135 Apr 30, 2024
011d140
Set subtopic to be the sentiment
p-ferreira Apr 30, 2024
0e8e27c
Merge pull request #220 from opentensor/features/sentiment-task
bkb2135 Apr 30, 2024
bbb4983
adds translation to validator flow
p-ferreira Apr 30, 2024
d8e74db
task integration fixes
p-ferreira Apr 30, 2024
4cc15b0
fix cleaner bug
p-ferreira Apr 30, 2024
f9e523c
fix test broken reference + adds translation task to fixtures
p-ferreira Apr 30, 2024
046e40c
Merge pull request #217 from opentensor/features/multiturn-conversation
p-ferreira Apr 30, 2024
ee06191
adds argo translate to requirements
p-ferreira Apr 30, 2024
2a5c4b5
Update Generic
p-ferreira Apr 30, 2024
09494b3
Merge branch 'pre-staging' into features/translation_task
p-ferreira Apr 30, 2024
68748b3
Merge branch 'features/template-challenges' of https://github.com/ope…
p-ferreira Apr 30, 2024
119a356
Remove Typos
p-ferreira Apr 30, 2024
2aaf93a
Merge pull request #219 from opentensor/features/template-challenges
bkb2135 Apr 30, 2024
cfab079
Merge branch 'pre-staging' into features/translation_task
p-ferreira Apr 30, 2024
8f360c9
Merge pull request #221 from opentensor/features/translation_task
p-ferreira Apr 30, 2024
c50957e
Merge branch 'staging' into pre-staging
p-ferreira Apr 30, 2024
03bc12b
adds translation pipeline to validator code
p-ferreira Apr 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion prompting/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# DEALINGS IN THE SOFTWARE.

# Define the version of the template module.
__version__ = "2.1.1"
__version__ = "2.2.0"
version_split = __version__.split(".")
__spec_version__ = (
(10000 * int(version_split[0]))
Expand All @@ -36,6 +36,7 @@
from . import agent
from . import conversation
from . import dendrite
from . import shared
from . import validator

from .llms import hf
Expand Down
14 changes: 10 additions & 4 deletions prompting/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,16 @@ def create_challenge(self) -> str:
cleaner = None
if hasattr(self.task, "cleaning_pipeline"):
cleaner = CleanerPipeline(cleaning_pipeline=self.task.cleaning_pipeline)

self.challenge = super().query(
message="Ask a question related to your goal", cleaner=cleaner
)
if self.task.challenge_type == "inference":
self.challenge = super().query(
message="Ask a question related to your goal", cleaner=cleaner
)
elif self.task.challenge_type == 'paraphrase':
self.challenge = self.task.challenge_template.next(self.task.query)
elif self.task.challenge_type == 'query':
self.challenge = self.task.query
else:
bt.logging.error(f"Task {self.task.name} has challenge type of: {self.task.challenge_type} which is not supported.")
self.challenge = self.task.format_challenge(self.challenge)
self.challenge_time = time.time() - t0

Expand Down
25 changes: 25 additions & 0 deletions prompting/cleaners/all_cleaners.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from abc import ABC, abstractmethod
from typing import Union
import bittensor as bt
import re
from typing import Union


class BaseCleaner(ABC):
Expand Down Expand Up @@ -57,6 +59,7 @@ def capitalize_sentences(self, input_string):
return result_string

def apply(self, generation: str) -> str:
generation = re.sub(r'\n*\w+\s*:','',generation)
roles = [
"User: ",
"System: ",
Expand All @@ -77,3 +80,25 @@ def apply(self, generation: str) -> str:
return self.capitalize_sentences(
input_string=generation
) # LLMs are good at being formal. Do the same if we remove a prefix.

class PrunePostQuestionText(BaseCleaner):
def __init__(self, **kwargs):
pass

def apply(self, generation: str, min_pos: Union[int,float] = 5, max_pos: Union[int,float]= 0.5, max_questions: int = None) -> str:

if min_pos < 1:
min_pos = int(min_pos * len(generation))
if max_pos < 1:
max_pos = int(max_pos * len(generation))

# question mark occurs in first half of the query
if not min_pos <= generation.rfind("?") <= max_pos:
return generation
elif max_questions is not None:
generation = '?'.join(generation.split("?",max_questions)[:-1]) + '?'
else:
# drop everything after the last question mark. Alternatively, we can just extract the first question.
generation = generation.rsplit("?",1) + '?'

return generation
3 changes: 2 additions & 1 deletion prompting/cleaners/cleaner.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import bittensor as bt

from prompting.cleaners.all_cleaners import RemoveQuotes, RemoveRoles, PruneEnding
from prompting.cleaners.all_cleaners import RemoveQuotes, RemoveRoles, PruneEnding, PrunePostQuestionText

SUPPORTED_CLEANERS = {
"remove_quotes": RemoveQuotes,
"remove_roles": RemoveRoles,
"prune_ending": PruneEnding,
"remove_post_question_text": PrunePostQuestionText,
}


Expand Down
9 changes: 8 additions & 1 deletion prompting/conversation.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import random
from transformers import Pipeline
from prompting.tasks import Task, TASKS
from prompting.tasks import Task, TASKS, TranslationPipeline, TranslationTask
from prompting.tools import Selector, DATASETS
from prompting.task_registry import TASK_REGISTRY


def create_task(
llm_pipeline: Pipeline,
translation_pipeline: TranslationPipeline,
task_name: str,
create_reference: bool = True,
selector: Selector = random.choice,
Expand Down Expand Up @@ -42,6 +43,12 @@ def create_task(
raise ValueError(f"Dataset {dataset_name} not found")
else:
dataset = dataset()

if task_name == TranslationTask.name:
return task(
translation_pipeline=translation_pipeline,
context=dataset.next()
)

return task(
llm_pipeline=llm_pipeline,
Expand Down
61 changes: 49 additions & 12 deletions prompting/forward.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,30 @@
# DEALINGS IN
# THE SOFTWARE.

import time
import sys
import time
import random
import asyncio
import traceback
import numpy as np
import bittensor as bt
import traceback
from typing import List, Dict, Awaitable
from prompting.agent import HumanAgent
from prompting.dendrite import DendriteResponseEvent
from prompting.conversation import create_task
from prompting.protocol import StreamPromptingSynapse
from prompting.rewards import RewardResult
from prompting.tasks import QuestionAnsweringTask
from prompting.utils.uids import get_random_uids
from prompting.utils.logging import log_event
from prompting.utils.misc import async_log, serialize_exception_to_string
from dataclasses import dataclass

@async_log
async def generate_reference(agent):
async def generate_reference(agent):
loop = asyncio.get_running_loop()
result = await loop.run_in_executor(None, agent.task.generate_reference, agent.llm_pipeline)
return result
return result

@async_log
async def execute_dendrite_call(dendrite_call):
Expand Down Expand Up @@ -167,7 +169,7 @@ def log_stream_results(stream_results: List[StreamResult]):


async def run_step(
self, agent: HumanAgent, k: int, timeout: float, exclude: list = None
self, agent: HumanAgent, roles: List[str], messages: List[str], k: int, timeout: float, exclude: list = None
):
"""Executes a single step of the agent, which consists of:
- Getting a list of uids to query
Expand All @@ -178,6 +180,8 @@ async def run_step(

Args:
agent (HumanAgent): The agent to run the step for.
roles (List[str]): The roles for the synapse.
messages (List[str]): The messages for the synapse.
k (int): The number of uids to query.
timeout (float): The timeout for the queries.
exclude (list, optional): The list of uids to exclude from the query. Defaults to [].
Expand All @@ -196,7 +200,7 @@ async def run_step(
# Directly call dendrite and process responses in parallel
streams_responses = await self.dendrite(
axons=axons,
synapse=StreamPromptingSynapse(roles=["user"], messages=[agent.challenge]),
synapse=StreamPromptingSynapse(roles=roles, messages=messages),
timeout=timeout,
deserialize=False,
streaming=True,
Expand All @@ -217,8 +221,8 @@ async def run_step(

log_stream_results(stream_results)

all_synapses_results = [stream_result.synapse for stream_result in stream_results]
all_synapses_results = [stream_result.synapse for stream_result in stream_results]

# Encapsulate the responses in a response event (dataclass)
response_event = DendriteResponseEvent(
responses=all_synapses_results, uids=uids, timeout=timeout
Expand All @@ -235,10 +239,12 @@ async def run_step(
)
bt.logging.info(f"Created RewardResult:\n {reward_result}")

best_response = response_event.completions[reward_result.rewards.argmax()]

# The original idea was that the agent is 'satisfied' when it gets a good enough response (e.g. reward critera is met, such as ROUGE>threshold)
agent.update_progress(
top_reward=reward_result.rewards.max(),
top_response=response_event.completions[reward_result.rewards.argmax()],
top_response=best_response,
)

self.update_scores(reward_result.rewards, uids)
Expand All @@ -250,7 +256,9 @@ async def run_step(
]
# Log the step event.
event = {
"best": best_response,
"block": self.block,
"step": self.step,
"step_time": time.time() - start_time,
"stream_results_uids": stream_results_uids,
"stream_results_exceptions": stream_results_exceptions,
Expand All @@ -263,6 +271,10 @@ async def run_step(


async def forward(self):
"""
Encapsulates a full conversation between the validator and miners. Contains one or more rounds of request-response.

"""
bt.logging.info("🚀 Starting forward loop...")
forward_start_time = time.time()

Expand All @@ -278,6 +290,7 @@ async def forward(self):
try:
task = create_task(
llm_pipeline=self.llm_pipeline,
translation_pipeline=self.translation_pipeline,
task_name=task_name,
create_reference=False,
)
Expand All @@ -294,29 +307,53 @@ async def forward(self):
task=task, llm_pipeline=self.llm_pipeline, begin_conversation=True
)

rounds = 0
turn = 0
exclude_uids = []
while not agent.finished:
roles = ['user']
messages = [agent.challenge]
while True:
# Note: The try catch is a safe clause to ensure that the forward loop continues even if an error occurs in run_step.
# To be reconsidered in the next version.
try:
# when run_step is called, the agent updates its progress
event = await run_step(
self,
agent,
roles=roles,
messages=messages,
k=self.config.neuron.sample_size,
timeout=self.config.neuron.timeout,
exclude=exclude_uids,
)

# Adds forward time to event and logs it to wandb
event["forward_time"] = time.time() - forward_start_time
event["turn"] = turn
log_event(self, event)

exclude_uids += event["uids"]
task.complete = True

accepted_answer = event["best"] if random.random() < 0.5 else agent.task.reference
roles.append("assistant")
messages.append(accepted_answer)

# 50% chance of single turn conversation, 25% of two turns, 12.5% chance of 3 turns, 6.25% chance of 4 turns, 3.63% chance of 5...
if random.random()<0.5 or turn>=2:
break

history = '\n'.join([f"{role}: {message}" for role, message in zip(roles, messages)])

# Use PREVIOUS task context
agent.task = QuestionAnsweringTask(self.llm_pipeline, context=task.context, create_reference=False, history=history)

# overwrite the challenge with the followup query, which *should* continue the persona
agent.challenge = agent.task.query

roles.append("user")
messages.append(agent.challenge)
turn += 1

rounds += 1
except BaseException as e:
unexpected_errors = serialize_exception_to_string(e)
bt.logging.error(
Expand Down
1 change: 1 addition & 0 deletions prompting/rewards/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
from .rouge import RougeRewardModel
from .float_diff import FloatDiffModel
from .date import DateRewardModel
from .ordinal import OrdinalRewardModel
from .pipeline import RewardPipeline, REWARD_MODELS
50 changes: 50 additions & 0 deletions prompting/rewards/ordinal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import time
import torch
from typing import List
from prompting.rewards import BaseRewardModel, BatchRewardOutput


class OrdinalRewardModel(BaseRewardModel):
@property
def name(self) -> str:
return "category_distance"

def __init__(self, **kwargs):
super().__init__()
#TODO: Expand to allow for more than 3 classes (Must also adjust dataset/review.py)
self.sentiments = [
"casual",
"basic",
"silly",
"random",
"thoughtful",
"serious",
"rushed",
]
#NOTE: These sentimens are not the same as the sentiments defined in the dataset/review.py file. These are the subtopic


def reward(self, reference: str, completions: List[str]) -> BatchRewardOutput:
"""Compute difference scores given a completion and reference pair."""
rewards = []
timings = []
classes = self.sentiments
for completion in completions:
t0 = time.time()

# Check if exactly one answer can be found in the completion
if sum(option in completion for option in classes) == 1:
reward = abs(classes.index(reference) - classes.index(completion))
else:
reward = 0
timings.append(time.time() - t0)
rewards.append(reward)

output = BatchRewardOutput(
rewards=torch.FloatTensor(rewards),
timings=torch.FloatTensor(timings),
extra_info={
"type": "math",
},
)
return output
2 changes: 2 additions & 0 deletions prompting/rewards/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
RelevanceRewardModel,
FloatDiffModel,
DateRewardModel,
OrdinalRewardModel,
)

REWARD_MODELS = {
Expand All @@ -16,6 +17,7 @@
"diff": DiffRewardModel,
"float_diff": FloatDiffModel,
"date": DateRewardModel,
"ordinal": OrdinalRewardModel,
}


Expand Down
1 change: 1 addition & 0 deletions prompting/shared/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .context import Context
File renamed without changes.
Loading