Skip to content

Commit 75494f4

Browse files
authored
feat: add naive experiment generator and update proposal configurations (#759)
* feat: Add naive experiment generator and update proposal configurations * lint * lint
1 parent 963f96e commit 75494f4

File tree

11 files changed

+133
-26
lines changed

11 files changed

+133
-26
lines changed

rdagent/app/data_science/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ class DataScienceBasePropSetting(KaggleBasePropSetting):
2424
#### enable specification
2525
spec_enabled: bool = True
2626

27+
### proposal related
2728
proposal_version: str = "v1"
2829
coder_on_whole_pipeline: bool = False
30+
max_trace_hist: int = 3
2931

3032
coder_max_loop: int = 10
3133
runner_max_loop: int = 3

rdagent/components/coder/data_science/pipeline/exp.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33

44
# Because we use isinstance to distinguish between different types of tasks, we need to use sub classes to represent different types of tasks
55
class PipelineTask(CoSTEERTask):
6-
pass
6+
def __init__(self, name: str = "Pipeline", *args, **kwargs) -> None:
7+
super().__init__(name=name, *args, **kwargs)

rdagent/components/coder/data_science/workflow/exp.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@
1010

1111
# Because we use isinstance to distinguish between different types of tasks, we need to use sub classes to represent different types of tasks
1212
class WorkflowTask(CoSTEERTask):
13-
pass
13+
def __init__(self, name: str = "Workflow", *args, **kwargs) -> None:
14+
super().__init__(name=name, *args, **kwargs)

rdagent/core/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def base_iter(settings_cls: type[ExtendedBaseSettings]) -> list[type[ExtendedBas
3939
env_prefix=base_cls.model_config.get("env_prefix"),
4040
env_nested_delimiter=base_cls.model_config.get("env_nested_delimiter"),
4141
)
42-
for base_cls in base_iter(cast(type[ExtendedBaseSettings], settings_cls))
42+
for base_cls in base_iter(cast("type[ExtendedBaseSettings]", settings_cls))
4343
]
4444
return init_settings, env_settings, *parent_env_settings, dotenv_settings, file_secret_settings
4545

rdagent/core/experiment.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from collections.abc import Sequence
1111
from copy import deepcopy
1212
from pathlib import Path
13-
from typing import Any, Generic, Literal, TypeVar
13+
from typing import Any, Generic, TypeVar
1414

1515
from rdagent.core.conf import RD_AGENT_SETTINGS
1616
from rdagent.core.evaluation import Feedback

rdagent/core/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def similarity(text1: str, text2: str) -> int:
6969
text2 = text2 if isinstance(text2, str) else ""
7070

7171
# Maybe we can use other similarity algorithm such as tfidf
72-
return cast(int, fuzz.ratio(text1, text2)) # mypy does not regard it as int
72+
return cast("int", fuzz.ratio(text1, text2)) # mypy does not regard it as int
7373

7474

7575
def import_class(class_path: str) -> Any:
Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from rdagent.app.data_science.conf import DS_RD_SETTING
22
from rdagent.core.proposal import ExpGen
3+
from rdagent.core.utils import import_class
34
from rdagent.scenarios.data_science.experiment.experiment import DSExperiment
45
from rdagent.scenarios.data_science.proposal.exp_gen.base import DSTrace
56
from rdagent.scenarios.data_science.proposal.exp_gen.draft import DSDraftExpGen
@@ -11,32 +12,29 @@
1112

1213

1314
class DSExpGen(ExpGen):
14-
"""Data Science Task Generator."""
15+
"""
16+
Data Science Task Generator.
17+
This is a experiment router generator;
18+
"""
1519

16-
def __init__(self, scen: DataScienceScen, max_trace_hist: int = 3) -> None:
17-
self.max_trace_hist = max_trace_hist # max number of historical trace to know when propose new experiment
20+
def __init__(self, scen: DataScienceScen) -> None:
1821
super().__init__(scen)
1922

2023
def gen(self, trace: DSTrace) -> DSExperiment:
24+
25+
if DS_RD_SETTING.proposal_version not in ["v1", "v2"]:
26+
return import_class(DS_RD_SETTING.proposal_version)(scen=self.scen).gen(trace=trace)
27+
2128
if DS_RD_SETTING.coder_on_whole_pipeline:
22-
return DSProposalV2ExpGen(scen=self.scen).gen(
23-
trace=trace,
24-
max_trace_hist=self.max_trace_hist,
25-
pipeline=True,
26-
)
29+
return DSProposalV2ExpGen(scen=self.scen).gen(trace=trace, pipeline=True)
30+
2731
next_missing_component = trace.next_incomplete_component()
2832
if next_missing_component is not None:
2933
return DSDraftExpGen(scen=self.scen).gen(
3034
component=next_missing_component,
3135
trace=trace,
3236
)
3337
if DS_RD_SETTING.proposal_version == "v1":
34-
return DSProposalV1ExpGen(scen=self.scen).gen(
35-
trace=trace,
36-
max_trace_hist=self.max_trace_hist,
37-
)
38+
return DSProposalV1ExpGen(scen=self.scen).gen(trace=trace)
3839
if DS_RD_SETTING.proposal_version == "v2":
39-
return DSProposalV2ExpGen(scen=self.scen).gen(
40-
trace=trace,
41-
max_trace_hist=self.max_trace_hist,
42-
)
40+
return DSProposalV2ExpGen(scen=self.scen).gen(trace=trace)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""
2+
The most naive way to design experiments
3+
"""
4+
5+
from rdagent.app.data_science.conf import DS_RD_SETTING
6+
from rdagent.components.coder.data_science.pipeline.exp import PipelineTask
7+
from rdagent.core.proposal import ExpGen
8+
from rdagent.scenarios.data_science.experiment.experiment import DSExperiment
9+
from rdagent.scenarios.data_science.proposal.exp_gen.base import DSHypothesis, DSTrace
10+
from rdagent.utils.agent.tpl import T
11+
from rdagent.utils.agent.workflow import build_cls_from_json_with_retry
12+
13+
14+
class NaiveExpGen(ExpGen):
15+
def gen(self, trace: DSTrace) -> DSExperiment:
16+
sota_exp = trace.sota_experiment()
17+
scenario_desc = trace.scen.get_scenario_all_desc()
18+
competition_desc = trace.scen.get_competition_full_desc()
19+
sota_exp_desc = T("scenarios.data_science.share:describe.exp").r(
20+
exp=sota_exp, heading="Best of previous exploration of the scenario"
21+
)
22+
23+
sota_exp_feedback_list = trace.experiment_and_feedback_list_after_init(return_type="sota")
24+
failed_exp_feedback_list = trace.experiment_and_feedback_list_after_init(return_type="failed")[
25+
-DS_RD_SETTING.max_trace_hist :
26+
]
27+
28+
sota_exp_and_feedback_list_desc = T("scenarios.data_science.share:describe.trace").r(
29+
exp_and_feedback_list=sota_exp_feedback_list,
30+
success=True,
31+
)
32+
failed_exp_and_feedback_list_desc = T("scenarios.data_science.share:describe.trace").r(
33+
exp_and_feedback_list=failed_exp_feedback_list,
34+
success=False,
35+
)
36+
37+
sys_prompt = T(".naive:naive_gen.system").r()
38+
39+
user_prompt = T(".naive:naive_gen.user").r(
40+
competition_desc=competition_desc,
41+
sota_exp_desc=sota_exp_desc,
42+
scenario_desc=scenario_desc,
43+
sota_exp_and_feedback_list_desc=sota_exp_and_feedback_list_desc,
44+
failed_exp_and_feedback_list_desc=failed_exp_and_feedback_list_desc,
45+
)
46+
47+
task = build_cls_from_json_with_retry(
48+
cls=PipelineTask,
49+
system_prompt=sys_prompt,
50+
user_prompt=user_prompt,
51+
retry_n=5,
52+
)
53+
54+
exp = DSExperiment(
55+
pending_tasks_list=[[task]],
56+
hypothesis=DSHypothesis(
57+
component="Pipeline",
58+
hypothesis=task.description,
59+
),
60+
)
61+
62+
if sota_exp is not None:
63+
exp.experiment_workspace.inject_code_from_file_dict(sota_exp.experiment_workspace)
64+
return exp
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
naive_gen:
2+
system: |-
3+
You are a Kaggle Grandmaster and expert ML engineer with deep expertise in statistics, machine learning, and competition optimization.
4+
The user is improving a Kaggle competition implementation iteratively through traces where each new trace is modified from the current SOTA in the trace, not necessarily the immediate predecessor.
5+
You will be given a competition scenario, previous SOTA(best) and failed experiments and feedbacks, the current SOTA implementation and feedback, and a list of identified problems.
6+
7+
## Guidelines
8+
Here are guidelines to aid your task design. You don't need to answer all the questions.
9+
1. Problem Impact Analysis
10+
- Assess how the identified problem affects the performance of the current SOTA implementation.
11+
2. Lessons from Previous Experiments
12+
- For persistent problem, analyze why previous experiments failed on this problem.
13+
- Review why previous experiments failed to address the problem. Identify patterns, overlooked factors, or misaligned assumptions.
14+
- Incorporate learnings from both failed and successful past experiments to ground your hypothesis in evidence.
15+
3. Actionable Changes
16+
- If the problem relates to time/memory constraints, suggest smaller model sizes or alternative algorithms with reduced complexity.
17+
- If the problem involves underperforming models, propose removing or replacing models with significantly worse performance.
18+
- If the problem relates to hyperparameter tuning, recommend a specific method or strategy for tuning.
19+
20+
## Final Output Format in JSON Schema:
21+
{% include "scenarios.data_science.proposal.exp_gen.prompts:output_format.pipeline" %}
22+
23+
user: |-
24+
# Scenario Description
25+
{{ scenario_desc }}
26+
27+
# Competition Description
28+
{{ competition_desc }}
29+
30+
# Previous Failed Experiments and Feedbacks:
31+
{{ failed_exp_and_feedback_list_desc }}
32+
33+
# Previous SOTA Experiments and Feedbacks:
34+
{{ sota_exp_and_feedback_list_desc }}
35+
36+
# Current SOTA Implementation
37+
{{ sota_exp_desc }}

rdagent/scenarios/data_science/proposal/exp_gen/proposal.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858

5959

6060
class DSProposalV1ExpGen(ExpGen):
61-
def gen(self, trace: DSTrace, max_trace_hist: int) -> DSExperiment:
61+
def gen(self, trace: DSTrace) -> DSExperiment:
6262
# Guidelines:
6363
# System prompts: Shared condition you are facing
6464
# - scenario description: `scenario_desc`
@@ -84,7 +84,9 @@ def gen(self, trace: DSTrace, max_trace_hist: int) -> DSExperiment:
8484
) # we use file_dict for hitting the cache when replicate the experiment in another machine.
8585

8686
sota_exp_feedback_list = trace.experiment_and_feedback_list_after_init(return_type="sota")
87-
failed_exp_feedback_list = trace.experiment_and_feedback_list_after_init(return_type="failed")[-max_trace_hist:]
87+
failed_exp_feedback_list = trace.experiment_and_feedback_list_after_init(return_type="failed")[
88+
-DS_RD_SETTING.max_trace_hist :
89+
]
8890
all_exp_feedback_list = trace.experiment_and_feedback_list_after_init(return_type="all")
8991
trace_component_to_feedback_df = pd.DataFrame(columns=["component", "hypothesis", "decision"])
9092
for index, (exp, fb) in enumerate(all_exp_feedback_list):
@@ -414,7 +416,7 @@ def task_gen(
414416
exp.pending_tasks_list.append([workflow_task])
415417
return exp
416418

417-
def gen(self, trace: DSTrace, max_trace_hist: int, pipeline: bool = False) -> DSExperiment:
419+
def gen(self, trace: DSTrace, pipeline: bool = False) -> DSExperiment:
418420
component_desc = "\n".join(
419421
[
420422
f"[{key}] {value}"
@@ -431,7 +433,9 @@ def gen(self, trace: DSTrace, max_trace_hist: int, pipeline: bool = False) -> DS
431433
)
432434

433435
sota_exp_feedback_list = trace.experiment_and_feedback_list_after_init(return_type="sota")
434-
failed_exp_feedback_list = trace.experiment_and_feedback_list_after_init(return_type="failed")[-max_trace_hist:]
436+
failed_exp_feedback_list = trace.experiment_and_feedback_list_after_init(return_type="failed")[
437+
-DS_RD_SETTING.max_trace_hist :
438+
]
435439

436440
sota_exp_feedback_list_desc = T("scenarios.data_science.share:describe.trace").r(
437441
exp_and_feedback_list=sota_exp_feedback_list,

0 commit comments

Comments
 (0)