model proposal first version (#61)

* init code

* first version of model proposal
This commit is contained in:
Xu Yang
2024-07-11 10:50:34 +08:00
committed by GitHub
parent 22e1aa3330
commit b4ba69dacc
14 changed files with 248 additions and 50 deletions
+6 -6
View File
@@ -14,12 +14,12 @@ class PropSetting(BaseSettings):
)
# TODO: model part is not finished yet
qlib_model_scen: str = ""
qlib_model_hypothesis_gen: str = ""
qlib_model_hypothesis2experiment: str = ""
qlib_model_coder: str = ""
qlib_model_runner: str = ""
qlib_model_summarizer: str = ""
qlib_model_scen: str = "rdagent.scenarios.qlib.experiment.model_experiment.QlibModelScenario"
qlib_model_hypothesis_gen: str = "rdagent.scenarios.qlib.model_proposal.QlibModelHypothesisGen"
qlib_model_hypothesis2experiment: str = "rdagent.scenarios.qlib.model_proposal.QlibModelHypothesis2Experiment"
qlib_model_coder: str = "rdagent.scenarios.qlib.model_task_implementation.QlibModelCoSTEER"
qlib_model_runner: str = "rdagent.scenarios.qlib.task_generator.model.QlibModelRunner"
qlib_model_summarizer: str = "rdagent.scenarios.qlib.task_generator.feedback.QlibModelHypothesisExperiment2Feedback"
evolving_n: int = 10
+3 -1
View File
@@ -4,6 +4,8 @@ TODO: Factor Structure RD-Loop
from dotenv import load_dotenv
from rdagent.core.scenario import Scenario
load_dotenv(override=True)
from rdagent.app.qlib_rd_loop.conf import PROP_SETTING
@@ -16,7 +18,7 @@ from rdagent.core.proposal import (
from rdagent.core.task_generator import TaskGenerator
from rdagent.core.utils import import_class
scen = import_class(PROP_SETTING.qlib_factor_scen)()
scen: Scenario = import_class(PROP_SETTING.qlib_factor_scen)()
hypothesis_gen: HypothesisGen = import_class(PROP_SETTING.qlib_factor_hypothesis_gen)(scen)
+5 -3
View File
@@ -9,21 +9,23 @@ from rdagent.app.qlib_rd_loop.conf import PROP_SETTING
from rdagent.core.proposal import (
Hypothesis2Experiment,
HypothesisExperiment2Feedback,
HypothesisGen,
Trace,
)
from rdagent.core.scenario import Scenario
from rdagent.core.task_generator import TaskGenerator
from rdagent.core.utils import import_class
scen = import_class(PROP_SETTING.qlib_model_scen)()
scen: Scenario = import_class(PROP_SETTING.qlib_model_scen)()
hypothesis_gen = import_class(PROP_SETTING.qlib_model_hypothesis_gen)(scen)
hypothesis_gen: HypothesisGen = import_class(PROP_SETTING.qlib_model_hypothesis_gen)(scen)
hypothesis2experiment: Hypothesis2Experiment = import_class(PROP_SETTING.qlib_model_hypothesis2experiment)()
qlib_model_coder: TaskGenerator = import_class(PROP_SETTING.qlib_model_coder)(scen)
qlib_model_runner: TaskGenerator = import_class(PROP_SETTING.qlib_model_runner)(scen)
qlib_model_summarizer: HypothesisExperiment2Feedback = import_class(PROP_SETTING.qlib_model_hypothesis2experiment)(scen)
qlib_model_summarizer: HypothesisExperiment2Feedback = import_class(PROP_SETTING.qlib_model_hypothesis2experiment)()
trace = Trace(scen=scen)
for _ in range(PROP_SETTING.evolving_n):
@@ -15,12 +15,6 @@ from rdagent.utils import get_module_by_module_path
class ModelTask(Task):
# TODO: it should change when the Task changes.
name: str
description: str
formulation: str
variables: Dict[str, str] # map the variable name to the variable description
def __init__(
self, name: str, description: str, formulation: str, variables: Dict[str, str], model_type: Optional[str] = None
) -> None:
@@ -37,16 +37,18 @@ class FactorHypothesisGen(HypothesisGen):
system_prompt = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["factor_hypothesis_gen"]["system_prompt"])
.from_string(prompt_dict["hypothesis_gen"]["system_prompt"])
.render(
targets="factors",
scenario=self.scen.get_scenario_all_desc(),
hypothesis_output_format=context_dict["hypothesis_output_format"],
)
)
user_prompt = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["factor_hypothesis_gen"]["user_prompt"])
.from_string(prompt_dict["hypothesis_gen"]["user_prompt"])
.render(
targets="factors",
hypothesis_and_feedback=context_dict["hypothesis_and_feedback"],
RAG=context_dict["RAG"],
)
@@ -60,8 +62,6 @@ class FactorHypothesisGen(HypothesisGen):
class FactorHypothesis2Experiment(Hypothesis2Experiment[FactorExperiment]):
def __init__(self) -> None:
super().__init__()
@abstractmethod
def prepare_context(self, hypothesis: Hypothesis, trace: Trace) -> Tuple[dict, bool]: ...
@@ -73,19 +73,21 @@ class FactorHypothesis2Experiment(Hypothesis2Experiment[FactorExperiment]):
context, json_flag = self.prepare_context(hypothesis, trace)
system_prompt = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["factor_hypothesis2experiment"]["system_prompt"])
.from_string(prompt_dict["hypothesis2experiment"]["system_prompt"])
.render(
targets="factors",
scenario=trace.scen.get_scenario_all_desc(),
experiment_output_format=context["experiment_output_format"],
)
)
user_prompt = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["factor_hypothesis2experiment"]["user_prompt"])
.from_string(prompt_dict["hypothesis2experiment"]["user_prompt"])
.render(
targets="factors",
target_hypothesis=context["target_hypothesis"],
hypothesis_and_feedback=context["hypothesis_and_feedback"],
factor_list=context["factor_list"],
target_list=context["target_list"],
RAG=context["RAG"],
)
)
@@ -0,0 +1,96 @@
from abc import abstractmethod
from pathlib import Path
from typing import Tuple
from jinja2 import Environment, StrictUndefined
from rdagent.components.coder.model_coder.model import ModelExperiment
from rdagent.core.prompts import Prompts
from rdagent.core.proposal import (
Hypothesis,
Hypothesis2Experiment,
HypothesisGen,
Scenario,
Trace,
)
from rdagent.oai.llm_utils import APIBackend
prompt_dict = Prompts(file_path=Path(__file__).parent / "prompts.yaml")
ModelHypothesis = Hypothesis
class ModelHypothesisGen(HypothesisGen):
# The following methods are scenario related so they should be implemented in the subclass
@abstractmethod
def prepare_context(self, trace: Trace) -> Tuple[dict, bool]: ...
@abstractmethod
def convert_response(self, response: str) -> ModelHypothesis: ...
def gen(self, trace: Trace) -> ModelHypothesis:
context_dict, json_flag = self.prepare_context(trace)
system_prompt = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["hypothesis_gen"]["system_prompt"])
.render(
targets="factors",
scenario=self.scen.get_scenario_all_desc(),
hypothesis_output_format=context_dict["hypothesis_output_format"],
)
)
user_prompt = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["hypothesis_gen"]["user_prompt"])
.render(
targets="factors",
hypothesis_and_feedback=context_dict["hypothesis_and_feedback"],
RAG=context_dict["RAG"],
)
)
resp = APIBackend().build_messages_and_create_chat_completion(user_prompt, system_prompt, json_mode=json_flag)
hypothesis = self.convert_response(resp)
return hypothesis
class ModelHypothesis2Experiment(Hypothesis2Experiment[ModelExperiment]):
def __init__(self) -> None:
super().__init__()
@abstractmethod
def prepare_context(self, hypothesis: Hypothesis, trace: Trace) -> Tuple[dict, bool]: ...
@abstractmethod
def convert_response(self, response: str, trace: Trace) -> ModelExperiment: ...
def convert(self, hypothesis: Hypothesis, trace: Trace) -> ModelExperiment:
context, json_flag = self.prepare_context(hypothesis, trace)
system_prompt = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["hypothesis2experiment"]["system_prompt"])
.render(
targets="factors",
scenario=trace.scen.get_scenario_all_desc(),
experiment_output_format=context["experiment_output_format"],
)
)
user_prompt = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["hypothesis2experiment"]["user_prompt"])
.render(
targets="factors",
target_hypothesis=context["target_hypothesis"],
hypothesis_and_feedback=context["hypothesis_and_feedback"],
target_list=context["target_list"],
RAG=context["RAG"],
)
)
resp = APIBackend().build_messages_and_create_chat_completion(user_prompt, system_prompt, json_mode=json_flag)
return self.convert_response(resp, trace)
+17 -17
View File
@@ -1,41 +1,41 @@
factor_hypothesis_gen:
hypothesis_gen:
system_prompt: |-
The user is trying to generate new hypothesis on the factors in data-driven research and development.
The factors are used in a certain scenario, the scenario is as follows:
The user is trying to generate new hypothesis on the {{targets}} in data-driven research and development.
The {{targets}} are used in a certain scenario, the scenario is as follows:
{{ scenario }}
The user has made several hypothesis on this scenario and did several evaluation on them. The user will provide this information to you.
To help you generate new hypothesis, the user has prepared some additional information for you. You should use this information to help generate new factors.
To help you generate new hypothesis, the user has prepared some additional information for you. You should use this information to help generate new {{targets}}.
Please generate the output following the format below:
{{ hypothesis_output_format }}
user_prompt: |-
The user has made several hypothesis on this scenario and did several evaluation on them.
The former hypothesis and the corresponding feedbacks are as follows:
{{ hypothesis_and_feedback }}
To help you generate new factors, we have prepared the following information for you:
To help you generate new {{targets}}, we have prepared the following information for you:
{{ RAG }}
Please generate the new hypothesis based on the information above.
factor_hypothesis2experiment:
hypothesis2experiment:
system_prompt: |-
The user is trying to generate new factors based on the hypothesis generated in the previous step.
The factors are used in certain scenario, the scenario is as follows:
The user is trying to generate new {{targets}} based on the hypothesis generated in the previous step.
The {{targets}} are used in certain scenario, the scenario is as follows:
{{ scenario }}
The user will use the factors generated to do some experiments. The user will provide this information to you:
1. The target hypothesis you are targeting to generate factors for.
The user will use the {{targets}} generated to do some experiments. The user will provide this information to you:
1. The target hypothesis you are targeting to generate {{targets}} for.
2. The hypothesis generated in the previous steps and their corresponding feedbacks.
3. Former proposed factors on similar hypothesis.
4. Some additional information to help you generate new factors.
3. Former proposed {{targets}} on similar hypothesis.
4. Some additional information to help you generate new {{targets}}.
Please generate the output following the format below:
{{ experiment_output_format }}
user_prompt: |-
The user has made several hypothesis on this scenario and did several evaluation on them.
The target hypothesis you are targeting to generate factors for is as follows:
The target hypothesis you are targeting to generate {{targets}} for is as follows:
{{ target_hypothesis }}
The former hypothesis and the corresponding feedbacks are as follows:
{{ hypothesis_and_feedback }}
The former proposed factors on similar hypothesis are as follows:
{{ factor_list }}
To help you generate new factors, we have prepared the following information for you:
The former proposed {{targets}} on similar hypothesis are as follows:
{{ target_list }}
To help you generate new {{targets}}, we have prepared the following information for you:
{{ RAG }}
Please generate the new factors based on the information above.
Please generate the new {{targets}} based on the information above.
@@ -92,6 +92,8 @@ qlib_model_interface: |-
Don't write any try-except block in your python code. The user will catch the exception message and provide the feedback to you. Also, don't write main function in your python code. The user will call the forward method in the model_cls to get the output tensor.
Please notice that your model should only use current features as input. The user will provide the input tensor to the model's forward function.
qlib_model_output_format: |-
Your output should be a tensor with shape (batch_size, 1).
+3 -4
View File
@@ -5,7 +5,6 @@ from typing import List, Tuple
from jinja2 import Environment, StrictUndefined
from rdagent.components.coder.factor_coder.factor import FactorExperiment, FactorTask
from rdagent.components.coder.factor_coder.utils import get_data_folder_intro
from rdagent.components.proposal.factor_proposal import (
FactorHypothesis,
FactorHypothesis2Experiment,
@@ -23,7 +22,7 @@ class QlibFactorHypothesisGen(FactorHypothesisGen):
def __init__(self, scen: Scenario) -> Tuple[dict, bool]:
super().__init__(scen)
def prepare_context(self, trace: Trace) -> None:
def prepare_context(self, trace: Trace) -> Tuple[dict, bool]:
hypothesis_feedback = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["hypothesis_and_feedback"])
@@ -45,7 +44,7 @@ class QlibFactorHypothesisGen(FactorHypothesisGen):
class QlibFactorHypothesis2Experiment(FactorHypothesis2Experiment):
def prepare_context(self, hypothesis: Hypothesis, trace: Trace) -> Tuple[dict | bool]:
scenario = trace.scen.get_scenario_all_desc()
experiment_output_format = prompt_dict["experiment_output_format"]
experiment_output_format = prompt_dict["factor_experiment_output_format"]
hypothesis_and_feedback = (
Environment(undefined=StrictUndefined)
@@ -64,7 +63,7 @@ class QlibFactorHypothesis2Experiment(FactorHypothesis2Experiment):
"scenario": scenario,
"hypothesis_and_feedback": hypothesis_and_feedback,
"experiment_output_format": experiment_output_format,
"factor_list": factor_list,
"target_list": factor_list,
"RAG": ...,
}, True
+81
View File
@@ -0,0 +1,81 @@
import json
from pathlib import Path
from typing import List, Tuple
from jinja2 import Environment, StrictUndefined
from rdagent.components.coder.model_coder.model import ModelExperiment, ModelTask
from rdagent.components.proposal.model_proposal import (
ModelHypothesis,
ModelHypothesis2Experiment,
ModelHypothesisGen,
)
from rdagent.core.prompts import Prompts
from rdagent.core.proposal import Hypothesis, Scenario, Trace
prompt_dict = Prompts(file_path=Path(__file__).parent / "prompts.yaml")
QlibModelHypothesis = ModelHypothesis
class QlibModelHypothesisGen(ModelHypothesisGen):
def __init__(self, scen: Scenario) -> Tuple[dict, bool]:
super().__init__(scen)
def prepare_context(self, trace: Trace) -> Tuple[dict, bool]:
hypothesis_feedback = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["hypothesis_and_feedback"])
.render(trace=trace)
)
context_dict = {
"hypothesis_and_feedback": hypothesis_feedback,
"RAG": ...,
"hypothesis_output_format": prompt_dict["hypothesis_output_format"],
}
return context_dict, True
def convert_response(self, response: str) -> ModelHypothesis:
response_dict = json.loads(response)
hypothesis = QlibModelHypothesis(hypothesis=response_dict["hypothesis"], reason=response_dict["reason"])
return hypothesis
class QlibModelHypothesis2Experiment(ModelHypothesis2Experiment):
def prepare_context(self, hypothesis: Hypothesis, trace: Trace) -> Tuple[dict, bool]:
scenario = trace.scen.get_scenario_all_desc()
experiment_output_format = prompt_dict["model_experiment_output_format"]
hypothesis_and_feedback = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["hypothesis_and_feedback"])
.render(trace=trace)
)
experiment_list: List[ModelExperiment] = [t[1] for t in trace.hist]
model_list = []
for experiment in experiment_list:
model_list.extend(experiment.sub_tasks)
return {
"target_hypothesis": str(hypothesis),
"scenario": scenario,
"hypothesis_and_feedback": hypothesis_and_feedback,
"experiment_output_format": experiment_output_format,
"target_list": model_list,
"RAG": ...,
}, True
def convert_response(self, response: str, trace: Trace) -> ModelExperiment:
response_dict = json.loads(response)
tasks = []
for model_name in response_dict:
description = response_dict[model_name]["description"]
formulation = response_dict[model_name]["formulation"]
variables = response_dict[model_name]["variables"]
model_type = response_dict[model_name]["model_type"]
tasks.append(ModelTask(model_name, description, formulation, variables, model_type))
exp = ModelExperiment(tasks)
exp.based_experiments = [t[1] for t in trace.hist if t[2]]
return exp
@@ -1,5 +1,3 @@
from rdagent.components.coder.model_coder.one_shot import ModelCodeWriter
from rdagent.components.coder.model_coder.CoSTEER import ModelCoSTEER
class QlibModelCodeWriter(ModelCodeWriter):
...
QlibModelCoSTEER = ModelCoSTEER
+17 -1
View File
@@ -11,7 +11,7 @@ hypothesis_output_format: |-
"reason": "The reason why you generate this hypothesis."
}
experiment_output_format: |-
factor_experiment_output_format: |-
The output should follow JSON format. The schema is as follows:
{
"factor name 1": {
@@ -32,3 +32,19 @@ experiment_output_format: |-
}
# Don't add ellipsis (...) or any filler text that might cause JSON parsing errors here!
}
model_experiment_output_format: |-
So far please only design one model to test the hypothesis!
The output should follow JSON format. The schema is as follows:
{
"model name 1": {
"description": "detailed description of model 1",
"formulation": "latex formulation of model 1",
"variables": {
"variable or function name 1": "description of variable or function 1",
"variable or function name 2": "description of variable or function 2"
}
"model_type": "type of model 1, Tabular or TimesSeries"
}
# Don't add ellipsis (...) or any filler text that might cause JSON parsing errors here!
}
@@ -5,3 +5,6 @@ from rdagent.core.proposal import HypothesisExperiment2Feedback
class QlibFactorHypothesisExperiment2Feedback(HypothesisExperiment2Feedback): ...
class QlibModelHypothesisExperiment2Feedback(HypothesisExperiment2Feedback): ...
@@ -2,7 +2,7 @@ from rdagent.components.coder.model_coder.model import ModelImplementation
from rdagent.core.task_generator import TaskGenerator
class QlibModelImplementation(TaskGenerator[ModelImplementation]):
class QlibModelRunner(TaskGenerator[ModelImplementation]):
"""
Docker run
Everything in a folder
@@ -14,3 +14,6 @@ class QlibModelImplementation(TaskGenerator[ModelImplementation]):
- pt_model_uri: hard-code `model.py:Net` in the config
- let LLM modify model.py
"""
def generate(self, exp: ModelImplementation) -> ModelImplementation:
return exp # TODO IMPLEMENT THIS