Several update on the repo (see desc) (#76)

* ignore result csv file

* fix app scripts

* rename taskgenerator to developer and generate to develop

* fix a config bug in coder

* fix a small bug in factor coder evaluators

* remove a single logger in factor coder evaluators

* fix a small bug in model coder main.py

* rename Implementation to Workspace

* move the prepare the inject_code into FBWorkspace to align all the behavior

* fix a small bug in model feedback

* remove debug lines for multi processing and simplify evaluators multi proc

* add a copy function to workspace to freeze the workspace && add config prefix to speed up debugging

* make hypothesisgen a abc class

* use Qlib***Experiment

* fix a small bug

* rename Imp to Ws

* rename sub_implementations to sub_workspace_list

* fix a bug in feedback not presented as content in prompts

* move proposal pys to proposal folder

* reformat the folder

* align factor and model qlib workspace and use template to handle the workspace

* add a filter to evoagent to filter out false evo

* align multi_proc_n into RDAGENT seeting

* handle when runner gets empty experiment

* fix logger merge remaining problems

* fix black and isort automatically
This commit is contained in:
Xu Yang
2024-07-17 15:00:13 +08:00
committed by GitHub
parent eee2b3c56a
commit e0a24fb46f
76 changed files with 804 additions and 702 deletions
@@ -8,6 +8,7 @@ from rdagent.components.coder.model_coder.CoSTEER.evaluators import (
from rdagent.components.coder.model_coder.CoSTEER.evolvable_subjects import (
ModelEvolvingItem,
)
from rdagent.components.coder.model_coder.CoSTEER.evolving_agent import ModelRAGEvoAgent
from rdagent.components.coder.model_coder.CoSTEER.evolving_strategy import (
ModelCoderEvolvingStrategy,
)
@@ -16,17 +17,18 @@ from rdagent.components.coder.model_coder.CoSTEER.knowledge_management import (
ModelRAGStrategy,
)
from rdagent.components.coder.model_coder.model import ModelExperiment
from rdagent.core.developer import Developer
from rdagent.core.evolving_agent import RAGEvoAgent
from rdagent.core.task_generator import TaskGenerator
class ModelCoSTEER(TaskGenerator[ModelExperiment]):
class ModelCoSTEER(Developer[ModelExperiment]):
def __init__(
self,
*args,
with_knowledge: bool = True,
with_feedback: bool = True,
knowledge_self_gen: bool = True,
filter_final_evo: bool = True,
**kwargs,
) -> None:
super().__init__(*args, **kwargs)
@@ -44,6 +46,7 @@ class ModelCoSTEER(TaskGenerator[ModelExperiment]):
self.with_knowledge = with_knowledge
self.with_feedback = with_feedback
self.knowledge_self_gen = knowledge_self_gen
self.filter_final_evo = filter_final_evo
self.evolving_strategy = ModelCoderEvolvingStrategy(scen=self.scen)
self.model_evaluator = ModelCoderMultiEvaluator(scen=self.scen)
@@ -57,7 +60,7 @@ class ModelCoSTEER(TaskGenerator[ModelExperiment]):
return model_knowledge_base
def generate(self, exp: ModelExperiment) -> ModelExperiment:
def develop(self, exp: ModelExperiment) -> ModelExperiment:
# init knowledge base
model_knowledge_base = self.load_or_init_knowledge_base(
former_knowledge_base_path=self.knowledge_base_path,
@@ -69,7 +72,9 @@ class ModelCoSTEER(TaskGenerator[ModelExperiment]):
# init intermediate items
model_experiment = ModelEvolvingItem(sub_tasks=exp.sub_tasks)
self.evolve_agent = RAGEvoAgent(max_loop=self.max_loop, evolving_strategy=self.evolving_strategy, rag=self.rag)
self.evolve_agent = ModelRAGEvoAgent(
max_loop=self.max_loop, evolving_strategy=self.evolving_strategy, rag=self.rag
)
model_experiment = self.evolve_agent.multistep_evolve(
model_experiment,
@@ -77,11 +82,11 @@ class ModelCoSTEER(TaskGenerator[ModelExperiment]):
with_knowledge=self.with_knowledge,
with_feedback=self.with_feedback,
knowledge_self_gen=self.knowledge_self_gen,
filter_final_evo=self.filter_final_evo,
)
# save new knowledge base
if self.new_knowledge_base_path is not None:
pickle.dump(model_knowledge_base, open(self.new_knowledge_base_path, "wb"))
self.knowledge_base = model_knowledge_base
model_experiment.based_experiments = exp.based_experiments
return model_experiment
exp.sub_workspace_list = model_experiment.sub_workspace_list
return exp
@@ -11,14 +11,14 @@ from rdagent.components.coder.model_coder.conf import MODEL_IMPL_SETTINGS
from rdagent.components.coder.model_coder.CoSTEER.evolvable_subjects import (
ModelEvolvingItem,
)
from rdagent.components.coder.model_coder.model import ModelImplementation, ModelTask
from rdagent.components.coder.model_coder.model import ModelFBWorkspace, ModelTask
from rdagent.core.conf import RD_AGENT_SETTINGS
from rdagent.core.evaluation import Evaluator
from rdagent.core.evolving_framework import QueriedKnowledge
from rdagent.core.experiment import Implementation, Task
from rdagent.log import rdagent_logger as logger
from rdagent.core.experiment import Task, Workspace
from rdagent.core.prompts import Prompts
from rdagent.core.utils import multiprocessing_wrapper
from rdagent.log import rdagent_logger as logger
from rdagent.oai.llm_utils import APIBackend
evaluate_prompts = Prompts(file_path=Path(__file__).parent.parent / "prompts.yaml")
@@ -62,15 +62,15 @@ class ModelCodeEvaluator(Evaluator):
def evaluate(
self,
target_task: Task,
implementation: Implementation,
gt_implementation: Implementation,
implementation: Workspace,
gt_implementation: Workspace,
model_execution_feedback: str = "",
model_value_feedback: str = "",
):
assert isinstance(target_task, ModelTask)
assert isinstance(implementation, ModelImplementation)
assert isinstance(implementation, ModelFBWorkspace)
if gt_implementation is not None:
assert isinstance(gt_implementation, ModelImplementation)
assert isinstance(gt_implementation, ModelFBWorkspace)
model_task_information = target_task.get_task_information()
code = implementation.code
@@ -120,16 +120,16 @@ class ModelFinalEvaluator(Evaluator):
def evaluate(
self,
target_task: Task,
implementation: Implementation,
gt_implementation: Implementation,
implementation: Workspace,
gt_implementation: Workspace,
model_execution_feedback: str,
model_value_feedback: str,
model_code_feedback: str,
):
assert isinstance(target_task, ModelTask)
assert isinstance(implementation, ModelImplementation)
assert isinstance(implementation, ModelFBWorkspace)
if gt_implementation is not None:
assert isinstance(gt_implementation, ModelImplementation)
assert isinstance(gt_implementation, ModelFBWorkspace)
system_prompt = (
Environment(undefined=StrictUndefined)
@@ -219,8 +219,8 @@ class ModelCoderEvaluator(Evaluator):
def evaluate(
self,
target_task: Task,
implementation: Implementation,
gt_implementation: Implementation,
implementation: Workspace,
gt_implementation: Workspace,
queried_knowledge: QueriedKnowledge = None,
**kwargs,
) -> ModelCoderFeedback:
@@ -248,7 +248,7 @@ class ModelCoderEvaluator(Evaluator):
input_value = 0.4
param_init_value = 0.6
assert isinstance(implementation, ModelImplementation)
assert isinstance(implementation, ModelFBWorkspace)
model_execution_feedback, gen_tensor = implementation.execute(
batch_size=batch_size,
num_features=num_features,
@@ -257,7 +257,7 @@ class ModelCoderEvaluator(Evaluator):
param_init_value=param_init_value,
)
if gt_implementation is not None:
assert isinstance(gt_implementation, ModelImplementation)
assert isinstance(gt_implementation, ModelFBWorkspace)
_, gt_tensor = gt_implementation.execute(
batch_size=batch_size,
num_features=num_features,
@@ -303,26 +303,21 @@ class ModelCoderMultiEvaluator(Evaluator):
queried_knowledge: QueriedKnowledge = None,
**kwargs,
) -> List[ModelCoderFeedback]:
multi_implementation_feedback = []
calls = []
for index in range(len(evo.sub_tasks)):
corresponding_implementation = evo.sub_implementations[index]
corresponding_gt_implementation = (
evo.sub_gt_implementations[index] if evo.sub_gt_implementations is not None else None
)
calls.append(
multi_implementation_feedback = multiprocessing_wrapper(
[
(
ModelCoderEvaluator(scen=self.scen).evaluate,
(
evo.sub_tasks[index],
corresponding_implementation,
corresponding_gt_implementation,
evo.sub_workspace_list[index],
evo.sub_gt_implementations[index] if evo.sub_gt_implementations is not None else None,
queried_knowledge,
),
),
)
multi_implementation_feedback = multiprocessing_wrapper(calls, n=MODEL_IMPL_SETTINGS.evo_multi_proc_n)
)
for index in range(len(evo.sub_tasks))
],
n=RD_AGENT_SETTINGS.multi_proc_n,
)
final_decision = [
None if single_feedback is None else single_feedback.final_decision
@@ -1,6 +1,6 @@
from rdagent.components.coder.model_coder.model import (
ModelExperiment,
ModelImplementation,
ModelFBWorkspace,
ModelTask,
)
from rdagent.core.evolving_framework import EvolvableSubjects
@@ -15,7 +15,7 @@ class ModelEvolvingItem(ModelExperiment, EvolvableSubjects):
def __init__(
self,
sub_tasks: list[ModelTask],
sub_gt_implementations: list[ModelImplementation] = None,
sub_gt_implementations: list[ModelFBWorkspace] = None,
):
ModelExperiment.__init__(self, sub_tasks=sub_tasks)
if sub_gt_implementations is not None and len(
@@ -0,0 +1,19 @@
from rdagent.components.coder.model_coder.CoSTEER.evaluators import ModelCoderFeedback
from rdagent.components.coder.model_coder.CoSTEER.evolvable_subjects import (
ModelEvolvingItem,
)
from rdagent.core.evaluation import Feedback
from rdagent.core.evolving_agent import RAGEvoAgent
from rdagent.core.evolving_framework import EvolvableSubjects
class ModelRAGEvoAgent(RAGEvoAgent):
def filter_evolvable_subjects_by_feedback(self, evo: EvolvableSubjects, feedback: Feedback) -> EvolvableSubjects:
assert isinstance(evo, ModelEvolvingItem)
assert isinstance(feedback, list)
assert len(evo.sub_workspace_list) == len(feedback)
for index in range(len(evo.sub_workspace_list)):
if not feedback[index].final_decision:
evo.sub_workspace_list[index].clear()
return evo
@@ -11,7 +11,7 @@ from rdagent.components.coder.model_coder.CoSTEER.evolvable_subjects import (
from rdagent.components.coder.model_coder.CoSTEER.knowledge_management import (
ModelQueriedKnowledge,
)
from rdagent.components.coder.model_coder.model import ModelImplementation, ModelTask
from rdagent.components.coder.model_coder.model import ModelFBWorkspace, ModelTask
from rdagent.core.conf import RD_AGENT_SETTINGS
from rdagent.core.evolving_framework import EvolvingStrategy
from rdagent.core.prompts import Prompts
@@ -26,7 +26,7 @@ class ModelCoderEvolvingStrategy(EvolvingStrategy):
self,
target_task: ModelTask,
queried_knowledge: ModelQueriedKnowledge = None,
) -> ModelImplementation:
) -> str:
model_information_str = target_task.get_task_information()
if queried_knowledge is not None and model_information_str in queried_knowledge.success_task_to_knowledge_dict:
@@ -86,19 +86,15 @@ class ModelCoderEvolvingStrategy(EvolvingStrategy):
queried_similar_successful_knowledge_to_render = queried_similar_successful_knowledge_to_render[1:]
code = json.loads(
APIBackend(use_chat_cache=False).build_messages_and_create_chat_completion(
APIBackend(
use_chat_cache=MODEL_IMPL_SETTINGS.coder_use_cache
).build_messages_and_create_chat_completion(
user_prompt=user_prompt,
system_prompt=system_prompt,
json_mode=True,
),
)["code"]
model_implementation = ModelImplementation(
target_task,
)
model_implementation.prepare()
model_implementation.inject_code(**{"model.py": code})
return model_implementation
return code
def evolve(
self,
@@ -107,14 +103,12 @@ class ModelCoderEvolvingStrategy(EvolvingStrategy):
queried_knowledge: ModelQueriedKnowledge | None = None,
**kwargs,
) -> ModelEvolvingItem:
new_evo = deepcopy(evo)
# 1.找出需要evolve的model
to_be_finished_task_index = []
for index, target_model_task in enumerate(new_evo.sub_tasks):
for index, target_model_task in enumerate(evo.sub_tasks):
target_model_task_desc = target_model_task.get_task_information()
if target_model_task_desc in queried_knowledge.success_task_to_knowledge_dict:
new_evo.sub_implementations[index] = queried_knowledge.success_task_to_knowledge_dict[
evo.sub_workspace_list[index] = queried_knowledge.success_task_to_knowledge_dict[
target_model_task_desc
].implementation
elif (
@@ -125,20 +119,17 @@ class ModelCoderEvolvingStrategy(EvolvingStrategy):
result = multiprocessing_wrapper(
[
(self.implement_one_model, (new_evo.sub_tasks[target_index], queried_knowledge))
(self.implement_one_model, (evo.sub_tasks[target_index], queried_knowledge))
for target_index in to_be_finished_task_index
],
n=MODEL_IMPL_SETTINGS.evo_multi_proc_n,
n=RD_AGENT_SETTINGS.multi_proc_n,
)
for index, target_index in enumerate(to_be_finished_task_index):
new_evo.sub_implementations[target_index] = result[index]
if evo.sub_workspace_list[target_index] is None:
evo.sub_workspace_list[target_index] = ModelFBWorkspace(target_task=evo.sub_tasks[target_index])
evo.sub_workspace_list[target_index].inject_code(**{"model.py": result[index]})
# for target_index in to_be_finished_task_index:
# new_evo.sub_implementations[target_index] = self.implement_one_model(
# new_evo.sub_tasks[target_index], queried_knowledge
# )
evo.corresponding_selection = to_be_finished_task_index
new_evo.corresponding_selection = to_be_finished_task_index
return new_evo
return evo
@@ -9,7 +9,7 @@ from rdagent.core.evolving_framework import (
QueriedKnowledge,
RAGStrategy,
)
from rdagent.core.experiment import Implementation
from rdagent.core.experiment import Workspace
from rdagent.oai.llm_utils import calculate_embedding_distance_between_str_list
@@ -17,7 +17,7 @@ class ModelKnowledge(Knowledge):
def __init__(
self,
target_task: ModelTask,
implementation: Implementation,
implementation: Workspace,
feedback: ModelCoderFeedback,
) -> None:
"""
@@ -30,7 +30,7 @@ class ModelKnowledge(Knowledge):
None
"""
self.target_task = target_task
self.implementation = implementation
self.implementation = implementation.copy()
self.feedback = feedback
def get_implementation_and_feedback_str(self) -> str:
@@ -87,7 +87,7 @@ class ModelRAGStrategy(RAGStrategy):
for task_index in range(len(implementations.sub_tasks)):
target_task = implementations.sub_tasks[task_index]
target_task_information = target_task.get_task_information()
implementation = implementations.sub_implementations[task_index]
implementation = implementations.sub_workspace_list[task_index]
single_feedback = feedback[task_index]
if single_feedback is None:
continue
@@ -121,9 +121,9 @@ class ModelRAGStrategy(RAGStrategy):
for target_model_task in evo.sub_tasks:
target_model_task_information = target_model_task.get_task_information()
if target_model_task_information in self.knowledgebase.success_task_info_set:
queried_knowledge.success_task_to_knowledge_dict[target_model_task_information] = (
self.knowledgebase.implementation_trace[target_model_task_information][-1]
)
queried_knowledge.success_task_to_knowledge_dict[
target_model_task_information
] = self.knowledgebase.implementation_trace[target_model_task_information][-1]
elif (
len(
self.knowledgebase.implementation_trace.setdefault(
@@ -135,12 +135,14 @@ class ModelRAGStrategy(RAGStrategy):
):
queried_knowledge.failed_task_info_set.add(target_model_task_information)
else:
queried_knowledge.working_task_to_former_failed_knowledge_dict[target_model_task_information] = (
self.knowledgebase.implementation_trace.setdefault(
target_model_task_information,
[],
)[-query_former_trace_limit:]
)
queried_knowledge.working_task_to_former_failed_knowledge_dict[
target_model_task_information
] = self.knowledgebase.implementation_trace.setdefault(
target_model_task_information,
[],
)[
-query_former_trace_limit:
]
knowledge_base_success_task_list = list(
self.knowledgebase.success_task_info_set,
@@ -161,7 +163,7 @@ class ModelRAGStrategy(RAGStrategy):
)[-1]
for index in similar_indexes
]
queried_knowledge.working_task_to_similar_successful_knowledge_dict[target_model_task_information] = (
similar_successful_knowledge
)
queried_knowledge.working_task_to_similar_successful_knowledge_dict[
target_model_task_information
] = similar_successful_knowledge
return queried_knowledge
@@ -1,7 +1,7 @@
# TODO: inherent from the benchmark base class
import torch
from rdagent.components.coder.model_coder.model import ModelImplementation
from rdagent.components.coder.model_coder.model import ModelFBWorkspace
def get_data_conf(init_val):
@@ -32,7 +32,7 @@ class ModelImpValEval:
For each hidden output, we can calculate a correlation. The average correlation will be the metrics.
"""
def evaluate(self, gt: ModelImplementation, gen: ModelImplementation):
def evaluate(self, gt: ModelFBWorkspace, gen: ModelFBWorkspace):
round_n = 10
eval_pairs: list[tuple] = []
+4 -7
View File
@@ -6,12 +6,11 @@ from pydantic_settings import BaseSettings
class ModelImplSettings(BaseSettings):
class Config:
env_prefix = "MODEL_IMPL_" # Use MODEL_IMPL_ as prefix for environment variables
env_prefix = "MODEL_CODER_" # Use MODEL_CODER_ as prefix for environment variables
model_execution_workspace: str = str(
(Path().cwd() / "git_ignore_folder" / "model_implementation_workspace").absolute(),
)
model_cache_location: str = str(
coder_use_cache: bool = False
cache_location: str = str(
(Path().cwd() / "git_ignore_folder" / "model_implementation_execution_cache").absolute(),
)
@@ -24,8 +23,6 @@ class ModelImplSettings(BaseSettings):
query_similar_success_limit: int = 5
fail_task_trial_limit: int = 20
evo_multi_proc_n: int = 1
enable_execution_cache: bool = True # whether to enable the execution cache
+5 -3
View File
@@ -10,6 +10,10 @@ import os
import torch
from dotenv import load_dotenv
from rdagent.components.coder.model_coder.CoSTEER.evaluators import (
shape_evaluator,
value_evaluator,
)
from rdagent.oai.llm_utils import APIBackend
assert load_dotenv()
@@ -68,8 +72,6 @@ for test_mode in ["zeros", "ones", "randn"]:
os.system("rm node_features.pt")
# load the output and print the shape
from evaluator import shape_evaluator, value_evaluator
try:
llm_output = torch.load("llm_output.pt")
except:
@@ -80,7 +82,7 @@ for test_mode in ["zeros", "ones", "randn"]:
average_value_eval.append(value_evaluator(llm_output, gt_output)[1])
print("Shape evaluation: ", average_shape_eval[-1])
print("Value evaluation:super().generate(task_l) ", average_value_eval[-1])
print("Value evaluation:super().develop(task_l) ", average_value_eval[-1])
os.system("rm llm_output.pt")
os.system("rm gt_output.pt")
+6 -17
View File
@@ -9,7 +9,7 @@ import torch
from rdagent.components.coder.model_coder.conf import MODEL_IMPL_SETTINGS
from rdagent.core.exception import CodeFormatException
from rdagent.core.experiment import Experiment, FBImplementation, Task
from rdagent.core.experiment import Experiment, FBWorkspace, Task
from rdagent.oai.llm_utils import md5_hash
from rdagent.utils import get_module_by_module_path
@@ -40,7 +40,7 @@ model_type: {self.model_type}
return f"<{self.__class__.__name__} {self.name}>"
class ModelImplementation(FBImplementation):
class ModelFBWorkspace(FBWorkspace):
"""
It is a Pytorch model implementation task;
All the things are placed in a folder.
@@ -60,18 +60,6 @@ class ModelImplementation(FBImplementation):
"""
def __init__(self, target_task: Task) -> None:
super().__init__(target_task)
def prepare(self) -> None:
"""
Prepare for the workspace;
"""
unique_id = uuid.uuid4()
self.workspace_path = Path(MODEL_IMPL_SETTINGS.model_execution_workspace) / f"M{unique_id}"
# start with `M` so that it can be imported via python
self.workspace_path.mkdir(parents=True, exist_ok=True)
def execute(
self,
batch_size: int = 8,
@@ -80,14 +68,15 @@ class ModelImplementation(FBImplementation):
input_value: float = 1.0,
param_init_value: float = 1.0,
):
super().execute()
try:
if MODEL_IMPL_SETTINGS.enable_execution_cache:
# NOTE: cache the result for the same code
target_file_name = md5_hash(
f"{batch_size}_{num_features}_{num_timesteps}_{input_value}_{param_init_value}_{self.code_dict['model.py']}"
)
cache_file_path = Path(MODEL_IMPL_SETTINGS.model_cache_location) / f"{target_file_name}.pkl"
Path(MODEL_IMPL_SETTINGS.model_cache_location).mkdir(exist_ok=True, parents=True)
cache_file_path = Path(MODEL_IMPL_SETTINGS.cache_location) / f"{target_file_name}.pkl"
Path(MODEL_IMPL_SETTINGS.cache_location).mkdir(exist_ok=True, parents=True)
if cache_file_path.exists():
return pickle.load(open(cache_file_path, "rb"))
mod = get_module_by_module_path(str(self.workspace_path / "model.py"))
@@ -115,4 +104,4 @@ class ModelImplementation(FBImplementation):
return f"Execution error: {e}", None
class ModelExperiment(Experiment[ModelTask, ModelImplementation]): ...
ModelExperiment = Experiment
@@ -3,22 +3,19 @@ from pathlib import Path
from jinja2 import Environment, StrictUndefined
from rdagent.components.coder.model_coder.model import (
ModelExperiment,
ModelImplementation,
)
from rdagent.components.coder.model_coder.model import ModelExperiment, ModelFBWorkspace
from rdagent.core.developer import Developer
from rdagent.core.prompts import Prompts
from rdagent.core.task_generator import TaskGenerator
from rdagent.oai.llm_utils import APIBackend
DIRNAME = Path(__file__).absolute().resolve().parent
class ModelCodeWriter(TaskGenerator[ModelExperiment]):
def generate(self, exp: ModelExperiment) -> ModelExperiment:
class ModelCodeWriter(Developer[ModelExperiment]):
def develop(self, exp: ModelExperiment) -> ModelExperiment:
mti_l = []
for t in exp.sub_tasks:
mti = ModelImplementation(t)
mti = ModelFBWorkspace(t)
mti.prepare()
pr = Prompts(file_path=DIRNAME / "prompt.yaml")
@@ -40,5 +37,5 @@ class ModelCodeWriter(TaskGenerator[ModelExperiment]):
code = match.group(1)
mti.inject_code(**{"model.py": code})
mti_l.append(mti)
exp.sub_implementations = mti_l
exp.sub_workspace_list = mti_l
return exp
@@ -9,12 +9,14 @@ from rdagent.components.document_reader.document_reader import (
load_and_process_pdfs_by_langchain,
)
from rdagent.components.loader.task_loader import ModelTaskLoader
from rdagent.log import rdagent_logger as logger
from rdagent.core.prompts import Prompts
from rdagent.log import rdagent_logger as logger
from rdagent.oai.llm_utils import APIBackend
from rdagent.scenarios.qlib.experiment.model_experiment import QlibModelExperiment
document_process_prompts = Prompts(file_path=Path(__file__).parent / "prompts.yaml")
def extract_model_from_doc(doc_content: str) -> dict:
"""
Extract model information from document content.
@@ -107,7 +109,7 @@ class ModelExperimentLoaderFromDict(ModelTaskLoader):
key=model_name,
)
task_l.append(task)
return ModelExperiment(sub_tasks=task_l)
return QlibModelExperiment(sub_tasks=task_l)
class ModelExperimentLoaderFromPDFfiles(ModelTaskLoader):