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
@@ -9,6 +9,9 @@ from rdagent.components.coder.factor_coder.CoSTEER.evaluators import (
from rdagent.components.coder.factor_coder.CoSTEER.evolvable_subjects import (
FactorEvolvingItem,
)
from rdagent.components.coder.factor_coder.CoSTEER.evolving_agent import (
FactorRAGEvoAgent,
)
from rdagent.components.coder.factor_coder.CoSTEER.evolving_strategy import (
FactorEvolvingStrategyWithGraph,
)
@@ -18,18 +21,19 @@ from rdagent.components.coder.factor_coder.CoSTEER.knowledge_management import (
FactorKnowledgeBaseV1,
)
from rdagent.components.coder.factor_coder.factor import FactorExperiment
from rdagent.core.developer import Developer
from rdagent.core.evolving_agent import RAGEvoAgent
from rdagent.core.scenario import Scenario
from rdagent.core.task_generator import TaskGenerator
class FactorCoSTEER(TaskGenerator[FactorExperiment]):
class FactorCoSTEER(Developer[FactorExperiment]):
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)
@@ -47,6 +51,7 @@ class FactorCoSTEER(TaskGenerator[FactorExperiment]):
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 = FactorEvolvingStrategyWithGraph(scen=self.scen)
# declare the factor evaluator
self.factor_evaluator = FactorMultiEvaluator(FactorEvaluatorForCoder(scen=self.scen), scen=self.scen)
@@ -72,7 +77,7 @@ class FactorCoSTEER(TaskGenerator[FactorExperiment]):
)
return factor_knowledge_base
def generate(self, exp: FactorExperiment) -> FactorExperiment:
def develop(self, exp: FactorExperiment) -> FactorExperiment:
# init knowledge base
factor_knowledge_base = self.load_or_init_knowledge_base(
former_knowledge_base_path=self.knowledge_base_path,
@@ -84,7 +89,9 @@ class FactorCoSTEER(TaskGenerator[FactorExperiment]):
# init intermediate items
factor_experiment = FactorEvolvingItem(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 = FactorRAGEvoAgent(
max_loop=self.max_loop, evolving_strategy=self.evolving_strategy, rag=self.rag
)
factor_experiment = self.evolve_agent.multistep_evolve(
factor_experiment,
@@ -92,11 +99,11 @@ class FactorCoSTEER(TaskGenerator[FactorExperiment]):
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(factor_knowledge_base, open(self.new_knowledge_base_path, "wb"))
self.knowledge_base = factor_knowledge_base
factor_experiment.based_experiments = exp.based_experiments
return factor_experiment
exp.sub_workspace_list = factor_experiment.sub_workspace_list
return exp
@@ -8,7 +8,6 @@ from typing import List, Tuple
import pandas as pd
from jinja2 import Environment, StrictUndefined
from rdagent.components.coder.factor_coder.config import FACTOR_IMPLEMENT_SETTINGS
from rdagent.components.coder.factor_coder.CoSTEER.evolvable_subjects import (
FactorEvolvingItem,
)
@@ -16,10 +15,10 @@ from rdagent.components.coder.factor_coder.factor import FactorTask
from rdagent.core.conf import RD_AGENT_SETTINGS
from rdagent.core.evaluation import Evaluator
from rdagent.core.evolving_framework import Feedback, 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")
@@ -33,8 +32,8 @@ class FactorEvaluator(Evaluator):
def evaluate(
self,
target_task: Task,
implementation: Implementation,
gt_implementation: Implementation,
implementation: Workspace,
gt_implementation: Workspace,
**kwargs,
) -> Tuple[str, object]:
"""You can get the dataframe by
@@ -53,7 +52,7 @@ class FactorEvaluator(Evaluator):
"""
raise NotImplementedError("Please implement the `evaluator` method")
def _get_df(self, gt_implementation: Implementation, implementation: Implementation):
def _get_df(self, gt_implementation: Workspace, implementation: Workspace):
if gt_implementation is not None:
_, gt_df = gt_implementation.execute()
if isinstance(gt_df, pd.Series):
@@ -78,10 +77,10 @@ class FactorCodeEvaluator(FactorEvaluator):
def evaluate(
self,
target_task: FactorTask,
implementation: Implementation,
implementation: Workspace,
execution_feedback: str,
factor_value_feedback: str = "",
gt_implementation: Implementation = None,
gt_implementation: Workspace = None,
**kwargs,
):
factor_information = target_task.get_task_information()
@@ -130,8 +129,8 @@ class FactorCodeEvaluator(FactorEvaluator):
class FactorSingleColumnEvaluator(FactorEvaluator):
def evaluate(
self,
implementation: Implementation,
gt_implementation: Implementation,
implementation: Workspace,
gt_implementation: Workspace,
) -> Tuple[str, object]:
_, gen_df = self._get_df(gt_implementation, implementation)
@@ -147,8 +146,8 @@ class FactorSingleColumnEvaluator(FactorEvaluator):
class FactorOutputFormatEvaluator(FactorEvaluator):
def evaluate(
self,
implementation: Implementation,
gt_implementation: Implementation,
implementation: Workspace,
gt_implementation: Workspace,
) -> Tuple[str, object]:
gt_df, gen_df = self._get_df(gt_implementation, implementation)
if gen_df is None:
@@ -184,8 +183,8 @@ class FactorOutputFormatEvaluator(FactorEvaluator):
class FactorDatetimeDailyEvaluator(FactorEvaluator):
def evaluate(
self,
implementation: Implementation,
gt_implementation: Implementation,
implementation: Workspace,
gt_implementation: Workspace,
) -> Tuple[str | object]:
_, gen_df = self._get_df(gt_implementation, implementation)
if gen_df is None:
@@ -214,8 +213,8 @@ class FactorDatetimeDailyEvaluator(FactorEvaluator):
class FactorRowCountEvaluator(FactorEvaluator):
def evaluate(
self,
implementation: Implementation,
gt_implementation: Implementation,
implementation: Workspace,
gt_implementation: Workspace,
) -> Tuple[str, object]:
gt_df, gen_df = self._get_df(gt_implementation, implementation)
@@ -231,8 +230,8 @@ class FactorRowCountEvaluator(FactorEvaluator):
class FactorIndexEvaluator(FactorEvaluator):
def evaluate(
self,
implementation: Implementation,
gt_implementation: Implementation,
implementation: Workspace,
gt_implementation: Workspace,
) -> Tuple[str, object]:
gt_df, gen_df = self._get_df(gt_implementation, implementation)
@@ -248,8 +247,8 @@ class FactorIndexEvaluator(FactorEvaluator):
class FactorMissingValuesEvaluator(FactorEvaluator):
def evaluate(
self,
implementation: Implementation,
gt_implementation: Implementation,
implementation: Workspace,
gt_implementation: Workspace,
) -> Tuple[str, object]:
gt_df, gen_df = self._get_df(gt_implementation, implementation)
@@ -265,8 +264,8 @@ class FactorMissingValuesEvaluator(FactorEvaluator):
class FactorEqualValueCountEvaluator(FactorEvaluator):
def evaluate(
self,
implementation: Implementation,
gt_implementation: Implementation,
implementation: Workspace,
gt_implementation: Workspace,
) -> Tuple[str, object]:
gt_df, gen_df = self._get_df(gt_implementation, implementation)
@@ -296,8 +295,8 @@ class FactorCorrelationEvaluator(FactorEvaluator):
def evaluate(
self,
implementation: Implementation,
gt_implementation: Implementation,
implementation: Workspace,
gt_implementation: Workspace,
) -> Tuple[str, object]:
gt_df, gen_df = self._get_df(gt_implementation, implementation)
@@ -327,11 +326,10 @@ class FactorCorrelationEvaluator(FactorEvaluator):
class FactorValueEvaluator(FactorEvaluator):
def evaluate(
self,
implementation: Implementation,
gt_implementation: Implementation,
implementation: Workspace,
gt_implementation: Workspace,
**kwargs,
) -> Tuple:
conclusions = []
@@ -508,8 +506,8 @@ class FactorEvaluatorForCoder(FactorEvaluator):
def evaluate(
self,
target_task: FactorTask,
implementation: Implementation,
gt_implementation: Implementation = None,
implementation: Workspace,
gt_implementation: Workspace = None,
queried_knowledge: QueriedKnowledge = None,
**kwargs,
) -> FactorSingleFeedback:
@@ -603,41 +601,21 @@ class FactorMultiEvaluator(Evaluator):
queried_knowledge: QueriedKnowledge = None,
**kwargs,
) -> FactorMultiFeedback:
multi_implementation_feedback = FactorMultiFeedback()
# 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
# )
# multi_implementation_feedback.append(
# self.single_factor_implementation_evaluator.evaluate(
# target_task=evo.sub_tasks[index],
# implementation=corresponding_implementation,
# gt_implementation=corresponding_gt_implementation,
# queried_knowledge=queried_knowledge,
# )
# )
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(
[
(
self.single_factor_implementation_evaluator.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=FACTOR_IMPLEMENT_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,7 +1,7 @@
from rdagent.components.coder.factor_coder.factor import (
FactorExperiment,
FactorFBWorkspace,
FactorTask,
FileBasedFactorImplementation,
)
from rdagent.core.evolving_framework import EvolvableSubjects
from rdagent.log import rdagent_logger as logger
@@ -15,7 +15,7 @@ class FactorEvolvingItem(FactorExperiment, EvolvableSubjects):
def __init__(
self,
sub_tasks: list[FactorTask],
sub_gt_implementations: list[FileBasedFactorImplementation] = None,
sub_gt_implementations: list[FactorFBWorkspace] = None,
):
FactorExperiment.__init__(self, sub_tasks=sub_tasks)
self.corresponding_selection: list = None
@@ -0,0 +1,19 @@
from rdagent.components.coder.factor_coder.CoSTEER.evaluators import FactorMultiFeedback
from rdagent.components.coder.factor_coder.CoSTEER.evolvable_subjects import (
FactorEvolvingItem,
)
from rdagent.core.evaluation import Feedback
from rdagent.core.evolving_agent import RAGEvoAgent
from rdagent.core.evolving_framework import EvolvableSubjects
class FactorRAGEvoAgent(RAGEvoAgent):
def filter_evolvable_subjects_by_feedback(self, evo: EvolvableSubjects, feedback: Feedback) -> EvolvableSubjects:
assert isinstance(evo, FactorEvolvingItem)
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
@@ -16,14 +16,11 @@ from rdagent.components.coder.factor_coder.CoSTEER.scheduler import (
LLMSelect,
RandomSelect,
)
from rdagent.components.coder.factor_coder.factor import (
FactorTask,
FileBasedFactorImplementation,
)
from rdagent.components.coder.factor_coder.factor import FactorFBWorkspace, FactorTask
from rdagent.components.coder.factor_coder.utils import get_data_folder_intro
from rdagent.core.conf import RD_AGENT_SETTINGS
from rdagent.core.evolving_framework import EvolvingStrategy, QueriedKnowledge
from rdagent.core.experiment import Implementation
from rdagent.core.experiment import Workspace
from rdagent.core.prompts import Prompts
from rdagent.core.utils import multiprocessing_wrapper
from rdagent.oai.llm_utils import APIBackend
@@ -43,7 +40,7 @@ class MultiProcessEvolvingStrategy(EvolvingStrategy):
self,
target_task: FactorTask,
queried_knowledge: QueriedKnowledge = None,
) -> Implementation:
) -> Workspace:
raise NotImplementedError
def evolve(
@@ -53,15 +50,12 @@ class MultiProcessEvolvingStrategy(EvolvingStrategy):
queried_knowledge: FactorQueriedKnowledge | None = None,
**kwargs,
) -> FactorEvolvingItem:
self.num_loop += 1
new_evo = deepcopy(evo)
# 1.找出需要evolve的factor
to_be_finished_task_index = []
for index, target_factor_task in enumerate(new_evo.sub_tasks):
for index, target_factor_task in enumerate(evo.sub_tasks):
target_factor_task_desc = target_factor_task.get_task_information()
if target_factor_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_factor_task_desc
].implementation
elif (
@@ -87,30 +81,27 @@ class MultiProcessEvolvingStrategy(EvolvingStrategy):
to_be_finished_task_index = LLMSelect(
to_be_finished_task_index,
implementation_factors_per_round,
new_evo,
evo,
queried_knowledge.former_traces,
self.scen,
)
result = multiprocessing_wrapper(
[
(self.implement_one_factor, (new_evo.sub_tasks[target_index], queried_knowledge))
(self.implement_one_factor, (evo.sub_tasks[target_index], queried_knowledge))
for target_index in to_be_finished_task_index
],
n=FACTOR_IMPLEMENT_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] = FactorFBWorkspace(target_task=evo.sub_tasks[target_index])
evo.sub_workspace_list[target_index].inject_code(**{"factor.py": result[index]})
# for target_index in to_be_finished_task_index:
# new_evo.sub_implementations[target_index] = self.implement_one_factor(
# 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
class FactorEvolvingStrategy(MultiProcessEvolvingStrategy):
@@ -118,7 +109,7 @@ class FactorEvolvingStrategy(MultiProcessEvolvingStrategy):
self,
target_task: FactorTask,
queried_knowledge: FactorQueriedKnowledgeV1 = None,
) -> Implementation:
) -> str:
factor_information_str = target_task.get_task_information()
if queried_knowledge is not None and factor_information_str in queried_knowledge.success_task_to_knowledge_dict:
@@ -149,7 +140,7 @@ class FactorEvolvingStrategy(MultiProcessEvolvingStrategy):
queried_former_failed_knowledge=queried_former_failed_knowledge_to_render,
)
)
session = APIBackend(use_chat_cache=False).build_chat_session(
session = APIBackend(use_chat_cache=FACTOR_IMPLEMENT_SETTINGS.coder_use_cache).build_chat_session(
session_system_prompt=system_prompt,
)
@@ -185,14 +176,8 @@ class FactorEvolvingStrategy(MultiProcessEvolvingStrategy):
json_mode=True,
),
)["code"]
# ast.parse(code)
factor_implementation = FileBasedFactorImplementation(
target_task,
)
factor_implementation.prepare()
factor_implementation.inject_code(**{"factor.py": code})
return factor_implementation
return code
class FactorEvolvingStrategyWithGraph(MultiProcessEvolvingStrategy):
@@ -205,7 +190,7 @@ class FactorEvolvingStrategyWithGraph(MultiProcessEvolvingStrategy):
self,
target_task: FactorTask,
queried_knowledge,
) -> Implementation:
) -> str:
error_summary = FACTOR_IMPLEMENT_SETTINGS.v2_error_summary
# 1. 提取因子的背景信息
target_factor_task_information = target_task.get_task_information()
@@ -249,7 +234,7 @@ class FactorEvolvingStrategyWithGraph(MultiProcessEvolvingStrategy):
)
)
session = APIBackend(use_chat_cache=False).build_chat_session(
session = APIBackend(use_chat_cache=FACTOR_IMPLEMENT_SETTINGS.coder_use_cache).build_chat_session(
session_system_prompt=system_prompt,
)
@@ -276,7 +261,9 @@ class FactorEvolvingStrategyWithGraph(MultiProcessEvolvingStrategy):
)
.strip("\n")
)
session_summary = APIBackend(use_chat_cache=False).build_chat_session(
session_summary = APIBackend(
use_chat_cache=FACTOR_IMPLEMENT_SETTINGS.coder_use_cache
).build_chat_session(
session_system_prompt=error_summary_system_prompt,
)
for _ in range(10): # max attempt to reduce the length of error_summary_user_prompt
@@ -335,7 +322,4 @@ class FactorEvolvingStrategyWithGraph(MultiProcessEvolvingStrategy):
json_mode=True,
)
code = json.loads(response)["code"]
factor_implementation = FileBasedFactorImplementation(target_task)
factor_implementation.prepare()
factor_implementation.inject_code(**{"factor.py": code})
return factor_implementation
return code
@@ -27,9 +27,9 @@ from rdagent.core.evolving_framework import (
QueriedKnowledge,
RAGStrategy,
)
from rdagent.core.experiment import Implementation
from rdagent.log import rdagent_logger as logger
from rdagent.core.experiment import Workspace
from rdagent.core.prompts import Prompts
from rdagent.log import rdagent_logger as logger
from rdagent.oai.llm_utils import (
APIBackend,
calculate_embedding_distance_between_str_list,
@@ -40,7 +40,7 @@ class FactorKnowledge(Knowledge):
def __init__(
self,
target_task: FactorTask,
implementation: Implementation,
implementation: Workspace,
feedback: FactorSingleFeedback,
) -> None:
"""
@@ -53,7 +53,7 @@ class FactorKnowledge(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:
@@ -115,7 +115,7 @@ class FactorRAGStrategyV1(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
@@ -149,9 +149,9 @@ class FactorRAGStrategyV1(RAGStrategy):
for target_factor_task in evo.sub_tasks:
target_factor_task_information = target_factor_task.get_task_information()
if target_factor_task_information in self.knowledgebase.success_task_info_set:
queried_knowledge.success_task_to_knowledge_dict[target_factor_task_information] = (
self.knowledgebase.implementation_trace[target_factor_task_information][-1]
)
queried_knowledge.success_task_to_knowledge_dict[
target_factor_task_information
] = self.knowledgebase.implementation_trace[target_factor_task_information][-1]
elif (
len(
self.knowledgebase.implementation_trace.setdefault(
@@ -163,12 +163,14 @@ class FactorRAGStrategyV1(RAGStrategy):
):
queried_knowledge.failed_task_info_set.add(target_factor_task_information)
else:
queried_knowledge.working_task_to_former_failed_knowledge_dict[target_factor_task_information] = (
self.knowledgebase.implementation_trace.setdefault(
target_factor_task_information,
[],
)[-v1_query_former_trace_limit:]
)
queried_knowledge.working_task_to_former_failed_knowledge_dict[
target_factor_task_information
] = self.knowledgebase.implementation_trace.setdefault(
target_factor_task_information,
[],
)[
-v1_query_former_trace_limit:
]
knowledge_base_success_task_list = list(
self.knowledgebase.success_task_info_set,
@@ -189,9 +191,9 @@ class FactorRAGStrategyV1(RAGStrategy):
)[-1]
for index in similar_indexes
]
queried_knowledge.working_task_to_similar_successful_knowledge_dict[target_factor_task_information] = (
similar_successful_knowledge
)
queried_knowledge.working_task_to_similar_successful_knowledge_dict[
target_factor_task_information
] = similar_successful_knowledge
return queried_knowledge
@@ -234,7 +236,7 @@ class FactorGraphRAGStrategy(RAGStrategy):
single_feedback = feedback[task_index]
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
@@ -425,9 +427,9 @@ class FactorGraphRAGStrategy(RAGStrategy):
else:
current_index += 1
factor_implementation_queried_graph_knowledge.former_traces[target_factor_task_information] = (
former_trace_knowledge[-v2_query_former_trace_limit:]
)
factor_implementation_queried_graph_knowledge.former_traces[
target_factor_task_information
] = former_trace_knowledge[-v2_query_former_trace_limit:]
else:
factor_implementation_queried_graph_knowledge.former_traces[target_factor_task_information] = []
@@ -9,9 +9,9 @@ from rdagent.components.coder.factor_coder.CoSTEER.evolvable_subjects import (
)
from rdagent.components.coder.factor_coder.utils import get_data_folder_intro
from rdagent.core.conf import RD_AGENT_SETTINGS
from rdagent.log import rdagent_logger as logger
from rdagent.core.prompts import Prompts
from rdagent.core.scenario import Scenario
from rdagent.log import rdagent_logger as logger
from rdagent.oai.llm_utils import APIBackend
scheduler_prompts = Prompts(file_path=Path(__file__).parent.parent / "prompts.yaml")
@@ -7,16 +7,17 @@ SELECT_METHOD = Literal["random", "scheduler"]
class FactorImplementSettings(BaseSettings):
factor_data_folder: str = str(
class Config:
env_prefix = "FACTOR_CODER_" # Use FACTOR_CODER_ as prefix for environment variables
coder_use_cache: bool = False
data_folder: str = str(
(Path().cwd() / "git_ignore_folder" / "factor_implementation_source_data").absolute(),
)
factor_data_folder_debug: str = str(
data_folder_debug: str = str(
(Path().cwd() / "git_ignore_folder" / "factor_implementation_source_data_debug").absolute(),
)
factor_execution_workspace: str = str(
(Path().cwd() / "git_ignore_folder" / "factor_implementation_workspace").absolute(),
)
factor_cache_location: str = str(
cache_location: str = str(
(Path().cwd() / "git_ignore_folder" / "factor_implementation_execution_cache").absolute(),
)
enable_execution_cache: bool = True # whether to enable the execution cache
@@ -35,8 +36,6 @@ class FactorImplementSettings(BaseSettings):
v2_error_summary: bool = False
v2_knowledge_sampler: float = 1.0
evo_multi_proc_n: int = 16 # how many processes to use for evolving (including eval & generation)
file_based_execution_timeout: int = 120 # seconds for each factor implementation execution
select_method: SELECT_METHOD = "random"
@@ -47,5 +46,7 @@ class FactorImplementSettings(BaseSettings):
knowledge_base_path: Union[str, None] = None
new_knowledge_base_path: Union[str, None] = None
python_bin: str = "python"
FACTOR_IMPLEMENT_SETTINGS = FactorImplementSettings()
+10 -18
View File
@@ -15,7 +15,7 @@ from rdagent.core.exception import (
NoOutputException,
RuntimeErrorException,
)
from rdagent.core.experiment import Experiment, FBImplementation, Task
from rdagent.core.experiment import Experiment, FBWorkspace, Task
from rdagent.log import rdagent_logger as logger
from rdagent.oai.llm_utils import md5_hash
@@ -51,7 +51,7 @@ variables: {str(self.variables)}"""
return f"<{self.__class__.__name__}[{self.factor_name}]>"
class FileBasedFactorImplementation(FBImplementation):
class FactorFBWorkspace(FBWorkspace):
"""
This class is used to implement a factor by writing the code to a file.
Input data and output factor value are also written to files.
@@ -90,15 +90,6 @@ class FileBasedFactorImplementation(FBImplementation):
check=False,
)
def execute_desc(self):
raise NotImplementedError
def prepare(self, *args, **kwargs):
self.workspace_path = Path(
FACTOR_IMPLEMENT_SETTINGS.factor_execution_workspace,
) / str(uuid.uuid4())
self.workspace_path.mkdir(exist_ok=True, parents=True)
def execute(self, store_result: bool = False, data_type: str = "Debug") -> Tuple[str, pd.DataFrame]:
"""
execute the implementation and get the factor value by the following steps:
@@ -112,6 +103,7 @@ class FileBasedFactorImplementation(FBImplementation):
parameters:
store_result: if True, store the factor value in the instance variable, this feature is to be used in the gt implementation to avoid multiple execution on the same gt implementation
"""
super().execute()
if self.code_dict is None or "factor.py" not in self.code_dict:
if self.raise_exception:
raise CodeFormatException(self.FB_CODE_NOT_SET)
@@ -122,8 +114,8 @@ class FileBasedFactorImplementation(FBImplementation):
if FACTOR_IMPLEMENT_SETTINGS.enable_execution_cache:
# NOTE: cache the result for the same code and same data type
target_file_name = md5_hash(data_type + self.code_dict["factor.py"])
cache_file_path = Path(FACTOR_IMPLEMENT_SETTINGS.factor_cache_location) / f"{target_file_name}.pkl"
Path(FACTOR_IMPLEMENT_SETTINGS.factor_cache_location).mkdir(exist_ok=True, parents=True)
cache_file_path = Path(FACTOR_IMPLEMENT_SETTINGS.cache_location) / f"{target_file_name}.pkl"
Path(FACTOR_IMPLEMENT_SETTINGS.cache_location).mkdir(exist_ok=True, parents=True)
if cache_file_path.exists() and not self.raise_exception:
cached_res = pickle.load(open(cache_file_path, "rb"))
if store_result and cached_res[1] is not None:
@@ -135,11 +127,11 @@ class FileBasedFactorImplementation(FBImplementation):
source_data_path = (
Path(
FACTOR_IMPLEMENT_SETTINGS.factor_data_folder_debug,
FACTOR_IMPLEMENT_SETTINGS.data_folder_debug,
)
if data_type == "Debug"
else Path(
FACTOR_IMPLEMENT_SETTINGS.factor_data_folder,
FACTOR_IMPLEMENT_SETTINGS.data_folder,
)
)
@@ -151,7 +143,7 @@ class FileBasedFactorImplementation(FBImplementation):
execution_feedback = self.FB_EXECUTION_SUCCEEDED
try:
subprocess.check_output(
f"python {code_path}",
f"{FACTOR_IMPLEMENT_SETTINGS.python_bin} {code_path}",
shell=True,
cwd=self.workspace_path,
stderr=subprocess.STDOUT,
@@ -215,7 +207,7 @@ class FileBasedFactorImplementation(FBImplementation):
for file_path in path.iterdir():
if file_path.suffix == ".py":
code_dict[file_path.name] = file_path.read_text()
return FileBasedFactorImplementation(target_task=task, code_dict=code_dict, **kwargs)
return FactorFBWorkspace(target_task=task, code_dict=code_dict, **kwargs)
class FactorExperiment(Experiment[FactorTask, FileBasedFactorImplementation]): ...
FactorExperiment = Experiment
@@ -22,7 +22,7 @@ def get_data_folder_intro():
It is for preparing prompting message.
"""
content_l = []
for p in Path(FACTOR_IMPLEMENT_SETTINGS.factor_data_folder).iterdir():
for p in Path(FACTOR_IMPLEMENT_SETTINGS.data_folder).iterdir():
if p.name.endswith(".h5"):
df = pd.read_hdf(p)
# get df.head() as string with full width