diff --git a/.gitignore b/.gitignore index 80a4923..6fd27e0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /data/ /old_notebooks/ +/lightning_logs/ # Created by https://www.gitignore.io/api/code,linux,macos,python,windows,jupyternotebook,jupyternotebooks # Edit at https://www.gitignore.io/?templates=code,linux,macos,python,windows,jupyternotebook,jupyternotebooks diff --git a/requirements.txt b/requirements.txt index 1cda392..af1cd48 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ tqdm pandas numpy torchsummaryX +pytorch_lightning diff --git a/smartmeters-attention.ipynb b/smartmeters-deterministic.ipynb similarity index 100% rename from smartmeters-attention.ipynb rename to smartmeters-deterministic.ipynb diff --git a/smartmeters-lightning.ipynb b/smartmeters-lightning.ipynb new file mode 100644 index 0000000..3086fe7 --- /dev/null +++ b/smartmeters-lightning.ipynb @@ -0,0 +1,683 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:39:06.619783Z", + "start_time": "2020-01-25T06:39:05.021382Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Populating the interactive namespace from numpy and matplotlib\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/wassname/.pyenv/versions/jup3.7.3/lib/python3.7/site-packages/IPython/core/magics/pylab.py:160: UserWarning: pylab import has clobbered these variables: ['plt']\n", + "`%matplotlib` prevents importing * from pylab and numpy\n", + " \"\\n`%matplotlib` prevents importing * from pylab and numpy\"\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib as plt\n", + "import collections\n", + "from pathlib import Path\n", + "from tqdm.auto import tqdm\n", + "import pytorch_lightning as pl\n", + "\n", + "import math\n", + "%pylab inline\n", + "%reload_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:39:06.657721Z", + "start_time": "2020-01-25T06:39:06.622708Z" + } + }, + "outputs": [], + "source": [ + "import logging\n", + "logging.basicConfig(stream=sys.stdout, level=logging.INFO)\n", + "logger = logging.getLogger(\"smartmeters.ipynb\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:39:06.694010Z", + "start_time": "2020-01-25T06:39:06.660812Z" + } + }, + "outputs": [], + "source": [ + "import torch\n", + "from torch import nn\n", + "import torch.nn.functional as F" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:39:06.735223Z", + "start_time": "2020-01-25T06:39:06.696932Z" + } + }, + "outputs": [], + "source": [ + "from src.models.model import LatentModel\n", + "from src.data.smart_meter import collate_fns, SmartMeterDataSet" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:39:06.791657Z", + "start_time": "2020-01-25T06:39:06.739340Z" + } + }, + "outputs": [], + "source": [ + "# Params\n", + "device='cuda'\n", + "use_logy=False" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Load kaggle smart meter data" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:39:06.858920Z", + "start_time": "2020-01-25T06:39:06.794823Z" + } + }, + "outputs": [], + "source": [ + "def get_data_df(indir=Path('./data/smart-meters-in-london')):\n", + " csv_files = sorted(Path('data/smart-meters-in-london/halfhourly_dataset').glob('*.csv'))[:1]\n", + " df = pd.concat([pd.read_csv(f, parse_dates=[1], na_values=['Null']) for f in csv_files])\n", + "# print(df.info())\n", + "\n", + " df = df.groupby('tstp').mean()\n", + " df['tstp'] = df.index\n", + " df.index.name = ''\n", + "\n", + " # Load weather data\n", + " df_weather = pd.read_csv(indir/'weather_hourly_darksky.csv', parse_dates=[3])\n", + "\n", + " use_cols = ['visibility', 'windBearing', 'temperature', 'time', 'dewPoint',\n", + " 'pressure', 'apparentTemperature', 'windSpeed', \n", + " 'humidity']\n", + " df_weather = df_weather[use_cols].set_index('time')\n", + "\n", + " # Resample to match energy data \n", + " df_weather = df_weather.resample('30T').ffill()\n", + "\n", + " # Normalise\n", + " weather_norms=dict(mean={'visibility': 11.2,\n", + " 'windBearing': 195.7,\n", + " 'temperature': 10.5,\n", + " 'dewPoint': 6.5,\n", + " 'pressure': 1014.1,\n", + " 'apparentTemperature': 9.2,\n", + " 'windSpeed': 3.9,\n", + " 'humidity': 0.8},\n", + " std={'visibility': 3.1,\n", + " 'windBearing': 90.6,\n", + " 'temperature': 5.8,\n", + " 'dewPoint': 5.0,\n", + " 'pressure': 11.4,\n", + " 'apparentTemperature': 6.9,\n", + " 'windSpeed': 2.0,\n", + " 'humidity': 0.1})\n", + "\n", + " for col in df_weather.columns:\n", + " df_weather[col] -= weather_norms['mean'][col]\n", + " df_weather[col] /= weather_norms['std'][col]\n", + "\n", + " df = pd.concat([df, df_weather], 1).dropna()\n", + " \n", + " \n", + " # Also find bank holidays\n", + " df_hols = pd.read_csv(indir/'uk_bank_holidays.csv', parse_dates=[0])\n", + " holidays = set(df_hols['Bank holidays'].dt.round('D'))\n", + "\n", + " df['holiday'] = df.tstp.apply(lambda dt:dt.floor('D') in holidays).astype(int)\n", + "\n", + " # Add time features\n", + " time = df.tstp\n", + " df[\"month\"] = time.dt.month / 12.0\n", + " df['day'] = time.dt.day / 310.0\n", + " df['week'] = time.dt.week / 52.0\n", + " df['hour'] = time.dt.hour / 24.0\n", + " df['minute'] = time.dt.minute / 24.0\n", + " df['dayofweek'] = time.dt.dayofweek / 7.0\n", + "\n", + " # Drop nan and 0's\n", + " df = df[df['energy(kWh/hh)']!=0]\n", + " df = df.dropna()\n", + "\n", + " if use_logy:\n", + " df['energy(kWh/hh)'] = np.log(df['energy(kWh/hh)']+eps)\n", + " df = df.sort_values('tstp')\n", + " \n", + " # split data\n", + " n_split = -int(len(df)*0.1)\n", + " df_train = df[:n_split]\n", + " df_test = df[n_split:]\n", + " return df_train, df_test" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T05:26:47.145623Z", + "start_time": "2020-01-25T05:26:39.607967Z" + }, + "scrolled": false + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T05:26:47.222482Z", + "start_time": "2020-01-25T05:26:47.148344Z" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:39:15.688916Z", + "start_time": "2020-01-25T06:39:06.861292Z" + } + }, + "outputs": [], + "source": [ + "df_train, df_test = get_data_df()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:39:16.304060Z", + "start_time": "2020-01-25T06:39:15.693906Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Show split\n", + "df_train['energy(kWh/hh)'].plot(label='train')\n", + "df_test['energy(kWh/hh)'].plot(label='test')\n", + "plt.title('energy(kWh/hh)')\n", + "plt.legend()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T05:07:36.234226Z", + "start_time": "2020-01-25T05:07:36.198552Z" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2019-11-02T05:35:58.304088Z", + "start_time": "2019-11-02T05:35:58.274458Z" + } + }, + "source": [ + "# Plot helpers" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:39:16.347881Z", + "start_time": "2020-01-25T06:39:16.306427Z" + } + }, + "outputs": [], + "source": [ + "def plot_rows(target_y_rows, context_y_rows, pred_y, std, undo_log=use_logy, legend=False):\n", + " \"\"\"Plots the predicted mean and variance and the context points.\n", + " \n", + " Args: \n", + " target_y_rows\n", + " context_y_rows: dataframe with datetime index, and labels\n", + " pred_y: An array of shape [B,num_targets,1] that contains the\n", + " predicted means of the y values at the target points in target_x.\n", + " std: An array of shape [B,num_targets,1] that contains the\n", + " predicted std dev of the y values at the target points in target_x.\n", + " \"\"\"\n", + " if undo_log:\n", + " target_y_rows=np.exp(target_y_rows)-eps\n", + " context_y_rows=np.exp(context_y_rows)-eps\n", + " \n", + " # Plot everything \n", + " j=0\n", + " label='energy(kWh/hh)'\n", + " \n", + " plt.plot(target_y_rows.index, pred_y[0], 'b', linewidth=2, label='predicted')\n", + " plt.fill_between(\n", + " target_y_rows.index,\n", + " pred_y[0, :, 0] - std[0, :, 0],\n", + " pred_y[0, :, 0] + std[0, :, 0],\n", + " alpha=0.25,\n", + " facecolor='blue',\n", + " interpolate=True,\n", + " label='uncertainty')\n", + " \n", + " target_y_rows[label].plot(style='k:', linewidth=2, label='true', ax=plt.gca())\n", + " context_y_rows[label].plot(style='ko', linewidth=2, label='input data', ax=plt.gca())\n", + "\n", + " # Make the plot pretty\n", + " plt.grid('off')\n", + "# plt.ylim(*ylims)\n", + " plt.xlabel('Date')\n", + " plt.ylabel('Energy (kWh/hh)')\n", + " plt.grid(b=None)\n", + " if legend:\n", + " plt.legend()\n", + " ax = plt.gca()\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:39:16.405034Z", + "start_time": "2020-01-25T06:39:16.350259Z" + } + }, + "outputs": [], + "source": [ + "def plot_from_loader(loader, model, i=0, undo_log=use_logy, title='', plot=True, legend=False):\n", + " data = loader.collate_fn([loader.dataset[i]], sample=False)\n", + " data = [d.to(device) for d in data]\n", + " context_x, context_y, target_x, target_y = data\n", + " \n", + " x_rows, y_rows = loader.dataset.get_rows(i)\n", + " max_num_context = context_x.shape[1]\n", + " y_context_rows = y_rows[:max_num_context]\n", + " dt = y_context_rows.index[0]\n", + "\n", + " model.eval()\n", + " with torch.no_grad():\n", + " y_pred, kl, loss_test, y_std = model(context_x, context_y, target_x, target_y)\n", + "\n", + " if plot:\n", + " plt.title(title+f\" loss={loss_test: 2.2g} {dt}\")\n", + " plot_rows(y_rows,\n", + " y_context_rows, \n", + " y_pred.detach().cpu().numpy(),\n", + " y_std.detach().cpu().numpy(), undo_log=False, legend=legend)\n", + " return loss_test" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Model" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:39:16.499797Z", + "start_time": "2020-01-25T06:39:16.408355Z" + } + }, + "outputs": [], + "source": [ + "\n", + "\n", + "class LatentModelPL(pl.LightningModule):\n", + "\n", + " def __init__(self, hparams):\n", + " super().__init__()\n", + " self.model = LatentModel(\n", + " **hparams.__dict__)\n", + " self.hparams = hparams\n", + "\n", + " def forward(self, context_x, context_y, target_x, target_y):\n", + " return self.model(context_x, context_y, target_x, target_y)\n", + "\n", + " def training_step(self, batch, batch_idx):\n", + " assert all(torch.isfinite(d).all() for d in batch)\n", + " context_x, context_y, target_x, target_y = batch\n", + " y_pred, kl, loss, y_std = self.forward(context_x, context_y, target_x, target_y)\n", + " tensorboard_logs = {'train_loss': loss, 'train_kl': kl.mean(), 'train/std': y_std.mean()}\n", + " return {'loss': loss, 'log': tensorboard_logs}\n", + "\n", + " def validation_step(self, batch, batch_idx):\n", + " if batch_idx==0:\n", + " plot_from_loader(self.val_dataloader()[0], self.model, i=self.hparams.vis_i) \n", + " assert all(torch.isfinite(d).all() for d in batch)\n", + " context_x, context_y, target_x, target_y = batch\n", + " y_pred, kl, loss, y_std = self.forward(context_x, context_y, target_x, target_y)\n", + " tensorboard_logs = {'train_loss': loss, 'train_kl': kl.mean(), 'train/std': y_std.mean()}\n", + " return {'val_loss': loss}\n", + "\n", + " def validation_end(self, outputs):\n", + " avg_loss = torch.stack([x['val_loss'] for x in outputs]).mean()\n", + " tensorboard_logs = {'val_loss': avg_loss}\n", + " return {'avg_val_loss': avg_loss, 'log': tensorboard_logs}\n", + "\n", + " def configure_optimizers(self):\n", + " optim = torch.optim.Adam(self.parameters(), lr=self.hparams.learning_rate)\n", + " scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optim)\n", + " return [optim], [scheduler]\n", + "\n", + " @pl.data_loader\n", + " def train_dataloader(self):\n", + " df_train, df_test = get_data_df()\n", + " data_train = SmartMeterDataSet(df_train, self.hparams.num_context, self.hparams.num_extra_target)\n", + " return torch.utils.data.DataLoader(data_train, batch_size=self.hparams.batch_size, shuffle=True, \n", + " collate_fn=collate_fns(self.hparams.num_context, self.hparams.num_extra_target, sample=True),\n", + " num_workers=self.hparams.num_workers,\n", + " )\n", + "\n", + " @pl.data_loader\n", + " def val_dataloader(self):\n", + "# df_train, df_test = get_data_df()\n", + " data_test = SmartMeterDataSet(df_test, self.hparams.num_context, self.hparams.num_extra_target)\n", + " return torch.utils.data.DataLoader(\n", + " data_test, batch_size=self.hparams.batch_size, shuffle=False, \n", + " collate_fn=collate_fns(self.hparams.num_context, self.hparams.num_extra_target, sample=False)\n", + " )\n", + "\n", + " @pl.data_loader\n", + " def test_dataloader(self):\n", + "# df_train, df_test = get_data_df()\n", + " data_test = SmartMeterDataSet(df_test, self.hparams.num_context, self.hparams.num_extra_target)\n", + " return torch.utils.data.DataLoader(\n", + " data_test, batch_size=self.hparams.batch_size, shuffle=False, \n", + " collate_fn=collate_fns(self.hparams.num_context, self.hparams.num_extra_target, sample=False)\n", + " )\n", + "\n", + " @staticmethod\n", + " def add_model_specific_args(parent_parser):\n", + " \"\"\"\n", + " Specify the hyperparams for this LightningModule\n", + " \"\"\"\n", + " # MODEL specific\n", + " parser = ArgumentParser(parents=[parent_parser])\n", + " parser.add_argument('--learning_rate', default=1e-4, type=float)\n", + " parser.add_argument('--batch_size', default=16, type=int)\n", + " \n", + " parser.add_argument('--x_dim', default=16, type=int)\n", + " parser.add_argument('--y_dim', default=1, type=int)\n", + " parser.add_argument('--vis_i', default=670, type=int)\n", + " \n", + " parser.add_argument('--hidden_dim', default=128, type=int)\n", + " parser.add_argument('--latent_dim', default=128, type=int)\n", + " parser.add_argument('--num_heads', default=8, type=int)\n", + " parser.add_argument('--n_latent_encoder_layers', default=4, type=int)\n", + " parser.add_argument('--n_det_encoder_layers', default=4, type=int)\n", + " parser.add_argument('--n_decoder_layers', default=2, type=int)\n", + " \n", + " parser.add_argument('--dropout', default=0, type=float)\n", + " parser.add_argument('--attention_dropout', default=0, type=float)\n", + " parser.add_argument('--min_std', default=0.01, type=float)\n", + " \n", + " parser.add_argument('--latent_enc_self_attn_type', default=\"multihead\", type=str)\n", + " parser.add_argument('--det_enc_self_attn_type', default=\"multihead\", type=str)\n", + " parser.add_argument('--det_enc_cross_attn_type', default=\"multihead\", type=str)\n", + " \n", + " parser.add_argument('--use_lvar', default=False, type=bool)\n", + " parser.add_argument('--use_deterministic_path', default=True, type=bool)\n", + "\n", + " # training specific (for this model)\n", + " parser.add_argument('--grad_clip', default=0, type=float) \n", + " parser.add_argument('--num_context', type=int, default=24*2)\n", + " parser.add_argument('--num_extra_target', type=int, default=24)\n", + " parser.add_argument('--max_nb_epochs', default=10, type=int)\n", + " parser.add_argument('--num_workers', default=4, type=int)\n", + " return parser" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:28:59.768716Z", + "start_time": "2020-01-25T06:28:59.722327Z" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:39:16.545085Z", + "start_time": "2020-01-25T06:39:16.502730Z" + } + }, + "outputs": [], + "source": [ + "# Set our params here, in a way compatible with cli\n", + "argv = f\"\"\"\n", + "--x_dim {df_train.shape[-1]-1} \\\n", + "--y_dim 1 \\\n", + "--max_nb_epochs 7 \\\n", + "--gpus 0 \\\n", + "\"\"\".replace('\\n','').strip().split(' ')" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "ExecuteTime": { + "end_time": "2020-01-25T06:39:16.591501Z", + "start_time": "2020-01-25T06:39:16.548042Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Namespace(attention_dropout=0, batch_size=32, det_enc_cross_attn_type='multihead', det_enc_self_attn_type='multihead', dropout=0, gpus='0', grad_clip=0, hidden_dim=128, latent_dim=128, latent_enc_self_attn_type='multihead', learning_rate=0.0001, max_nb_epochs=7, min_std=0.01, n_decoder_layers=2, n_det_encoder_layers=4, n_latent_encoder_layers=4, nodes=1, num_context=48, num_extra_target=24, num_heads=8, num_workers=4, use_deterministic_path=True, use_lvar=False, vis_i=670, x_dim=16, y_dim=1)\n" + ] + } + ], + "source": [ + "from pytorch_lightning import Trainer\n", + "from argparse import ArgumentParser \n", + "\n", + "parser = ArgumentParser(add_help=False)\n", + "parser.add_argument('--gpus', type=str, default=None)\n", + "parser.add_argument('--nodes', type=int, default=1)\n", + "\n", + "# give the module a chance to add own params\n", + "parser = LatentModelPL.add_model_specific_args(parser)\n", + "\n", + "# parse params\n", + "hparams = parser.parse_args(argv)\n", + "print(hparams)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Run" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "start_time": "2020-01-25T06:39:05.100Z" + }, + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:root:gpu available: True, used: True\n", + "INFO:root:VISIBLE GPUS: 0\n", + "/home/wassname/.pyenv/versions/jup3.7.3/lib/python3.7/site-packages/pytorch_lightning/logging/tensorboard.py:82: UserWarning: Hyperparameter logging is not available for Torch version 1.2.0. Skipping log_hyperparams. Upgrade to Torch 1.3.0 or above to enable hyperparameter logging.\n", + " f\"Hyperparameter logging is not available for Torch version {torch.__version__}.\"\n" + ] + } + ], + "source": [ + "model = LatentModelPL(hparams)\n", + "\n", + "# most basic trainer, uses good defaults\n", + "trainer = Trainer(\n", + " max_epochs=hparams.max_nb_epochs,\n", + " gpus=hparams.gpus,\n", + " nb_gpu_nodes=hparams.nodes,\n", + " gradient_clip_val=hparams.grad_clip,\n", + " track_grad_norm=1,\n", + " show_progress_bar=False\n", + ")\n", + "trainer.fit(model)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "file_extension": ".py", + "kernelspec": { + "display_name": "jup3.7.3", + "language": "python", + "name": "jup3.7.3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + }, + "mimetype": "text/x-python", + "name": "python", + "npconvert_exporter": "python", + "pygments_lexer": "ipython3", + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": false, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": true + }, + "version": 3 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/src/data/smart_meter.py b/src/data/smart_meter.py index dafa347..07c83fe 100644 --- a/src/data/smart_meter.py +++ b/src/data/smart_meter.py @@ -11,7 +11,7 @@ def npsample_batch(x, y, size=None, sort=True): return x[:, inds], y[:, inds] def collate_fns(max_num_context, max_num_extra_target, sample, sort=True): - def collate_fn(batch): + def collate_fn(batch, sample=sample): # Collate x = np.stack([x for x, y in batch], 0) y = np.stack([y for x, y in batch], 0) @@ -52,7 +52,7 @@ class SmartMeterDataSet(torch.utils.data.Dataset): self.num_extra_target = num_extra_target self.label_names = label_names - def __getitem__(self, i): + def get_rows(self, i): rows = self.df.iloc[i : i + (self.num_context + self.num_extra_target)].copy() rows['tstp'] = (rows['tstp'] - rows['tstp'].iloc[0]).dt.total_seconds() / 86400.0 rows = rows.sort_values('tstp') @@ -61,9 +61,14 @@ class SmartMeterDataSet(torch.utils.data.Dataset): columns = ['tstp'] + list(set(rows.columns) - set(['tstp'])) rows = rows[columns] - x = rows.drop(columns=self.label_names).values - y = rows[self.label_names].values + x = rows.drop(columns=self.label_names) + y = rows[self.label_names] return x, y + + + def __getitem__(self, i): + x,y = self.get_rows(i) + return x.values, y.values def __len__(self): return len(self.df) - (self.num_context + self.num_extra_target) diff --git a/src/models/model.py b/src/models/model.py index 43a0ed6..36aa5c2 100644 --- a/src/models/model.py +++ b/src/models/model.py @@ -52,7 +52,8 @@ class LatentModel(nn.Module): attention_dropout=0, min_std=0.1, use_lvar=False, - use_deterministic_path=True + use_deterministic_path=True, + **kwargs ): super().__init__()