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:
BIN
scripts_tree/__pycache__/config.cpython-310.pyc
Normal file
BIN
scripts_tree/__pycache__/config.cpython-310.pyc
Normal file
Binary file not shown.
50
scripts_tree/config.py
Normal file
50
scripts_tree/config.py
Normal file
@@ -0,0 +1,50 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(PROJECT_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from scripts.config import CORE_FEATURE_NAMES, DataConfig
|
||||
|
||||
|
||||
@dataclass
|
||||
class TreeModelConfig:
|
||||
candidate_models: tuple[str, ...] = ("extra_trees", "random_forest", "gradient_boosting")
|
||||
random_state: int = 42
|
||||
|
||||
|
||||
@dataclass
|
||||
class TrainConfig:
|
||||
checkpoint_dir: str = "checkpoints_tree"
|
||||
summary_name: str = "model_selection.csv"
|
||||
best_model_name: str = "best_tr_tree.pkl"
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExperimentConfig:
|
||||
data: DataConfig = field(default_factory=DataConfig)
|
||||
model: TreeModelConfig = field(default_factory=TreeModelConfig)
|
||||
train: TrainConfig = field(default_factory=TrainConfig)
|
||||
|
||||
|
||||
def make_experiment_config() -> ExperimentConfig:
|
||||
return ExperimentConfig()
|
||||
|
||||
|
||||
def checkpoint_dir(config: ExperimentConfig) -> Path:
|
||||
path = config.data.project_root / config.train.checkpoint_dir / "task1_tr_tree"
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
return path
|
||||
|
||||
|
||||
def evaluation_dir(config: ExperimentConfig) -> Path:
|
||||
path = config.data.project_root / "evaluation_outputs" / "task1_tr_tree"
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
return path
|
||||
|
||||
|
||||
FEATURE_NAMES = CORE_FEATURE_NAMES
|
||||
177
scripts_tree/evaluate.py
Normal file
177
scripts_tree/evaluate.py
Normal file
@@ -0,0 +1,177 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import pickle
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
|
||||
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, evaluation_dir, make_experiment_config
|
||||
except ImportError:
|
||||
from config import FEATURE_NAMES, evaluation_dir, make_experiment_config
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Evaluate tree model on train/val/test splits.")
|
||||
parser.add_argument("--split", choices=("train", "val", "test"), default="val")
|
||||
parser.add_argument("--sample-index", type=int, default=0)
|
||||
parser.add_argument("--all-samples", action="store_true")
|
||||
parser.add_argument("--checkpoint", type=str, default=None)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def resolve_checkpoint_path(project_root: Path, checkpoint_arg: str | None) -> Path:
|
||||
if checkpoint_arg:
|
||||
return Path(checkpoint_arg).resolve()
|
||||
return project_root / "checkpoints_tree" / "task1_tr_tree" / "best_tr_tree.pkl"
|
||||
|
||||
|
||||
def relative_percent_error(true_value: float, pred_value: float) -> float:
|
||||
return abs(pred_value - true_value) / max(abs(true_value), 1e-12) * 100.0
|
||||
|
||||
|
||||
def evaluate_record(model, record) -> dict[str, float | str]:
|
||||
feature_matrix = [record.features.tolist()]
|
||||
pred_tr = max(float(model.predict(feature_matrix)[0]), 1e-6)
|
||||
x_rms = float(record.x_rms.item())
|
||||
y_rms = float(record.y_rms.item())
|
||||
pred_rms = pred_tr * x_rms
|
||||
row = {
|
||||
"file_name": record.file_path.name,
|
||||
"frequency_hz": float(record.frequency_hz),
|
||||
"true_rms": y_rms,
|
||||
"pred_rms": pred_rms,
|
||||
"relative_error_percent": relative_percent_error(y_rms, pred_rms),
|
||||
"x_rms": x_rms,
|
||||
"pred_tr": pred_tr,
|
||||
"true_tr": float(record.target_y_rms.item()),
|
||||
}
|
||||
for name, value in zip(FEATURE_NAMES, record.features.tolist()):
|
||||
row[name] = float(value)
|
||||
row["sampling_rate"] = float(record.sampling_rate)
|
||||
return row
|
||||
|
||||
|
||||
def save_all_samples_plot(result_df: pd.DataFrame, split: str, save_dir: Path) -> Path | None:
|
||||
if result_df["frequency_hz"].isna().any():
|
||||
return None
|
||||
plot_df = result_df.sort_values("frequency_hz").reset_index(drop=True)
|
||||
fig, axes = plt.subplots(2, 1, figsize=(12, 8))
|
||||
fig.suptitle(f"Task1 TR Tree Evaluation | {split}")
|
||||
|
||||
axes[0].plot(plot_df["frequency_hz"], plot_df["true_rms"], marker="o", label="True RMS")
|
||||
axes[0].plot(plot_df["frequency_hz"], plot_df["pred_rms"], marker="o", label="Pred RMS")
|
||||
axes[0].set_xlabel("Frequency (Hz)")
|
||||
axes[0].set_ylabel("RMS")
|
||||
axes[0].grid(True, alpha=0.3)
|
||||
axes[0].legend()
|
||||
|
||||
axes[1].bar(plot_df["frequency_hz"].astype(str), plot_df["relative_error_percent"], color="tab:orange")
|
||||
axes[1].set_xlabel("Frequency (Hz)")
|
||||
axes[1].set_ylabel("Relative Error (%)")
|
||||
axes[1].grid(True, axis="y", alpha=0.3)
|
||||
axes[1].tick_params(axis="x", labelrotation=45)
|
||||
|
||||
plt.tight_layout()
|
||||
figure_path = save_dir / f"evaluation_{split}_curve.png"
|
||||
plt.savefig(figure_path, dpi=180, bbox_inches="tight")
|
||||
plt.close(fig)
|
||||
return figure_path
|
||||
|
||||
|
||||
def save_single_sample_plot(record, result: dict[str, float | str], split: str, save_dir: Path, sample_index: int) -> Path:
|
||||
time_middle = record.time_middle.detach().cpu().numpy().reshape(-1)
|
||||
x_middle = record.x_middle.detach().cpu().numpy().reshape(-1)
|
||||
y_middle = record.y_middle.detach().cpu().numpy().reshape(-1)
|
||||
frequency_hz = float(result["frequency_hz"])
|
||||
pred_rms = float(result["pred_rms"])
|
||||
true_rms = float(result["true_rms"])
|
||||
|
||||
fig, axes = plt.subplots(3, 1, figsize=(12, 10))
|
||||
fig.suptitle(f"Task1 TR Tree | {split} | {result['file_name']}")
|
||||
|
||||
axes[0].plot(time_middle, x_middle, color="tab:blue")
|
||||
axes[0].set_title("Input Base Excitation (Middle Segment)")
|
||||
axes[0].set_xlabel("Time")
|
||||
axes[0].set_ylabel("Acceleration")
|
||||
axes[0].grid(True, alpha=0.3)
|
||||
|
||||
axes[1].plot(time_middle, y_middle, color="tab:green")
|
||||
axes[1].set_title("True Top Response (Middle Segment)")
|
||||
axes[1].set_xlabel("Time")
|
||||
axes[1].set_ylabel("Acceleration")
|
||||
axes[1].grid(True, alpha=0.3)
|
||||
|
||||
axes[2].bar(["True RMS", "Pred RMS"], [true_rms, pred_rms], color=["tab:green", "tab:orange"])
|
||||
axes[2].set_title(
|
||||
f"Freq: {frequency_hz:.4f} Hz | True RMS: {true_rms:.6f} | Pred RMS: {pred_rms:.6f} | "
|
||||
f"Error: {float(result['relative_error_percent']):.2f}%"
|
||||
)
|
||||
axes[2].set_ylabel("RMS")
|
||||
axes[2].grid(True, axis="y", alpha=0.3)
|
||||
|
||||
plt.tight_layout()
|
||||
figure_path = save_dir / f"evaluation_{split}_s{sample_index}.png"
|
||||
plt.savefig(figure_path, dpi=180, bbox_inches="tight")
|
||||
plt.close(fig)
|
||||
return figure_path
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
config = make_experiment_config()
|
||||
ckpt_path = resolve_checkpoint_path(config.data.project_root, args.checkpoint)
|
||||
with ckpt_path.open("rb") as handle:
|
||||
bundle = pickle.load(handle)
|
||||
model = bundle["model"]
|
||||
|
||||
_, raw_records, reports = build_datasets(config.data)
|
||||
print(report_to_text(reports))
|
||||
records = raw_records[args.split]
|
||||
save_dir = evaluation_dir(config)
|
||||
|
||||
if args.all_samples:
|
||||
rows = [evaluate_record(model, record) for record in records]
|
||||
result_df = pd.DataFrame(rows).sort_values(["relative_error_percent", "file_name"]).reset_index(drop=True)
|
||||
csv_path = save_dir / f"evaluation_{args.split}_all_samples.csv"
|
||||
result_df.to_csv(csv_path, index=False)
|
||||
fig_path = save_all_samples_plot(result_df, args.split, save_dir)
|
||||
summary = {
|
||||
"count": len(result_df),
|
||||
"mean_error_percent": float(result_df["relative_error_percent"].mean()),
|
||||
"median_error_percent": float(result_df["relative_error_percent"].median()),
|
||||
"max_error_percent": float(result_df["relative_error_percent"].max()),
|
||||
"min_error_percent": float(result_df["relative_error_percent"].min()),
|
||||
}
|
||||
print(f"Checkpoint: {ckpt_path}")
|
||||
print(f"Model: {bundle['model_name']}")
|
||||
print(f"Summary: {summary}")
|
||||
print(f"CSV saved to: {csv_path}")
|
||||
if fig_path is not None:
|
||||
print(f"Figure saved to: {fig_path}")
|
||||
print(result_df.to_string(index=False))
|
||||
return
|
||||
|
||||
record = records[args.sample_index]
|
||||
result = evaluate_record(model, record)
|
||||
fig_path = save_single_sample_plot(record, result, args.split, save_dir, args.sample_index)
|
||||
print(f"Checkpoint: {ckpt_path}")
|
||||
print(f"Model: {bundle['model_name']}")
|
||||
print(f"Sample file: {result['file_name']}")
|
||||
print(f"True RMS: {float(result['true_rms']):.6f}")
|
||||
print(f"Pred RMS: {float(result['pred_rms']):.6f}")
|
||||
print(f"Relative RMS Error (%): {float(result['relative_error_percent']):.4f}")
|
||||
print(f"Figure saved to: {fig_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
115
scripts_tree/predict_single.py
Normal file
115
scripts_tree/predict_single.py
Normal file
@@ -0,0 +1,115 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import pickle
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
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_record_from_file
|
||||
|
||||
try:
|
||||
from .config import FEATURE_NAMES, evaluation_dir, make_experiment_config
|
||||
except ImportError:
|
||||
from config import FEATURE_NAMES, evaluation_dir, make_experiment_config
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Predict task1 RMS from a single waveform CSV with tree model.")
|
||||
parser.add_argument("--file", type=str, required=True)
|
||||
parser.add_argument("--checkpoint", type=str, default=None)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def resolve_checkpoint_path(project_root: Path, checkpoint_arg: str | None) -> Path:
|
||||
if checkpoint_arg:
|
||||
return Path(checkpoint_arg).resolve()
|
||||
return project_root / "checkpoints_tree" / "task1_tr_tree" / "best_tr_tree.pkl"
|
||||
|
||||
|
||||
def save_prediction_figure(file_path: Path, record, pred_rms: float, true_rms: float | None, output_dir: Path) -> Path:
|
||||
time_middle = record.time_middle.detach().cpu().numpy().reshape(-1)
|
||||
x_middle = record.x_middle.detach().cpu().numpy().reshape(-1)
|
||||
sampling_rate = record.sampling_rate
|
||||
fft_values = np.fft.rfft(x_middle)
|
||||
freqs = np.fft.rfftfreq(x_middle.size, d=1.0 / sampling_rate)
|
||||
amplitudes = np.abs(fft_values)
|
||||
|
||||
fig, axes = plt.subplots(3, 1, figsize=(12, 10))
|
||||
fig.suptitle(f"Task1 TR Tree Single-File Prediction | {file_path.name}")
|
||||
|
||||
axes[0].plot(time_middle, x_middle, color="tab:blue")
|
||||
axes[0].set_title("Input Base Excitation (Middle Segment)")
|
||||
axes[0].set_xlabel("Time")
|
||||
axes[0].set_ylabel("Acceleration")
|
||||
axes[0].grid(True, alpha=0.3)
|
||||
|
||||
axes[1].plot(freqs, amplitudes, color="tab:purple")
|
||||
axes[1].axvline(record.frequency_hz, color="tab:red", linestyle="--", label=f"Dominant freq = {record.frequency_hz:.4f} Hz")
|
||||
axes[1].set_xlim(0.0, 5.0)
|
||||
axes[1].set_title("Input Spectrum")
|
||||
axes[1].set_xlabel("Frequency (Hz)")
|
||||
axes[1].set_ylabel("Amplitude")
|
||||
axes[1].grid(True, alpha=0.3)
|
||||
axes[1].legend()
|
||||
|
||||
labels = ["Pred RMS"] if true_rms is None else ["True RMS", "Pred RMS"]
|
||||
values = [pred_rms] if true_rms is None else [true_rms, pred_rms]
|
||||
colors = ["tab:orange"] if true_rms is None else ["tab:green", "tab:orange"]
|
||||
axes[2].bar(labels, values, color=colors)
|
||||
title = f"Predicted RMS = {pred_rms:.6f}"
|
||||
if true_rms is not None:
|
||||
error_percent = abs(pred_rms - true_rms) / max(abs(true_rms), 1e-12) * 100.0
|
||||
title = f"True RMS = {true_rms:.6f} | Pred RMS = {pred_rms:.6f} | Error = {error_percent:.2f}%"
|
||||
axes[2].set_title(title)
|
||||
axes[2].set_ylabel("RMS")
|
||||
axes[2].grid(True, axis="y", alpha=0.3)
|
||||
|
||||
plt.tight_layout()
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
figure_path = output_dir / f"{file_path.stem}_prediction.png"
|
||||
plt.savefig(figure_path, dpi=180, bbox_inches="tight")
|
||||
plt.close(fig)
|
||||
return figure_path
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
config = make_experiment_config()
|
||||
ckpt_path = resolve_checkpoint_path(config.data.project_root, args.checkpoint)
|
||||
with ckpt_path.open("rb") as handle:
|
||||
bundle = pickle.load(handle)
|
||||
model = bundle["model"]
|
||||
|
||||
file_path = Path(args.file).resolve()
|
||||
record = build_record_from_file(file_path, split="predict", config=config.data)
|
||||
pred_tr = max(float(model.predict([record.features.tolist()])[0]), 1e-6)
|
||||
pred_rms = pred_tr * float(record.x_rms.item())
|
||||
true_rms = float(record.y_rms.item()) if record.y_rms.numel() > 0 else None
|
||||
|
||||
out_dir = evaluation_dir(config)
|
||||
fig_path = save_prediction_figure(file_path, record, pred_rms, true_rms, out_dir)
|
||||
|
||||
print(f"Checkpoint: {ckpt_path}")
|
||||
print(f"Model: {bundle['model_name']}")
|
||||
print(f"Input file: {file_path}")
|
||||
print(f"Extracted frequency (Hz): {record.frequency_hz:.6f}")
|
||||
for feature_name, feature_value in zip(FEATURE_NAMES, record.features.tolist()):
|
||||
print(f"{feature_name}: {feature_value:.6f}")
|
||||
print(f"Predicted TR: {pred_tr:.6f}")
|
||||
print(f"Predicted RMS: {pred_rms:.6f}")
|
||||
if true_rms is not None:
|
||||
error_percent = abs(pred_rms - true_rms) / max(abs(true_rms), 1e-12) * 100.0
|
||||
print(f"True RMS: {true_rms:.6f}")
|
||||
print(f"Relative RMS Error (%): {error_percent:.4f}")
|
||||
print(f"Figure saved to: {fig_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
160
scripts_tree/train.py
Normal file
160
scripts_tree/train.py
Normal 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()
|
||||
Reference in New Issue
Block a user