new file: checkpoints_tree/task1_tr_tree/best_tr_tree.pkl

new file:   checkpoints_tree/task1_tr_tree/model_selection.csv
	new file:   evaluation_outputs/task1_tr_tree/evaluation_train_all_samples.csv
	new file:   evaluation_outputs/task1_tr_tree/evaluation_train_curve.png
	new file:   evaluation_outputs/task1_tr_tree/evaluation_val_all_samples.csv
	new file:   evaluation_outputs/task1_tr_tree/evaluation_val_curve.png
	new file:   evaluation_outputs/task1_tr_tree/harmonic_5mm_1.55Hz_prediction.png
	new file:   scripts_tree/__pycache__/config.cpython-310.pyc
	new file:   scripts_tree/config.py
	new file:   scripts_tree/evaluate.py
	new file:   scripts_tree/predict_single.py
	new file:   scripts_tree/train.py
This commit is contained in:
2026-05-06 12:32:49 +08:00
parent 484643409d
commit 02e488cd0d
12 changed files with 549 additions and 0 deletions

160
scripts_tree/train.py Normal file
View File

@@ -0,0 +1,160 @@
from __future__ import annotations
import pickle
from dataclasses import asdict
from pathlib import Path
from typing import Any
import sys
import pandas as pd
from sklearn.ensemble import ExtraTreesRegressor, GradientBoostingRegressor, RandomForestRegressor
PROJECT_ROOT = Path(__file__).resolve().parents[1]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
from scripts.dataset import build_datasets, report_to_text
try:
from .config import FEATURE_NAMES, ExperimentConfig, checkpoint_dir, make_experiment_config
except ImportError:
from config import FEATURE_NAMES, ExperimentConfig, checkpoint_dir, make_experiment_config
def build_regressor(model_name: str, random_state: int):
if model_name == "extra_trees":
return ExtraTreesRegressor(
n_estimators=600,
max_depth=None,
min_samples_leaf=1,
min_samples_split=2,
random_state=random_state,
)
if model_name == "random_forest":
return RandomForestRegressor(
n_estimators=500,
max_depth=None,
min_samples_leaf=1,
min_samples_split=2,
random_state=random_state,
)
if model_name == "gradient_boosting":
return GradientBoostingRegressor(
n_estimators=300,
learning_rate=0.03,
max_depth=3,
random_state=random_state,
loss="huber",
)
raise ValueError(f"Unsupported model: {model_name}")
def records_to_frame(records: list[Any]) -> pd.DataFrame:
rows = []
for record in records:
row = {
"file_name": record.file_path.name,
"frequency_hz": float(record.frequency_hz),
"x_rms": float(record.x_rms.item()),
"y_rms": float(record.y_rms.item()),
"target_tr": float(record.target_y_rms.item()),
}
for name, value in zip(FEATURE_NAMES, record.features.tolist()):
row[name] = float(value)
rows.append(row)
return pd.DataFrame(rows)
def evaluate_frame(model, frame: pd.DataFrame) -> dict[str, float]:
feature_matrix = frame.loc[:, FEATURE_NAMES].to_numpy()
pred_tr = model.predict(feature_matrix)
pred_tr = pred_tr.clip(min=1e-6)
pred_rms = pred_tr * frame["x_rms"].to_numpy()
true_rms = frame["y_rms"].to_numpy()
relative_error = abs(pred_rms - true_rms) / true_rms.clip(min=1e-6)
return {
"mean_rms_error": float(relative_error.mean()),
"median_rms_error": float(pd.Series(relative_error).median()),
"max_rms_error": float(relative_error.max()),
}
def serialize_for_checkpoint(value: Any) -> Any:
if isinstance(value, Path):
return str(value)
if isinstance(value, dict):
return {key: serialize_for_checkpoint(sub_value) for key, sub_value in value.items()}
if isinstance(value, tuple):
return [serialize_for_checkpoint(item) for item in value]
if isinstance(value, list):
return [serialize_for_checkpoint(item) for item in value]
return value
def train() -> None:
config = make_experiment_config()
datasets, raw_records, reports = build_datasets(config.data)
del datasets
print(report_to_text(reports))
train_df = records_to_frame(raw_records["train"])
val_df = records_to_frame(raw_records["val"])
feature_matrix = train_df.loc[:, FEATURE_NAMES].to_numpy()
target = train_df["target_tr"].to_numpy()
results: list[dict[str, Any]] = []
best_bundle: dict[str, Any] | None = None
best_val_error = float("inf")
for model_name in config.model.candidate_models:
model = build_regressor(model_name, config.model.random_state)
model.fit(feature_matrix, target)
train_metrics = evaluate_frame(model, train_df)
val_metrics = evaluate_frame(model, val_df)
row = {
"model_name": model_name,
"train_mean_rms_error": train_metrics["mean_rms_error"],
"train_median_rms_error": train_metrics["median_rms_error"],
"train_max_rms_error": train_metrics["max_rms_error"],
"val_mean_rms_error": val_metrics["mean_rms_error"],
"val_median_rms_error": val_metrics["median_rms_error"],
"val_max_rms_error": val_metrics["max_rms_error"],
}
results.append(row)
print(
f"{model_name}: train_mean={train_metrics['mean_rms_error']:.6f} | "
f"val_mean={val_metrics['mean_rms_error']:.6f}"
)
if val_metrics["mean_rms_error"] < best_val_error:
best_val_error = val_metrics["mean_rms_error"]
best_bundle = {
"model_name": model_name,
"model": model,
"config": serialize_for_checkpoint(asdict(config)),
"feature_names": list(FEATURE_NAMES),
"val_metrics": val_metrics,
"train_metrics": train_metrics,
}
summary_df = pd.DataFrame(results).sort_values("val_mean_rms_error").reset_index(drop=True)
ckpt_dir = checkpoint_dir(config)
summary_path = ckpt_dir / config.train.summary_name
summary_df.to_csv(summary_path, index=False)
print(f"Model selection saved to: {summary_path}")
print(summary_df.to_string(index=False))
if best_bundle is None:
raise RuntimeError("No valid model trained.")
best_path = ckpt_dir / config.train.best_model_name
with best_path.open("wb") as handle:
pickle.dump(best_bundle, handle)
print(f"Best tree model saved to: {best_path}")
print(f"Best model: {best_bundle['model_name']} | val_mean_rms_error={best_val_error:.6f}")
if __name__ == "__main__":
train()