Rewrote dataset to be able to include new features
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
# Result Report November
|
||||
# Result Report November (1)
|
||||
## 1. TODOs
|
||||
|
||||
- [x] Compare autoregressive vs non-autoregressive
|
||||
- [ ] Add more input parameters (load forecast)
|
||||
- [x] Quantile Regression sampling fix
|
||||
- [x] Quantile Regression exploration
|
||||
- [ ] Plots with good scaling (y-axis)
|
||||
|
||||
## 2. Autoregressive vs Non-Autoregressive
|
||||
|
||||
@@ -84,4 +85,10 @@ Hidden Units: 1024
|
||||
| Quantiles | Train-MAE | Train-MSE | Test-MAE | Test-MSE |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 0.1, 0.2, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.8, 0.9 | 65.6542529596313 | 7392.5142575554955 | 77.55779692831604 | 10769.161724849037 |
|
||||
| 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 | 65.68495924348356 | 7326.2239225611975 | 77.62433888969542 | 10789.003223366473 |
|
||||
| 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 | 65.68495924348356 | 7326.2239225611975 | 77.62433888969542 | 10789.003223366473 |
|
||||
|
||||
Also tried one with dropout of 0.3, results are better. This needs to be tested more (hyperparameter tuning is not the focus here):
|
||||
|
||||
| Quantiles | Train-MAE | Train-MSE | Test-MAE | Test-MSE |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 | 63.710736942371994 | 6988.6436956508105 | 77.29499496466444 | 10706.484005597813 |
|
||||
310945
data/load_forecast.csv
Normal file
310945
data/load_forecast.csv
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,2 @@
|
||||
from .dataset import NrvDataset
|
||||
from .preprocessing import DataProcessor
|
||||
from .preprocessing import DataProcessor, DataConfig
|
||||
@@ -3,13 +3,61 @@ from torch.utils.data import Dataset, DataLoader
|
||||
import pandas as pd
|
||||
|
||||
class NrvDataset(Dataset):
|
||||
def __init__(self, dataframe, sequence_length=96, predict_sequence_length=96):
|
||||
self.data = torch.tensor(dataframe['nrv'].to_numpy(), dtype=torch.float32)
|
||||
def __init__(self, dataframe, data_config, sequence_length=96, predict_sequence_length=96):
|
||||
self.data_config = data_config
|
||||
|
||||
self.nrv = torch.tensor(dataframe['nrv'].to_numpy(), dtype=torch.float32)
|
||||
self.load_forecast = torch.tensor(dataframe['load_forecast'].to_numpy(), dtype=torch.float32)
|
||||
|
||||
self.sequence_length = sequence_length
|
||||
self.predict_sequence_length = predict_sequence_length
|
||||
|
||||
def __len__(self):
|
||||
return len(self.data) - self.sequence_length - self.predict_sequence_length
|
||||
return len(self.nrv) - self.sequence_length - self.predict_sequence_length
|
||||
|
||||
def __getitem__(self, idx):
|
||||
return self.data[idx:idx+self.sequence_length], self.data[idx+self.sequence_length:idx+self.sequence_length+self.predict_sequence_length]
|
||||
features = []
|
||||
|
||||
if self.data_config.NRV_HISTORY:
|
||||
nrv = self.nrv[idx:idx+self.sequence_length]
|
||||
features.append(nrv.view(-1))
|
||||
|
||||
if self.data_config.LOAD_HISTORY:
|
||||
load_history = self.load_forecast[idx:idx+self.sequence_length]
|
||||
features.append(load_history.view(-1))
|
||||
|
||||
if self.data_config.LOAD_FORECAST:
|
||||
load_forecast = self.load_forecast[idx+self.sequence_length:idx+self.sequence_length+self.predict_sequence_length]
|
||||
features.append(load_forecast.view(-1))
|
||||
|
||||
if not features:
|
||||
raise ValueError("No features are configured to be included in the dataset.")
|
||||
|
||||
# Concatenate along dimension 0 to create a one-dimensional feature vector
|
||||
all_features = torch.cat(features, dim=0)
|
||||
|
||||
# Target sequence, flattened if necessary
|
||||
nrv_target = self.nrv[idx+self.sequence_length:idx+self.sequence_length+self.predict_sequence_length].view(-1)
|
||||
|
||||
return all_features, nrv_target
|
||||
|
||||
def random_day_autoregressive(self, idx: int):
|
||||
features = []
|
||||
|
||||
# we already have the NRV history with the newly predicted values, so we don't need to include the last 96 values
|
||||
|
||||
if self.data_config.LOAD_HISTORY:
|
||||
load_history = self.load_forecast[idx:idx+self.sequence_length]
|
||||
features.append(load_history.view(-1))
|
||||
|
||||
if self.data_config.LOAD_FORECAST:
|
||||
load_forecast = self.load_forecast[idx+self.sequence_length:idx+self.sequence_length+self.predict_sequence_length]
|
||||
features.append(load_forecast.view(-1))
|
||||
|
||||
target = self.nrv[idx+self.sequence_length:idx+self.sequence_length+self.predict_sequence_length]
|
||||
|
||||
if len(features) == 0:
|
||||
return None, target
|
||||
|
||||
all_features = torch.cat(features, dim=0)
|
||||
return all_features, target
|
||||
@@ -8,9 +8,15 @@ import pytz
|
||||
|
||||
|
||||
history_data_path = "../../data/history-quarter-hour-data.csv"
|
||||
forecast_data_path = "../../data/load_forecast.csv"
|
||||
|
||||
class DataConfig:
|
||||
NRV_HISTORY: bool = True
|
||||
LOAD_FORECAST: bool = True
|
||||
LOAD_HISTORY: bool = False
|
||||
|
||||
class DataProcessor:
|
||||
def __init__(self):
|
||||
def __init__(self, data_config: DataConfig):
|
||||
self.batch_size = 2048
|
||||
|
||||
self.train_range = (-np.inf, datetime(year=2022, month=11, day=30, tzinfo=pytz.UTC))
|
||||
@@ -18,10 +24,15 @@ class DataProcessor:
|
||||
|
||||
self.update_range_str()
|
||||
|
||||
self.features = ['nrv']
|
||||
self.history_features = self.get_nrv_history()
|
||||
self.future_features = self.get_load_forecast()
|
||||
|
||||
self.all_features = self.history_features.merge(self.future_features, on='datetime', how='left')
|
||||
|
||||
self.data_config = data_config
|
||||
|
||||
self.nrv_df = self.get_nrv_history()
|
||||
self.nrv_scaler = MinMaxScaler(feature_range=(-1, 1))
|
||||
self.load_forecast_scaler = MinMaxScaler(feature_range=(-1, 1))
|
||||
|
||||
|
||||
def set_train_range(self, train_range: tuple):
|
||||
@@ -49,6 +60,22 @@ class DataProcessor:
|
||||
df.sort_values(by="datetime", inplace=True)
|
||||
return df
|
||||
|
||||
def get_load_forecast(self):
|
||||
df = pd.read_csv(forecast_data_path, delimiter=';')
|
||||
df = df.rename(columns={'Day-ahead 6PM forecast': 'load_forecast', 'Datetime': 'datetime'})
|
||||
df = df[['datetime', 'load_forecast']]
|
||||
|
||||
df['datetime'] = pd.to_datetime(df['datetime'], utc=True)
|
||||
|
||||
# check if there are nan values
|
||||
# if df.isnull().values.any():
|
||||
# # print the rows with nan values
|
||||
# print(df[df.isnull().any(axis=1)])
|
||||
# raise ValueError("There are nan values in the load forecast data.")
|
||||
|
||||
df.sort_values(by="datetime", inplace=True)
|
||||
return df
|
||||
|
||||
def set_batch_size(self, batch_size: int):
|
||||
self.batch_size = batch_size
|
||||
|
||||
@@ -56,7 +83,7 @@ class DataProcessor:
|
||||
return torch.utils.data.DataLoader(dataset, batch_size=self.batch_size, shuffle=shuffle, num_workers=4)
|
||||
|
||||
def get_train_dataloader(self, transform: bool = True, predict_sequence_length: int = 96):
|
||||
train_df = self.nrv_df.copy()
|
||||
train_df = self.all_features.copy()
|
||||
|
||||
if self.train_range[0] != -np.inf:
|
||||
train_df = train_df[(train_df['datetime'] >= self.train_range[0])]
|
||||
@@ -66,13 +93,14 @@ class DataProcessor:
|
||||
|
||||
if transform:
|
||||
train_df['nrv'] = self.nrv_scaler.fit_transform(train_df['nrv'].values.reshape(-1, 1)).reshape(-1)
|
||||
train_df['load_forecast'] = self.load_forecast_scaler.fit_transform(train_df['load_forecast'].values.reshape(-1, 1)).reshape(-1)
|
||||
|
||||
train_dataset = NrvDataset(train_df, predict_sequence_length=predict_sequence_length)
|
||||
train_dataset = NrvDataset(train_df, data_config=self.data_config, predict_sequence_length=predict_sequence_length)
|
||||
return self.get_dataloader(train_dataset)
|
||||
|
||||
def get_test_dataloader(self, transform: bool = True, predict_sequence_length: int = 96):
|
||||
|
||||
test_df = self.nrv_df.copy()
|
||||
test_df = self.all_features.copy()
|
||||
|
||||
if self.test_range[0] != -np.inf:
|
||||
test_df = test_df[(test_df['datetime'] >= self.test_range[0])]
|
||||
@@ -82,35 +110,14 @@ class DataProcessor:
|
||||
|
||||
if transform:
|
||||
test_df['nrv'] = self.nrv_scaler.transform(test_df['nrv'].values.reshape(-1, 1)).reshape(-1)
|
||||
test_dataset = NrvDataset(test_df, predict_sequence_length=predict_sequence_length)
|
||||
test_df['load_forecast'] = self.load_forecast_scaler.transform(test_df['load_forecast'].values.reshape(-1, 1)).reshape(-1)
|
||||
|
||||
test_dataset = NrvDataset(test_df, data_config=self.data_config, predict_sequence_length=predict_sequence_length)
|
||||
return self.get_dataloader(test_dataset, shuffle=False)
|
||||
|
||||
|
||||
def get_dataloaders(self, transform: bool = True, predict_sequence_length: int = 96):
|
||||
return self.get_train_dataloader(transform=transform, predict_sequence_length=predict_sequence_length), self.get_test_dataloader(transform=transform, predict_sequence_length=predict_sequence_length)
|
||||
|
||||
def get_random_day(self, train: bool = True, transform: bool = True):
|
||||
df = self.nrv_df.copy()
|
||||
|
||||
range = self.train_range if train else self.test_range
|
||||
|
||||
if range[0] != -np.inf:
|
||||
df = df[(df['datetime'] >= range[0])]
|
||||
|
||||
if range[1] != np.inf:
|
||||
df = df[(df['datetime'] <= range[1])]
|
||||
|
||||
if transform:
|
||||
df['nrv'] = self.nrv_scaler.transform(df['nrv'].values.reshape(-1, 1)).reshape(-1)
|
||||
|
||||
data_tensor = torch.tensor(df[self.features].values, dtype=torch.float32)
|
||||
|
||||
random_start_idx = np.random.randint(0, len(df) - 191)
|
||||
|
||||
current_day_features = data_tensor[random_start_idx:random_start_idx+96]
|
||||
next_day_features = data_tensor[random_start_idx+96:random_start_idx+192]
|
||||
|
||||
return (current_day_features, next_day_features)
|
||||
|
||||
def inverse_transform(self, tensor: torch.Tensor):
|
||||
return self.nrv_scaler.inverse_transform(tensor.cpu().numpy()).reshape(-1)
|
||||
@@ -1,7 +1,7 @@
|
||||
import torch
|
||||
|
||||
class NonLinearRegression(torch.nn.Module):
|
||||
def __init__(self, inputSize, output_size, hiddenSize=128, numLayers=2):
|
||||
def __init__(self, inputSize, output_size, hiddenSize=128, numLayers=2, dropout=0.0):
|
||||
super(NonLinearRegression, self).__init__()
|
||||
self.inputSize = inputSize
|
||||
self.output_size = output_size
|
||||
@@ -9,11 +9,15 @@ class NonLinearRegression(torch.nn.Module):
|
||||
self.hiddenSize = hiddenSize
|
||||
self.numLayers = numLayers
|
||||
|
||||
self.dropout = dropout
|
||||
|
||||
# add linear layers with relu
|
||||
self.layers = torch.nn.ModuleList()
|
||||
self.layers.append(torch.nn.Linear(inputSize, hiddenSize))
|
||||
self.layers.append(torch.nn.Dropout(dropout))
|
||||
for _ in range(numLayers - 2):
|
||||
self.layers.append(torch.nn.Linear(hiddenSize, hiddenSize))
|
||||
self.layers.append(torch.nn.Dropout(dropout))
|
||||
self.layers.append(torch.nn.Linear(hiddenSize, output_size))
|
||||
|
||||
self.relu = torch.nn.ReLU()
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"source": [
|
||||
"import sys\n",
|
||||
"sys.path.append('..')\n",
|
||||
"from data import DataProcessor\n",
|
||||
"from data import DataProcessor, DataConfig\n",
|
||||
"from trainers.quantile_trainer import QuantileTrainer\n",
|
||||
"from trainers.autoregressive_trainer import AutoRegressiveTrainer\n",
|
||||
"from trainers.trainer import Trainer\n",
|
||||
@@ -50,35 +50,40 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"ClearML Task: created new task id=909da25a8d214f75ab3858506ae615e8\n",
|
||||
"2023-11-07 16:29:35,665 - clearml.Task - INFO - Storing jupyter notebook directly as code\n",
|
||||
"ClearML results page: http://192.168.1.182:8080/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/909da25a8d214f75ab3858506ae615e8/output/log\n",
|
||||
"2023-11-07 16:30:08,121 - clearml.model - WARNING - 500 model found when searching for `file:///workspaces/Thesis/src/notebooks/checkpoint.pt`\n",
|
||||
"2023-11-07 16:30:08,123 - clearml.model - WARNING - Selected model `Quantile Regression - Linear` (id=bc0cb0d7fc614e2e8b0edf5b85348646)\n",
|
||||
"2023-11-07 16:30:08,130 - clearml.frameworks - INFO - Found existing registered model id=bc0cb0d7fc614e2e8b0edf5b85348646 [/workspaces/Thesis/src/notebooks/checkpoint.pt] reusing it.\n",
|
||||
"2023-11-07 16:30:08,677 - clearml.Task - INFO - Completed model upload to http://192.168.1.182:8081/Thesis/NrvForecast/Non-AutoRegressive%20-%20Non%20Linear%20%283%20hidden%20layers%20-%201024%20units%29.909da25a8d214f75ab3858506ae615e8/models/checkpoint.pt\n",
|
||||
"2023-11-07 16:30:10,302 - clearml.Task - INFO - Completed model upload to http://192.168.1.182:8081/Thesis/NrvForecast/Non-AutoRegressive%20-%20Non%20Linear%20%283%20hidden%20layers%20-%201024%20units%29.909da25a8d214f75ab3858506ae615e8/models/checkpoint.pt\n",
|
||||
"ClearML Task: created new task id=ae9d93e6bf3f4d228832378707574777\n",
|
||||
"ClearML results page: http://192.168.1.182:8080/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/ae9d93e6bf3f4d228832378707574777/output/log\n",
|
||||
"2023-11-08 21:46:32,338 - clearml.Task - INFO - Storing jupyter notebook directly as code\n",
|
||||
"2023-11-08 21:46:32,342 - clearml.Repository Detection - WARNING - Can't get url information for git repo in /workspaces/Thesis/src/notebooks\n",
|
||||
"2023-11-08 21:46:35,244 - clearml.model - WARNING - 500 model found when searching for `file:///workspaces/Thesis/src/notebooks/checkpoint.pt`\n",
|
||||
"2023-11-08 21:46:35,245 - clearml.model - WARNING - Selected model `Untitled Task` (id=bc0cb0d7fc614e2e8b0edf5b85348646)\n",
|
||||
"2023-11-08 21:46:35,254 - clearml.frameworks - INFO - Found existing registered model id=bc0cb0d7fc614e2e8b0edf5b85348646 [/workspaces/Thesis/src/notebooks/checkpoint.pt] reusing it.\n",
|
||||
"2023-11-08 21:46:35,748 - clearml.Task - INFO - Completed model upload to http://192.168.1.182:8081/Thesis/NrvForecast/Untitled%20Task.ae9d93e6bf3f4d228832378707574777/models/checkpoint.pt\n",
|
||||
"2023-11-08 21:46:37,673 - clearml.Task - INFO - Completed model upload to http://192.168.1.182:8081/Thesis/NrvForecast/Untitled%20Task.ae9d93e6bf3f4d228832378707574777/models/checkpoint.pt\n",
|
||||
"2023-11-08 21:46:41,215 - clearml.Task - INFO - Completed model upload to http://192.168.1.182:8081/Thesis/NrvForecast/Untitled%20Task.ae9d93e6bf3f4d228832378707574777/models/checkpoint.pt\n",
|
||||
"2023-11-08 21:46:43,004 - clearml.Task - INFO - Completed model upload to http://192.168.1.182:8081/Thesis/NrvForecast/Untitled%20Task.ae9d93e6bf3f4d228832378707574777/models/checkpoint.pt\n",
|
||||
"2023-11-08 21:46:44,745 - clearml.Task - INFO - Completed model upload to http://192.168.1.182:8081/Thesis/NrvForecast/Untitled%20Task.ae9d93e6bf3f4d228832378707574777/models/checkpoint.pt\n",
|
||||
"Early stopping triggered\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"#### Hyperparameters ####\n",
|
||||
"inputDim = 96\n",
|
||||
"inputDim = 96 + 96\n",
|
||||
"learningRate = 0.0003\n",
|
||||
"epochs = 50\n",
|
||||
"epochs = 150\n",
|
||||
"\n",
|
||||
"# model = LinearRegression(inputDim, 96)\n",
|
||||
"model = NonLinearRegression(inputDim, 96, hiddenSize=1024, numLayers=5)\n",
|
||||
"optimizer = torch.optim.Adam(model.parameters(), lr=learningRate)\n",
|
||||
"\n",
|
||||
"#### Data Processor ####\n",
|
||||
"data_processor = DataProcessor()\n",
|
||||
"data_config = DataConfig()\n",
|
||||
"data_processor = DataProcessor(data_config)\n",
|
||||
"data_processor.set_batch_size(1024)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"data_processor.set_train_range((datetime(year=2015, month=1, day=1, tzinfo=pytz.UTC), datetime(year=2022, month=11, day=30, tzinfo=pytz.UTC)))\n",
|
||||
"data_processor.set_test_range((datetime(year=2023, month=1, day=1, tzinfo=pytz.UTC), np.inf))\n",
|
||||
"data_processor.set_test_range((datetime(year=2023, month=1, day=1, tzinfo=pytz.UTC), datetime(year=2023, month=6, day=20, tzinfo=pytz.UTC)))\n",
|
||||
"\n",
|
||||
"#### ClearML ####\n",
|
||||
"clearml_helper = ClearMLHelper(project_name=\"Thesis/NrvForecast\")\n",
|
||||
@@ -87,7 +92,7 @@
|
||||
"trainer = Trainer(model, optimizer, nn.MSELoss(), data_processor, \"cuda\", debug=False, clearml_helper=clearml_helper)\n",
|
||||
"trainer.add_metrics_to_track([MSELoss(), L1Loss()])\n",
|
||||
"trainer.plot_every(10)\n",
|
||||
"trainer.early_stopping(patience=10)\n",
|
||||
"trainer.early_stopping(patience=40)\n",
|
||||
"trainer.train(epochs=epochs)"
|
||||
]
|
||||
},
|
||||
@@ -100,15 +105,30 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"InsecureRequestWarning: Certificate verification is disabled! Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"ClearML Task: created new task id=6467cef37fdc408d95b89f0dca0e26dd\n",
|
||||
"ClearML results page: http://192.168.1.182:8080/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/6467cef37fdc408d95b89f0dca0e26dd/output/log\n",
|
||||
"ClearML Task: created new task id=e4983af7aad748e8ae71e5fa46767d60\n",
|
||||
"ClearML results page: http://192.168.1.182:8080/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/e4983af7aad748e8ae71e5fa46767d60/output/log\n",
|
||||
"2023-11-08 22:51:38,769 - clearml.Task - INFO - Storing jupyter notebook directly as code\n",
|
||||
"2023-11-08 22:51:38,773 - clearml.Repository Detection - WARNING - Can't get url information for git repo in /workspaces/Thesis/src/notebooks\n",
|
||||
"2023-11-08 22:51:41,704 - clearml.model - WARNING - 500 model found when searching for `file:///workspaces/Thesis/src/notebooks/checkpoint.pt`\n",
|
||||
"2023-11-08 22:51:41,705 - clearml.model - WARNING - Selected model `Untitled Task` (id=bc0cb0d7fc614e2e8b0edf5b85348646)\n",
|
||||
"2023-11-08 22:51:41,713 - clearml.frameworks - INFO - Found existing registered model id=bc0cb0d7fc614e2e8b0edf5b85348646 [/workspaces/Thesis/src/notebooks/checkpoint.pt] reusing it.\n",
|
||||
"2023-11-08 22:51:42,239 - clearml.Task - INFO - Completed model upload to http://192.168.1.182:8081/Thesis/NrvForecast/Untitled%20Task.e4983af7aad748e8ae71e5fa46767d60/models/checkpoint.pt\n",
|
||||
"2023-11-08 22:51:43,980 - clearml.Task - INFO - Completed model upload to http://192.168.1.182:8081/Thesis/NrvForecast/Untitled%20Task.e4983af7aad748e8ae71e5fa46767d60/models/checkpoint.pt\n",
|
||||
"2023-11-08 22:51:45,684 - clearml.Task - INFO - Completed model upload to http://192.168.1.182:8081/Thesis/NrvForecast/Untitled%20Task.e4983af7aad748e8ae71e5fa46767d60/models/checkpoint.pt\n",
|
||||
"Early stopping triggered\n"
|
||||
]
|
||||
}
|
||||
@@ -124,7 +144,9 @@
|
||||
"optimizer = torch.optim.Adam(model.parameters(), lr=learningRate)\n",
|
||||
"\n",
|
||||
"#### Data Processor ####\n",
|
||||
"data_processor = DataProcessor()\n",
|
||||
"data_config = DataConfig()\n",
|
||||
"data_config.LOAD_FORECAST = False\n",
|
||||
"data_processor = DataProcessor(data_config)\n",
|
||||
"data_processor.set_batch_size(1024)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -151,26 +173,18 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/workspaces/Thesis/src/notebooks/../trainers/quantile_trainer.py:16: UserWarning:\n",
|
||||
"\n",
|
||||
"To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"ClearML Task: created new task id=07a2dc72793446d8a8101eafce0d80db\n",
|
||||
"ClearML results page: http://192.168.1.182:8080/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/07a2dc72793446d8a8101eafce0d80db/output/log\n",
|
||||
"Early stopping triggered\n"
|
||||
"ename": "TypeError",
|
||||
"evalue": "DataProcessor.__init__() missing 1 required positional argument: 'data_config'",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
|
||||
"\u001b[1;32m/workspaces/Thesis/src/notebooks/training.ipynb Cell 7\u001b[0m line \u001b[0;36m1\n\u001b[1;32m <a href='vscode-notebook-cell://dev-container%2B7b22686f737450617468223a222f686f6d652f766963746f726d796c6c652f53656144726976652f4d79204c69627261726965732f4750552d7365727665722f546865736973222c226c6f63616c446f636b6572223a66616c73652c22636f6e66696746696c65223a7b22246d6964223a312c2270617468223a222f686f6d652f766963746f726d796c6c652f53656144726976652f4d79204c69627261726965732f4750552d7365727665722f5468657369732f2e646576636f6e7461696e65722f646576636f6e7461696e65722e6a736f6e222c22736368656d65223a227673636f64652d66696c65486f7374227d7d@ssh-remote%2Bvictormylle.be/workspaces/Thesis/src/notebooks/training.ipynb#X10sdnNjb2RlLXJlbW90ZQ%3D%3D?line=13'>14</a>\u001b[0m data_config \u001b[39m=\u001b[39m DataConfig()\n\u001b[1;32m <a href='vscode-notebook-cell://dev-container%2B7b22686f737450617468223a222f686f6d652f766963746f726d796c6c652f53656144726976652f4d79204c69627261726965732f4750552d7365727665722f546865736973222c226c6f63616c446f636b6572223a66616c73652c22636f6e66696746696c65223a7b22246d6964223a312c2270617468223a222f686f6d652f766963746f726d796c6c652f53656144726976652f4d79204c69627261726965732f4750552d7365727665722f5468657369732f2e646576636f6e7461696e65722f646576636f6e7461696e65722e6a736f6e222c22736368656d65223a227673636f64652d66696c65486f7374227d7d@ssh-remote%2Bvictormylle.be/workspaces/Thesis/src/notebooks/training.ipynb#X10sdnNjb2RlLXJlbW90ZQ%3D%3D?line=14'>15</a>\u001b[0m data_config\u001b[39m.\u001b[39mLOAD_FORECAST \u001b[39m=\u001b[39m \u001b[39mFalse\u001b[39;00m\n\u001b[0;32m---> <a href='vscode-notebook-cell://dev-container%2B7b22686f737450617468223a222f686f6d652f766963746f726d796c6c652f53656144726976652f4d79204c69627261726965732f4750552d7365727665722f546865736973222c226c6f63616c446f636b6572223a66616c73652c22636f6e66696746696c65223a7b22246d6964223a312c2270617468223a222f686f6d652f766963746f726d796c6c652f53656144726976652f4d79204c69627261726965732f4750552d7365727665722f5468657369732f2e646576636f6e7461696e65722f646576636f6e7461696e65722e6a736f6e222c22736368656d65223a227673636f64652d66696c65486f7374227d7d@ssh-remote%2Bvictormylle.be/workspaces/Thesis/src/notebooks/training.ipynb#X10sdnNjb2RlLXJlbW90ZQ%3D%3D?line=15'>16</a>\u001b[0m data_processor \u001b[39m=\u001b[39m DataProcessor()\n\u001b[1;32m <a href='vscode-notebook-cell://dev-container%2B7b22686f737450617468223a222f686f6d652f766963746f726d796c6c652f53656144726976652f4d79204c69627261726965732f4750552d7365727665722f546865736973222c226c6f63616c446f636b6572223a66616c73652c22636f6e66696746696c65223a7b22246d6964223a312c2270617468223a222f686f6d652f766963746f726d796c6c652f53656144726976652f4d79204c69627261726965732f4750552d7365727665722f5468657369732f2e646576636f6e7461696e65722f646576636f6e7461696e65722e6a736f6e222c22736368656d65223a227673636f64652d66696c65486f7374227d7d@ssh-remote%2Bvictormylle.be/workspaces/Thesis/src/notebooks/training.ipynb#X10sdnNjb2RlLXJlbW90ZQ%3D%3D?line=16'>17</a>\u001b[0m data_processor\u001b[39m.\u001b[39mset_batch_size(\u001b[39m1024\u001b[39m)\n\u001b[1;32m <a href='vscode-notebook-cell://dev-container%2B7b22686f737450617468223a222f686f6d652f766963746f726d796c6c652f53656144726976652f4d79204c69627261726965732f4750552d7365727665722f546865736973222c226c6f63616c446f636b6572223a66616c73652c22636f6e66696746696c65223a7b22246d6964223a312c2270617468223a222f686f6d652f766963746f726d796c6c652f53656144726976652f4d79204c69627261726965732f4750552d7365727665722f5468657369732f2e646576636f6e7461696e65722f646576636f6e7461696e65722e6a736f6e222c22736368656d65223a227673636f64652d66696c65486f7374227d7d@ssh-remote%2Bvictormylle.be/workspaces/Thesis/src/notebooks/training.ipynb#X10sdnNjb2RlLXJlbW90ZQ%3D%3D?line=18'>19</a>\u001b[0m data_processor\u001b[39m.\u001b[39mset_train_range((\u001b[39m-\u001b[39mnp\u001b[39m.\u001b[39minf, datetime(year\u001b[39m=\u001b[39m\u001b[39m2022\u001b[39m, month\u001b[39m=\u001b[39m\u001b[39m11\u001b[39m, day\u001b[39m=\u001b[39m\u001b[39m30\u001b[39m, tzinfo\u001b[39m=\u001b[39mpytz\u001b[39m.\u001b[39mUTC)))\n",
|
||||
"\u001b[0;31mTypeError\u001b[0m: DataProcessor.__init__() missing 1 required positional argument: 'data_config'"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -178,17 +192,19 @@
|
||||
"#### Hyperparameters ####\n",
|
||||
"inputDim = 96\n",
|
||||
"learningRate = 0.0003\n",
|
||||
"epochs = 50\n",
|
||||
"epochs = 100\n",
|
||||
"\n",
|
||||
"quantiles = torch.tensor([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]).to(\"cuda\")\n",
|
||||
"\n",
|
||||
"# model = LinearRegression(inputDim, len(quantiles))\n",
|
||||
"model = NonLinearRegression(inputDim, len(quantiles), hiddenSize=1024, numLayers=5)\n",
|
||||
"model = NonLinearRegression(inputDim, len(quantiles), hiddenSize=1024, numLayers=5, dropout=0.2)\n",
|
||||
"model.output_size = 1\n",
|
||||
"optimizer = torch.optim.Adam(model.parameters(), lr=learningRate)\n",
|
||||
"\n",
|
||||
"#### Data Processor ####\n",
|
||||
"data_processor = DataProcessor()\n",
|
||||
"data_config = DataConfig()\n",
|
||||
"data_config.LOAD_FORECAST = False\n",
|
||||
"data_processor = DataProcessor(data_config)\n",
|
||||
"data_processor.set_batch_size(1024)\n",
|
||||
"\n",
|
||||
"data_processor.set_train_range((-np.inf, datetime(year=2022, month=11, day=30, tzinfo=pytz.UTC)))\n",
|
||||
@@ -204,6 +220,13 @@
|
||||
"trainer.plot_every(10)\n",
|
||||
"trainer.train(epochs=epochs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
@@ -10,19 +10,16 @@ from plotly.subplots import make_subplots
|
||||
from trainers.trainer import Trainer
|
||||
|
||||
class AutoRegressiveTrainer(Trainer):
|
||||
def debug_plots(self, task, train: bool, samples, epoch):
|
||||
X, y = samples
|
||||
X = X.to(self.device)
|
||||
|
||||
num_samples = len(X)
|
||||
def debug_plots(self, task, train: bool, data_loader, sample_indices, epoch):
|
||||
num_samples = len(sample_indices)
|
||||
rows = num_samples # One row per sample since we only want one column
|
||||
cols = 1
|
||||
|
||||
fig = make_subplots(rows=rows, cols=cols, subplot_titles=[f'Sample {i+1}' for i in range(num_samples)])
|
||||
|
||||
for i, (current_day, next_day) in enumerate(zip(X, y)):
|
||||
predictions = self.predict_auto_regressive(current_day)
|
||||
sub_fig = self.get_plot(current_day, next_day, predictions, show_legend=(i == 0))
|
||||
for i, idx in enumerate(sample_indices):
|
||||
initial, predictions, target = self.auto_regressive(data_loader, idx)
|
||||
sub_fig = self.get_plot(initial, target, predictions, show_legend=(i == 0))
|
||||
|
||||
row = i + 1
|
||||
col = 1
|
||||
@@ -30,7 +27,7 @@ class AutoRegressiveTrainer(Trainer):
|
||||
for trace in sub_fig.data:
|
||||
fig.add_trace(trace, row=row, col=col)
|
||||
|
||||
loss = self.criterion(predictions.to(self.device), next_day.to(self.device)).item()
|
||||
loss = self.criterion(predictions.to(self.device), target.to(self.device)).item()
|
||||
|
||||
fig['layout']['annotations'][i].update(text=f"{loss.__class__.__name__}: {loss:.6f}")
|
||||
|
||||
@@ -46,14 +43,38 @@ class AutoRegressiveTrainer(Trainer):
|
||||
figure=fig
|
||||
)
|
||||
|
||||
def auto_regressive(self, data_loader, idx, sequence_length: int = 96):
|
||||
self.model.eval()
|
||||
target_full = []
|
||||
predictions_full = []
|
||||
|
||||
def predict_auto_regressive(self, initial_sequence: torch.Tensor, sequence_length: int = 96):
|
||||
initial_sequence = initial_sequence.to(self.device)
|
||||
prev_features, target = data_loader.dataset[idx]
|
||||
prev_features = prev_features.to(self.device)
|
||||
|
||||
return predict_auto_regressive(self.model, initial_sequence, sequence_length)
|
||||
initial_sequence = prev_features[:96]
|
||||
|
||||
def random_day_prediction(self):
|
||||
current_day_features, next_day_features = self.data_processor.get_random_test_day()
|
||||
target_full.append(target)
|
||||
with torch.no_grad():
|
||||
prediction = self.model(prev_features.unsqueeze(0))
|
||||
predictions_full.append(prediction.squeeze(-1))
|
||||
|
||||
predictions = self.predict_auto_regressive(current_day_features)
|
||||
return current_day_features, next_day_features, predictions
|
||||
for i in range(sequence_length - 1):
|
||||
new_features = torch.cat((prev_features[1:97].cpu(), prediction.squeeze(-1).cpu()), dim=0)
|
||||
|
||||
# get the other needed features
|
||||
other_features, new_target = data_loader.dataset.random_day_autoregressive(idx + i + 1)
|
||||
|
||||
if other_features is not None:
|
||||
prev_features = torch.cat((new_features, other_features), dim=0)
|
||||
else:
|
||||
prev_features = new_features
|
||||
|
||||
# add target to target_full
|
||||
target_full.append(new_target)
|
||||
|
||||
# predict
|
||||
with torch.no_grad():
|
||||
prediction = self.model(new_features.unsqueeze(0).to(self.device))
|
||||
predictions_full.append(prediction.squeeze(-1))
|
||||
|
||||
return initial_sequence.cpu(), torch.stack(predictions_full).cpu(), torch.stack(target_full).cpu()
|
||||
@@ -20,10 +20,6 @@ class QuantileTrainer(AutoRegressiveTrainer):
|
||||
criterion = PinballLoss(quantiles=quantiles_tensor)
|
||||
super().__init__(model=model, optimizer=optimizer, criterion=criterion, data_processor=data_processor, device=device, clearml_helper=clearml_helper, debug=debug)
|
||||
|
||||
def predict_auto_regressive(self, initial_sequence: torch.Tensor, sequence_length: int = 96):
|
||||
initial_sequence = initial_sequence.to(self.device)
|
||||
|
||||
return predict_auto_regressive_quantile(self.model, self.sample_from_dist, initial_sequence, self.quantiles, sequence_length)
|
||||
|
||||
def log_final_metrics(self, task, dataloader, train: bool = True):
|
||||
metrics = { metric.__class__.__name__: 0.0 for metric in self.metrics_to_track }
|
||||
@@ -84,6 +80,52 @@ class QuantileTrainer(AutoRegressiveTrainer):
|
||||
fig.update_layout(title="Predictions and Quantiles of the Linear Model", showlegend=show_legend)
|
||||
|
||||
return fig
|
||||
|
||||
def auto_regressive(self, data_loader, idx, sequence_length: int = 96):
|
||||
self.model.eval()
|
||||
target_full = []
|
||||
predictions_sampled = []
|
||||
predictions_full = []
|
||||
|
||||
prev_features, target = data_loader.dataset[idx]
|
||||
prev_features = prev_features.to(self.device)
|
||||
|
||||
initial_sequence = prev_features[:96]
|
||||
|
||||
target_full.append(target)
|
||||
with torch.no_grad():
|
||||
prediction = self.model(prev_features.unsqueeze(0))
|
||||
predictions_full.append(prediction.squeeze(0))
|
||||
|
||||
# sample from the distribution
|
||||
sample = self.sample_from_dist(self.quantiles.cpu(), prediction.squeeze(-1).cpu().numpy())
|
||||
predictions_sampled.append(sample)
|
||||
|
||||
for i in range(sequence_length - 1):
|
||||
new_features = torch.cat((prev_features[1:97].cpu(), torch.tensor([predictions_sampled[-1]])), dim=0)
|
||||
new_features = new_features.float()
|
||||
|
||||
# get the other needed features
|
||||
other_features, new_target = data_loader.dataset.random_day_autoregressive(idx + i + 1)
|
||||
|
||||
if other_features is not None:
|
||||
prev_features = torch.cat((new_features, other_features), dim=0)
|
||||
else:
|
||||
prev_features = new_features
|
||||
|
||||
# add target to target_full
|
||||
target_full.append(new_target)
|
||||
|
||||
# predict
|
||||
with torch.no_grad():
|
||||
prediction = self.model(new_features.unsqueeze(0).to(self.device))
|
||||
predictions_full.append(prediction.squeeze(0))
|
||||
|
||||
# sample from the distribution
|
||||
sample = self.sample_from_dist(self.quantiles.cpu(), prediction.squeeze(-1).cpu().numpy())
|
||||
predictions_sampled.append(sample)
|
||||
|
||||
return initial_sequence.cpu(), torch.stack(predictions_full).cpu(), torch.stack(target_full).cpu()
|
||||
|
||||
@staticmethod
|
||||
def sample_from_dist(quantiles, output_values):
|
||||
|
||||
@@ -70,23 +70,22 @@ class Trainer:
|
||||
return task
|
||||
|
||||
def random_samples(self, train: bool = True, num_samples: int = 10):
|
||||
random_X = []
|
||||
random_Y = []
|
||||
train_loader, test_loader = self.data_processor.get_dataloaders(predict_sequence_length=self.model.output_size)
|
||||
|
||||
for _ in range(num_samples):
|
||||
X, y = self.data_processor.get_random_day(train=train)
|
||||
random_X.append(X)
|
||||
random_Y.append(y)
|
||||
if train:
|
||||
loader = train_loader
|
||||
else:
|
||||
loader = test_loader
|
||||
|
||||
indices = np.random.randint(0, len(loader.dataset) - 1, size=num_samples)
|
||||
return indices
|
||||
|
||||
random_X = torch.stack(random_X)
|
||||
random_Y = torch.stack(random_Y)
|
||||
return random_X, random_Y
|
||||
|
||||
def train(self, epochs: int):
|
||||
train_loader, test_loader = self.data_processor.get_dataloaders(predict_sequence_length=self.model.output_size)
|
||||
|
||||
train_random_X, train_random_y = self.random_samples(train=True)
|
||||
test_random_X, test_random_y = self.random_samples(train=False)
|
||||
train_samples = self.random_samples(train=True)
|
||||
test_samples = self.random_samples(train=False)
|
||||
|
||||
task = self.init_clearml_task()
|
||||
|
||||
@@ -129,8 +128,8 @@ class Trainer:
|
||||
|
||||
|
||||
if epoch % self.plot_every_n_epochs == 0:
|
||||
self.debug_plots(task, True, (train_random_X, train_random_y), epoch)
|
||||
self.debug_plots(task, False, (test_random_X, test_random_y), epoch)
|
||||
self.debug_plots(task, True, train_loader, train_samples, epoch)
|
||||
self.debug_plots(task, False, test_loader, test_samples, epoch)
|
||||
|
||||
if task:
|
||||
self.finish_training(task=task)
|
||||
@@ -144,6 +143,7 @@ class Trainer:
|
||||
with torch.no_grad():
|
||||
for inputs, targets in dataloader:
|
||||
inputs, targets = inputs.to(self.device), targets
|
||||
|
||||
outputs = self.model(inputs)
|
||||
|
||||
inversed_outputs = torch.tensor(self.data_processor.inverse_transform(outputs))
|
||||
@@ -215,22 +215,25 @@ class Trainer:
|
||||
return fig
|
||||
|
||||
|
||||
def debug_plots(self, task, train: bool, samples, epoch):
|
||||
X, y = samples
|
||||
X = X.to(self.device)
|
||||
|
||||
num_samples = len(X)
|
||||
def debug_plots(self, task, train: bool, data_loader, sample_indices, epoch):
|
||||
num_samples = len(sample_indices)
|
||||
rows = num_samples # One row per sample since we only want one column
|
||||
cols = 1
|
||||
|
||||
fig = make_subplots(rows=rows, cols=cols, subplot_titles=[f'Sample {i+1}' for i in range(num_samples)])
|
||||
|
||||
for i, (current_day, next_day) in enumerate(zip(X, y)):
|
||||
for i, idx in enumerate(sample_indices):
|
||||
|
||||
features, target = data_loader.dataset[idx]
|
||||
|
||||
features = features.to(self.device)
|
||||
target = target.to(self.device)
|
||||
|
||||
self.model.eval()
|
||||
with torch.no_grad():
|
||||
predictions = self.model(current_day).cpu()
|
||||
predictions = self.model(features).cpu()
|
||||
|
||||
sub_fig = self.get_plot(current_day, next_day, predictions, show_legend=(i == 0))
|
||||
sub_fig = self.get_plot(features[:96], target, predictions, show_legend=(i == 0))
|
||||
|
||||
row = i + 1
|
||||
col = 1
|
||||
@@ -239,7 +242,7 @@ class Trainer:
|
||||
fig.add_trace(trace, row=row, col=col)
|
||||
|
||||
|
||||
loss = self.criterion(predictions.to(self.device), next_day.squeeze(-1).to(self.device)).item()
|
||||
loss = self.criterion(predictions.to(self.device), target.squeeze(-1).to(self.device)).item()
|
||||
|
||||
fig['layout']['annotations'][i].update(text=f"{loss.__class__.__name__}: {loss:.6f}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user