169 lines
5.0 KiB
Python
169 lines
5.0 KiB
Python
import os
|
|
import matplotlib.pyplot as plt
|
|
import numpy as np
|
|
import pandas as pd
|
|
import seaborn as sns
|
|
from sklearn.ensemble import HistGradientBoostingRegressor
|
|
from sklearn.model_selection import GroupShuffleSplit
|
|
|
|
from src.training.decision_tree import preprocessor
|
|
from src.training.decision_tree.model import Model
|
|
from src.training.decision_tree.visualizer import Visualizer
|
|
from src.training.simulated_annealing.simulated_annealing import SimulatedAnnealing
|
|
|
|
# Path setup for saving figures
|
|
SAVE_DIR = "./doc/hyperparametersOptimisation/simulatedAnnealing/"
|
|
SAVE_PATH = os.path.join(SAVE_DIR, "pairwise_exploration.png")
|
|
os.makedirs(SAVE_DIR, exist_ok=True)
|
|
|
|
# Shared history state
|
|
evaluations_history = []
|
|
|
|
def create_split(x, y, game_ids):
|
|
|
|
splitter = GroupShuffleSplit(
|
|
n_splits=1,
|
|
test_size=0.10,
|
|
random_state=42
|
|
)
|
|
|
|
train_indices, test_indices = next(splitter.split(x, y, groups=game_ids))
|
|
|
|
x_train = x[train_indices]
|
|
x_test = x[test_indices]
|
|
|
|
y_train = y[train_indices]
|
|
y_test = y[test_indices]
|
|
|
|
train_games = set(game_ids[train_indices])
|
|
test_games = set(game_ids[test_indices])
|
|
|
|
print("Train positions:", len(x_train))
|
|
print("Test positions:", len(x_test))
|
|
print("Train games:", len(train_games))
|
|
print("Test games:", len(test_games))
|
|
print("Overlapping games:", len(train_games & test_games))
|
|
|
|
return x_train, x_test, y_train, y_test
|
|
|
|
# Graph for hyperparameter visualisation
|
|
def update_live_pairwise_plot(history, save_path):
|
|
"""Refreshes the live Seaborn pairplot and exports the updated figure to disk."""
|
|
df = pd.DataFrame(
|
|
[
|
|
{
|
|
"max_depth": e["params"]["max_depth"],
|
|
"min_samples_leaf": e["params"]["min_samples_leaf"],
|
|
# "n_estimators": e["params"]["n_estimators"],
|
|
"max_features": e["params"]["max_features"],
|
|
"test_mse": e["test_mse"],
|
|
}
|
|
for e in history
|
|
]
|
|
)
|
|
|
|
# Close previous figures to avoid accumulating memory and orphaned windows
|
|
plt.close("all")
|
|
|
|
# Render pairwise exploration matrix
|
|
grid = sns.pairplot(
|
|
df,
|
|
vars=[
|
|
"max_depth",
|
|
"min_samples_leaf",
|
|
# "n_estimators",
|
|
"max_features"],
|
|
hue="test_mse",
|
|
palette="crest",
|
|
diag_kind="kde",
|
|
)
|
|
grid.figure.suptitle(f"Live SA Search (Iteration {len(history)})", y=1.02)
|
|
|
|
# Save to disk
|
|
grid.savefig(save_path, bbox_inches="tight")
|
|
|
|
# Force Matplotlib canvas redraw and flush event loop
|
|
grid.figure.canvas.draw()
|
|
grid.figure.canvas.flush_events()
|
|
plt.pause(0.05)
|
|
|
|
# Callback function for training the model with given hyperparameters
|
|
def train_model(parameters):
|
|
# Enable interactive figure mode on first run
|
|
|
|
model = Model(
|
|
tree=HistGradientBoostingRegressor(**parameters),
|
|
feature_names=preprocessor.get_feature_names(),
|
|
train_test_split=split,
|
|
)
|
|
|
|
model.train()
|
|
train_mae, train_mse, test_mae, test_mse = model.evaluate()
|
|
model.release_training_data()
|
|
|
|
# Track current iteration state
|
|
evaluations_history.append(
|
|
{
|
|
"params": parameters,
|
|
"train_mse": train_mse,
|
|
"test_mse": test_mse,
|
|
}
|
|
)
|
|
|
|
# Trigger live update & file saving
|
|
update_live_pairwise_plot(evaluations_history, SAVE_PATH)
|
|
|
|
return test_mse
|
|
|
|
|
|
if __name__ == "__main__":
|
|
model_path = "./src/training/decision_tree/cache/model.joblib"
|
|
|
|
if os.path.exists(model_path):
|
|
model = Model.load(model_path)
|
|
else:
|
|
x, y, game_ids = preprocessor.run("./dataset/output.csv")
|
|
split = create_split(x, y, game_ids)
|
|
del x, y, game_ids
|
|
|
|
plt.ion()
|
|
|
|
base_model_parameters = {
|
|
"max_depth": {"min": 1, "max": 100},
|
|
"min_samples_leaf": {"min": 1, "max": 30},
|
|
# "n_estimators": {"min": 10, "max": 100},
|
|
"max_features": {"min": 0.01, "max": 1.0},
|
|
"random_state": 42,
|
|
# "n_jobs": 15,
|
|
}
|
|
|
|
optimization_algorithm = SimulatedAnnealing(
|
|
parameter_space=base_model_parameters,
|
|
initial_temperature=1,
|
|
cooling_rate=0.90,
|
|
max_iterations=100,
|
|
)
|
|
optimization_algorithm.set_training_callback(train_model)
|
|
|
|
try:
|
|
best_solution, best_score = optimization_algorithm.optimize()
|
|
except KeyboardInterrupt:
|
|
print("\n[Optimization Interrupted] Early exit triggered by user.")
|
|
|
|
|
|
print("\n[Optimization Complete] Training model with best hyperparameters :")
|
|
model = Model(
|
|
tree=HistGradientBoostingRegressor(**best_solution),
|
|
feature_names=preprocessor.get_feature_names(),
|
|
train_test_split=split,
|
|
)
|
|
|
|
model.train()
|
|
train_mae, train_mse, test_mae, test_mse = model.evaluate()
|
|
model.release_training_data()
|
|
|
|
plt.ioff()
|
|
plt.show()
|
|
|
|
visualizer = Visualizer(model=model)
|
|
visualizer.show_feature_importance(15) |