2025-01-23 16:12:22 +08:00
|
|
|
import json
|
|
|
|
|
import re
|
|
|
|
|
from collections import defaultdict
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
import fire
|
|
|
|
|
import pandas as pd
|
|
|
|
|
|
|
|
|
|
from rdagent.app.data_science.conf import DS_RD_SETTING
|
2025-02-13 14:50:56 +08:00
|
|
|
from rdagent.core.experiment import FBWorkspace
|
2025-02-07 11:00:18 +08:00
|
|
|
from rdagent.core.proposal import ExperimentFeedback
|
2025-01-23 16:12:22 +08:00
|
|
|
from rdagent.log.storage import FileStorage
|
2025-01-24 00:03:41 +08:00
|
|
|
from rdagent.scenarios.data_science.experiment.experiment import DSExperiment
|
2025-01-23 16:12:22 +08:00
|
|
|
from rdagent.utils.env import DockerEnv, MLEBDockerConf
|
|
|
|
|
|
|
|
|
|
mle_de_conf = MLEBDockerConf()
|
|
|
|
|
mle_de_conf.extra_volumes = {
|
|
|
|
|
f"{DS_RD_SETTING.local_data_path}/zip_files": "/mle/data",
|
|
|
|
|
}
|
|
|
|
|
de = DockerEnv(conf=mle_de_conf)
|
|
|
|
|
de.prepare()
|
|
|
|
|
|
|
|
|
|
|
2025-02-05 16:31:30 +08:00
|
|
|
def extract_mle_json(log_content: str) -> dict | None:
|
2025-01-23 16:12:22 +08:00
|
|
|
match = re.search(r"\{.*\}", log_content, re.DOTALL)
|
|
|
|
|
if match:
|
|
|
|
|
return json.loads(match.group(0))
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def save_grade_info(log_trace_path: Path):
|
|
|
|
|
for msg in FileStorage(log_trace_path).iter_msg():
|
|
|
|
|
if "competition" in msg.tag:
|
|
|
|
|
competition = msg.content
|
|
|
|
|
|
|
|
|
|
if "running" in msg.tag:
|
2025-01-24 00:03:41 +08:00
|
|
|
if isinstance(msg.content, DSExperiment):
|
|
|
|
|
msg.content.experiment_workspace.execute(
|
|
|
|
|
env=de,
|
2025-01-24 16:02:21 +08:00
|
|
|
entry=f"mlebench grade-sample submission.csv {competition} --data-dir /mle/data > mle_score.txt 2>&1",
|
2025-01-24 00:03:41 +08:00
|
|
|
)
|
|
|
|
|
msg.content.experiment_workspace.execute(env=de, entry="chmod 777 mle_score.txt")
|
2025-01-23 16:12:22 +08:00
|
|
|
|
|
|
|
|
|
2025-02-06 09:56:34 +08:00
|
|
|
def is_valid_session(p: Path) -> bool:
|
|
|
|
|
return p.is_dir() and p.joinpath("__session__").exists()
|
|
|
|
|
|
|
|
|
|
|
2025-01-23 16:12:22 +08:00
|
|
|
def save_all_grade_info(log_folder):
|
|
|
|
|
for log_trace_path in log_folder.iterdir():
|
2025-02-06 09:56:34 +08:00
|
|
|
if is_valid_session(log_trace_path):
|
2025-01-24 00:03:41 +08:00
|
|
|
save_grade_info(log_trace_path)
|
2025-01-23 16:12:22 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def summarize_folder(log_folder: Path):
|
2025-01-26 11:58:12 +08:00
|
|
|
log_folder = Path(log_folder)
|
2025-01-23 16:12:22 +08:00
|
|
|
stat = defaultdict(dict)
|
|
|
|
|
for log_trace_path in log_folder.iterdir(): # One log trace
|
2025-02-06 09:56:34 +08:00
|
|
|
if not is_valid_session(log_trace_path):
|
2025-01-23 16:12:22 +08:00
|
|
|
continue
|
|
|
|
|
loop_num = 0
|
|
|
|
|
made_submission_num = 0
|
2025-02-05 16:31:30 +08:00
|
|
|
valid_submission_num = 0
|
|
|
|
|
above_median_num = 0
|
|
|
|
|
get_medal_num = 0
|
|
|
|
|
bronze_num = 0
|
|
|
|
|
silver_num = 0
|
|
|
|
|
gold_num = 0
|
2025-01-23 16:12:22 +08:00
|
|
|
test_scores = {}
|
|
|
|
|
valid_scores = {}
|
2025-02-12 18:57:08 +08:00
|
|
|
bronze_threshold = 0.0
|
|
|
|
|
silver_threshold = 0.0
|
|
|
|
|
gold_threshold = 0.0
|
|
|
|
|
median_threshold = 0.0
|
2025-01-23 16:12:22 +08:00
|
|
|
success_loop_num = 0
|
|
|
|
|
|
2025-02-11 20:48:30 +08:00
|
|
|
sota_exp_stat = ""
|
2025-02-12 18:57:08 +08:00
|
|
|
sota_exp_score = None
|
2025-02-11 20:48:30 +08:00
|
|
|
grade_output = None
|
2025-01-23 16:12:22 +08:00
|
|
|
for msg in FileStorage(log_trace_path).iter_msg(): # messages in log trace
|
2025-01-26 11:58:12 +08:00
|
|
|
if msg.tag and "llm" not in msg.tag and "session" not in msg.tag:
|
|
|
|
|
if "competition" in msg.tag:
|
|
|
|
|
stat[log_trace_path.name]["competition"] = msg.content
|
|
|
|
|
|
2025-02-13 14:50:56 +08:00
|
|
|
# get threshold scores
|
|
|
|
|
workflowexp = FBWorkspace()
|
|
|
|
|
stdout = workflowexp.execute(
|
|
|
|
|
env=de,
|
|
|
|
|
entry=f"mlebench grade-sample None {stat[log_trace_path.name]['competition']} --data-dir /mle/data",
|
|
|
|
|
)
|
|
|
|
|
grade_output = extract_mle_json(stdout)
|
|
|
|
|
if grade_output:
|
|
|
|
|
bronze_threshold = grade_output["bronze_threshold"]
|
|
|
|
|
silver_threshold = grade_output["silver_threshold"]
|
|
|
|
|
gold_threshold = grade_output["gold_threshold"]
|
|
|
|
|
median_threshold = grade_output["median_threshold"]
|
|
|
|
|
|
2025-01-26 11:58:12 +08:00
|
|
|
if "direct_exp_gen" in msg.tag and isinstance(msg.content, DSExperiment):
|
|
|
|
|
loop_num += 1
|
|
|
|
|
|
|
|
|
|
if "running" in msg.tag:
|
|
|
|
|
if isinstance(msg.content, DSExperiment):
|
|
|
|
|
submission_path = msg.content.experiment_workspace.workspace_path / "submission.csv"
|
|
|
|
|
if submission_path.exists():
|
|
|
|
|
made_submission_num += 1
|
|
|
|
|
scores_path = msg.content.experiment_workspace.workspace_path / "scores.csv"
|
|
|
|
|
valid_scores[loop_num - 1] = pd.read_csv(scores_path, index_col=0)
|
|
|
|
|
grade_output_path = msg.content.experiment_workspace.workspace_path / "mle_score.txt"
|
|
|
|
|
if not grade_output_path.exists():
|
|
|
|
|
raise FileNotFoundError(
|
|
|
|
|
f"mle_score.txt in {grade_output_path} not found, genarate it first!"
|
2025-01-24 00:03:41 +08:00
|
|
|
)
|
2025-01-26 11:58:12 +08:00
|
|
|
grade_output = extract_mle_json(grade_output_path.read_text())
|
2025-02-05 16:31:30 +08:00
|
|
|
if grade_output:
|
|
|
|
|
if grade_output["score"] is not None:
|
|
|
|
|
test_scores[loop_num - 1] = grade_output["score"]
|
|
|
|
|
if grade_output["valid_submission"]:
|
|
|
|
|
valid_submission_num += 1
|
|
|
|
|
if grade_output["above_median"]:
|
|
|
|
|
above_median_num += 1
|
2025-01-26 11:58:12 +08:00
|
|
|
if grade_output["any_medal"]:
|
2025-02-05 16:31:30 +08:00
|
|
|
get_medal_num += 1
|
|
|
|
|
if grade_output["bronze_medal"]:
|
|
|
|
|
bronze_num += 1
|
|
|
|
|
if grade_output["silver_medal"]:
|
|
|
|
|
silver_num += 1
|
|
|
|
|
if grade_output["gold_medal"]:
|
|
|
|
|
gold_num += 1
|
2025-01-26 11:58:12 +08:00
|
|
|
|
|
|
|
|
if "feedback" in msg.tag and "evolving" not in msg.tag:
|
2025-02-07 11:00:18 +08:00
|
|
|
if isinstance(msg.content, ExperimentFeedback) and bool(msg.content):
|
2025-01-26 11:58:12 +08:00
|
|
|
success_loop_num += 1
|
2025-01-23 16:12:22 +08:00
|
|
|
|
2025-02-11 20:48:30 +08:00
|
|
|
if grade_output: # sota exp's grade output
|
|
|
|
|
if grade_output["gold_medal"]:
|
|
|
|
|
sota_exp_stat = "gold"
|
|
|
|
|
elif grade_output["silver_medal"]:
|
|
|
|
|
sota_exp_stat = "silver"
|
|
|
|
|
elif grade_output["bronze_medal"]:
|
|
|
|
|
sota_exp_stat = "bronze"
|
|
|
|
|
elif grade_output["above_median"]:
|
|
|
|
|
sota_exp_stat = "above_median"
|
|
|
|
|
elif grade_output["valid_submission"]:
|
|
|
|
|
sota_exp_stat = "valid_submission"
|
|
|
|
|
elif grade_output["submission_exists"]:
|
|
|
|
|
sota_exp_stat = "made_submission"
|
2025-02-12 18:57:08 +08:00
|
|
|
if grade_output["score"] is not None:
|
|
|
|
|
sota_exp_score = grade_output["score"]
|
2025-02-11 20:48:30 +08:00
|
|
|
|
2025-01-23 16:12:22 +08:00
|
|
|
stat[log_trace_path.name].update(
|
|
|
|
|
{
|
|
|
|
|
"loop_num": loop_num,
|
|
|
|
|
"made_submission_num": made_submission_num,
|
2025-02-05 16:31:30 +08:00
|
|
|
"valid_submission_num": valid_submission_num,
|
|
|
|
|
"above_median_num": above_median_num,
|
|
|
|
|
"get_medal_num": get_medal_num,
|
|
|
|
|
"bronze_num": bronze_num,
|
|
|
|
|
"silver_num": silver_num,
|
|
|
|
|
"gold_num": gold_num,
|
2025-01-23 16:12:22 +08:00
|
|
|
"test_scores": test_scores,
|
|
|
|
|
"valid_scores": valid_scores,
|
|
|
|
|
"success_loop_num": success_loop_num,
|
2025-02-11 20:48:30 +08:00
|
|
|
"sota_exp_stat": sota_exp_stat,
|
2025-02-12 18:57:08 +08:00
|
|
|
"sota_exp_score": sota_exp_score,
|
|
|
|
|
"bronze_threshold": bronze_threshold,
|
|
|
|
|
"silver_threshold": silver_threshold,
|
|
|
|
|
"gold_threshold": gold_threshold,
|
|
|
|
|
"median_threshold": median_threshold,
|
2025-01-23 16:12:22 +08:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
if (log_folder / "summary.pkl").exists():
|
|
|
|
|
(log_folder / "summary.pkl").unlink()
|
|
|
|
|
print("Old summary file removed.")
|
|
|
|
|
pd.to_pickle(stat, log_folder / "summary.pkl")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# {
|
|
|
|
|
# "competition_id": "stanford-covid-vaccine",
|
|
|
|
|
# "score": null,
|
|
|
|
|
# "gold_threshold": 0.34728,
|
|
|
|
|
# "silver_threshold": 0.35175,
|
|
|
|
|
# "bronze_threshold": 0.3534,
|
|
|
|
|
# "median_threshold": 0.363095,
|
|
|
|
|
# "any_medal": false,
|
|
|
|
|
# "gold_medal": false,
|
|
|
|
|
# "silver_medal": false,
|
|
|
|
|
# "bronze_medal": false,
|
|
|
|
|
# "above_median": false,
|
|
|
|
|
# "submission_exists": true,
|
|
|
|
|
# "valid_submission": false,
|
|
|
|
|
# "is_lower_better": true,
|
|
|
|
|
# "created_at": "2025-01-21T11:59:33.788201",
|
|
|
|
|
# "submission_path": "submission.csv"
|
|
|
|
|
# }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def grade_summary(log_folder):
|
|
|
|
|
log_folder = Path(log_folder)
|
|
|
|
|
save_all_grade_info(log_folder)
|
|
|
|
|
summarize_folder(log_folder)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
fire.Fire(
|
|
|
|
|
{
|
|
|
|
|
"grade": save_all_grade_info,
|
|
|
|
|
"summary": summarize_folder,
|
|
|
|
|
"grade_summary": grade_summary,
|
|
|
|
|
}
|
|
|
|
|
)
|