diff --git a/src/policies/policy_executer.py b/src/policies/policy_executer.py index e343231..4028326 100644 --- a/src/policies/policy_executer.py +++ b/src/policies/policy_executer.py @@ -8,7 +8,8 @@ import pandas as pd import datetime from tqdm import tqdm from src.utils.imbalance_price_calculator import ImbalancePriceCalculator -import time +import seaborn as sns +import matplotlib.pyplot as plt import plotly.express as px ### import functions ### @@ -16,7 +17,7 @@ from src.trainers.quantile_trainer import auto_regressive as quantile_auto_regre from src.trainers.diffusion_trainer import sample_diffusion from src.utils.clearml import ClearMLHelper -# argparse to parse task id and model type +### Arguments ### parser = argparse.ArgumentParser() parser.add_argument('--task_id', type=str, default=None) parser.add_argument('--model_type', type=str, default=None) @@ -27,6 +28,7 @@ assert args.task_id is not None, "Please specify task id" assert args.model_type is not None, "Please specify model type" assert args.model_name is not None, "Please specify model name" +### Baseline Policy ### battery = Battery(2, 1) baseline_policy = BaselinePolicy(battery, data_path="") @@ -163,20 +165,17 @@ def get_next_day_profits_for_date(model, data_processor, test_loader, date, ipc, return predicted_nrv_profits_cycles, baseline_profits_cycles, _charge_thresholds, _discharge_thresholds def next_day_test_set(model, data_processor, test_loader, ipc, predict_NRV: callable): - penalties = [0, 10, 50, 150, 300, 500, 600, 800, 1000, 1500, 2000, 2500] + penalties = [0, 50, 250, 500, 1000, 1500] predicted_nrv_profits_cycles = {i: [0, 0] for i in penalties} baseline_profits_cycles = {i: [0, 0] for i in penalties} charge_thresholds = {} discharge_thresholds = {} - # get all dates in test set dates = baseline_policy.test_data["DateTime"].dt.date.unique() - - # dates back to datetime dates = pd.to_datetime(dates) - for date in tqdm(dates[:10]): + for date in tqdm(dates): try: new_predicted_nrv_profits_cycles, new_baseline_profits_cycles, new_charge_thresholds, new_discharge_thresholds = get_next_day_profits_for_date(model, data_processor, test_loader, date, ipc, predict_NRV, penalties) @@ -191,8 +190,7 @@ def next_day_test_set(model, data_processor, test_loader, ipc, predict_NRV: call baseline_profits_cycles[penalty][1] += new_baseline_profits_cycles[penalty][1] except Exception as e: - # print(f"Error for date {date}") - raise e + print(f"Error for date {date}") return predicted_nrv_profits_cycles, baseline_profits_cycles, charge_thresholds, discharge_thresholds @@ -222,9 +220,6 @@ def main(): # the charge_thresholds is a dictionary with date as key. The values of the dictionary is another dictionary with keys as penalties and values as the charge thresholds # create density plot that shows a density plot of the charge thresholds for each penalty (use seaborn displot) (One plot with a different color for each penalty) - import seaborn as sns - import matplotlib.pyplot as plt - charge_thresholds_for_penalty = {} for d in charge_thresholds.values(): for penalty, thresholds in d.items(): @@ -239,47 +234,73 @@ def main(): discharge_thresholds_for_penalty[penalty] = [] discharge_thresholds_for_penalty[penalty].extend(thresholds) + def plot_threshold_distribution(thresholds: dict, title: str): + data_to_plot = [] + for penalty, values in thresholds.items(): + for value in values: + data_to_plot.append({'Penalty': penalty, 'Value': value.item()}) + df = pd.DataFrame(data_to_plot) + palette = sns.color_palette("bright", len(thresholds.keys())) + fig = sns.displot(data=df, x="Value", hue="Penalty", kind="kde", palette=palette) + plt.title('Density of Charge Thresholds by Penalty') + plt.xlabel('Charge Threshold') + plt.ylabel('Density') + plt.legend(title='Penalty') + task.get_logger().report_matplotlib_figure( + "Policy Results", + title, + iteration=0, + figure=fig + ) + plt.close() + ### Plot charge thresholds distribution ### - data_to_plot = [] - for penalty, values in charge_thresholds_for_penalty.items(): - for value in values: - data_to_plot.append({'Penalty': penalty, 'Value': value.item()}) - df = pd.DataFrame(data_to_plot) - print(df.head()) - palette = sns.color_palette("bright", len(charge_thresholds.keys())) - fig = sns.displot(data=df, x="Value", hue="Penalty", kind="kde", palette=palette) - plt.title('Density of Charge Thresholds by Penalty') - plt.xlabel('Charge Threshold') - plt.ylabel('Density') - plt.legend(title='Penalty') - task.get_logger().report_matplotlib_figure( - "Policy Results", - "Charge Thresholds", - iteration=0, - figure=fig - ) - plt.close() + plot_threshold_distribution(charge_thresholds_for_penalty, "Charge Thresholds") ### Plot discharge thresholds distribution ### - data_to_plot = [] - for penalty, values in discharge_thresholds_for_penalty.items(): - for value in values: - data_to_plot.append({'Penalty': penalty, 'Value': value.item()}) - df = pd.DataFrame(data_to_plot) - palette = sns.color_palette("bright", len(discharge_thresholds.keys())) - fig = sns.displot(data=df, x="Value", hue="Penalty", kind="kde", palette=palette) - plt.title('Density of Charge Thresholds by Penalty') - plt.xlabel('Charge Threshold') - plt.ylabel('Density') - plt.legend(title='Penalty') - task.get_logger().report_matplotlib_figure( - "Policy Results", - "Discharge Thresholds", - iteration=0, - figure=fig - ) - plt.close() + plot_threshold_distribution(discharge_thresholds_for_penalty, "Discharge Thresholds") + def plot_thresholds_per_day(thresholds: dict, title: str): + # plot mean charge threshold per day (per penalty (other color)) + data_to_plot = [] + for date, values in thresholds.items(): + for penalty, value in values.items(): + mean_val = value.mean().item() + std_val = value.std().item() # Calculate standard deviation + data_to_plot.append({'Date': date, 'Penalty': penalty, 'Mean': mean_val, 'StdDev': std_val}) + print(f"Date: {date}, Penalty: {penalty}, Mean: {mean_val}, StdDev: {std_val}") + df = pd.DataFrame(data_to_plot) + df["Date"] = pd.to_datetime(df["Date"]) + + fig = px.line( + df, + x="Date", + y="Mean", + color="Penalty", + title=title, + labels={"Mean": "Threshold", "Date": "Date"}, + markers=True, # Adds markers to the lines + hover_data=["Penalty"], # Adds additional hover information + ) + + fig.update_layout( + width=1000, # Set the width of the figure + height=600, # Set the height of the figure + title_x=0.5, # Center the title horizontally + ) + + task.get_logger().report_plotly( + "Thresholds per Day", + title, + iteration=0, + figure=fig + ) + + ### Plot mean charge thresholds per day ### + plot_thresholds_per_day(charge_thresholds, "Mean Charge Thresholds per Day") + + ### Plot mean discharge thresholds per day ### + plot_thresholds_per_day(discharge_thresholds, "Mean Discharge Thresholds per Day") # create dataframe with columns "name", "penalty", "profit", "cycles" diff --git a/src/trainers/diffusion_trainer.py b/src/trainers/diffusion_trainer.py index f96ebd6..6aa0185 100644 --- a/src/trainers/diffusion_trainer.py +++ b/src/trainers/diffusion_trainer.py @@ -19,8 +19,6 @@ def sample_diffusion(model: DiffusionModel, n: int, inputs: torch.tensor, noise_ alpha = 1. - beta alpha_hat = torch.cumprod(alpha, dim=0) - # inputs: (num_features) -> (batch_size, num_features) - # inputs: (time_steps, num_features) -> (batch_size, time_steps, num_features) if len(inputs.shape) == 2: inputs = inputs.repeat(n, 1) elif len(inputs.shape) == 3: @@ -42,17 +40,17 @@ def sample_diffusion(model: DiffusionModel, n: int, inputs: torch.tensor, noise_ noise = torch.zeros_like(x) x = 1/torch.sqrt(_alpha) * (x-((1-_alpha) / (torch.sqrt(1 - _alpha_hat))) * predicted_noise) + torch.sqrt(_beta) * noise + x = torch.clamp(x, -1.0, 1.0) return x - class DiffusionTrainer: def __init__(self, model: nn.Module, data_processor: DataProcessor, device: torch.device): self.model = model self.device = device - self.noise_steps = 20 - self.beta_start = 1e-4 + self.noise_steps = 30 + self.beta_start = 0.0001 self.beta_end = 0.02 self.ts_length = 96 @@ -183,17 +181,18 @@ class DiffusionTrainer: with torch.no_grad(): samples = self.sample(self.model, 100, features).cpu().numpy() - ci_99_upper = np.quantile(samples, 0.99, axis=0) - ci_99_lower = np.quantile(samples, 0.01, axis=0) + ci_99_upper = np.quantile(samples, 0.995, axis=0) + ci_99_lower = np.quantile(samples, 0.005, axis=0) - ci_95_upper = np.quantile(samples, 0.95, axis=0) - ci_95_lower = np.quantile(samples, 0.05, axis=0) + ci_95_upper = np.quantile(samples, 0.975, axis=0) + ci_95_lower = np.quantile(samples, 0.025, axis=0) - ci_90_upper = np.quantile(samples, 0.9, axis=0) - ci_90_lower = np.quantile(samples, 0.1, axis=0) + ci_90_upper = np.quantile(samples, 0.95, axis=0) + ci_90_lower = np.quantile(samples, 0.05, axis=0) + + ci_50_lower = np.quantile(samples, 0.25, axis=0) + ci_50_upper = np.quantile(samples, 0.75, axis=0) - ci_50_upper = np.quantile(samples, 0.5, axis=0) - ci_50_lower = np.quantile(samples, 0.5, axis=0) sns.set_theme() time_steps = np.arange(0, 96) diff --git a/src/training_scripts/diffusion_training.py b/src/training_scripts/diffusion_training.py index 9a1c2a3..d6b998c 100644 --- a/src/training_scripts/diffusion_training.py +++ b/src/training_scripts/diffusion_training.py @@ -38,7 +38,7 @@ data_config.NOMINAL_NET_POSITION = True data_config = task.connect(data_config, name="data_features") data_processor = DataProcessor(data_config, path="", lstm=False) -data_processor.set_batch_size(128) +data_processor.set_batch_size(64) data_processor.set_full_day_skip(True) inputDim = data_processor.get_input_size() @@ -47,15 +47,15 @@ print("Input dim: ", inputDim) model_parameters = { "epochs": 5000, "learning_rate": 0.0001, - "hidden_sizes": [512, 512, 512], - "time_dim": 64, + "hidden_sizes": [128, 128], + "time_dim": 8, } model_parameters = task.connect(model_parameters, name="model_parameters") #### Model #### -# model = SimpleDiffusionModel(96, model_parameters["hidden_sizes"], other_inputs_dim=inputDim[1], time_dim=model_parameters["time_dim"]) -model = GRUDiffusionModel(96, model_parameters["hidden_sizes"], other_inputs_dim=inputDim[2], time_dim=model_parameters["time_dim"], gru_hidden_size=256) +model = SimpleDiffusionModel(96, model_parameters["hidden_sizes"], other_inputs_dim=inputDim[1], time_dim=model_parameters["time_dim"]) +# model = GRUDiffusionModel(96, model_parameters["hidden_sizes"], other_inputs_dim=inputDim[2], time_dim=model_parameters["time_dim"], gru_hidden_size=128) print("Starting training ...")