Files
attentive-neural-processes/smartmeters-lstm-seq2seq.ipynb
T
2020-03-01 11:48:14 +08:00

777 lines
41 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# This notebook uses pytorch lightning & optuna & an LSTM\n",
"\n",
"This notebook trains an LSTM on timeseries data from smartmeters.\n",
"\n",
"It uses pytorch lighting for the training loop. And Optuna for the hyperparameter optimisation.\n",
"\n",
"It also pushes results to the tensorboard hyperparameter dashboard for examination.\n",
"\n",
"- https://github.com/optuna/optuna/blob/master/examples/pytorch_lightning_simple.py"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:41:29.841115Z",
"start_time": "2020-03-01T03:41:29.484738Z"
}
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"%reload_ext autoreload\n",
"%autoreload 2"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:41:31.805982Z",
"start_time": "2020-03-01T03:41:29.843485Z"
}
},
"outputs": [],
"source": [
"import sys, re, os, itertools, functools, collections\n",
"import pandas as pd\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import collections\n",
"from pathlib import Path\n",
"from tqdm.auto import tqdm\n",
"\n",
"import pytorch_lightning as pl\n",
"import optuna\n",
"from optuna.integration import PyTorchLightningPruningCallback\n",
"\n",
"\n",
"import math\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:41:31.857758Z",
"start_time": "2020-03-01T03:41:31.809871Z"
}
},
"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-03-01T03:41:31.973473Z",
"start_time": "2020-03-01T03:41:31.860963Z"
}
},
"outputs": [],
"source": [
"from src.models.model import LatentModel\n",
"from src.data.smart_meter import collate_fns, SmartMeterDataSet, get_smartmeter_df\n",
"from src.plot import plot_from_loader\n",
"from src.models.lstm_seqseq import LSTMSeq2Seq_PL\n",
"from src.dict_logger import DictLogger"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:41:32.025844Z",
"start_time": "2020-03-01T03:41:31.977741Z"
}
},
"outputs": [],
"source": [
"import logging\n",
"logging.basicConfig(stream=sys.stdout, level=logging.INFO)\n",
"logger = logging.getLogger(\"smartmeters.ipynb\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:41:32.075520Z",
"start_time": "2020-03-01T03:41:32.028741Z"
}
},
"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": 7,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:41:40.783929Z",
"start_time": "2020-03-01T03:41:32.077822Z"
}
},
"outputs": [],
"source": [
"df_train, df_test = get_smartmeter_df()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:41:41.497026Z",
"start_time": "2020-03-01T03:41:40.786905Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.legend.Legend at 0x7fb05e5d2668>"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"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-02-16T00:24:15.905017Z",
"start_time": "2020-02-16T00:24:15.747859Z"
}
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Train helpers"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:41:41.584788Z",
"start_time": "2020-03-01T03:41:41.503778Z"
}
},
"outputs": [],
"source": [
"def main(trial, train=True):\n",
" # PyTorch Lightning will try to restore model parameters from previous trials if checkpoint\n",
" # filenames match. Therefore, the filenames for each trial must be made unique.\n",
" \n",
" checkpoint_callback = pl.callbacks.ModelCheckpoint(\n",
" os.path.join(MODEL_DIR, name, 'version_{}'.format(trial.number), \"chk\"), monitor='val_loss', mode='min')\n",
"\n",
" # The default logger in PyTorch Lightning writes to event files to be consumed by\n",
" # TensorBoard. We create a simple logger instead that holds the log in memory so that the\n",
" # final accuracy can be obtained after optimization. When using the default logger, the\n",
" # final accuracy could be stored in an attribute of the `Trainer` instead.\n",
" logger = DictLogger(MODEL_DIR, name=name, version=trial.number)\n",
"# print(\"log_dir\", logger.experiment.log_dir)\n",
" hparams = dict(**trial.params, **trial.user_attrs)\n",
"\n",
" trainer = pl.Trainer(\n",
" logger=logger,\n",
" val_percent_check=PERCENT_TEST_EXAMPLES,\n",
" checkpoint_callback=checkpoint_callback,\n",
" max_epochs=hparams['max_nb_epochs'],\n",
" gpus=-1 if torch.cuda.is_available() else None,\n",
" early_stop_callback=PyTorchLightningPruningCallback(trial, monitor='val_loss')\n",
" )\n",
" \n",
" model = LSTMSeq2Seq_PL(hparams)\n",
" if train:\n",
" trainer.fit(model)\n",
" return model, trainer"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:41:41.652356Z",
"start_time": "2020-03-01T03:41:41.588888Z"
}
},
"outputs": [],
"source": [
"def add_suggest(trial):\n",
" trial.suggest_loguniform(\"learning_rate\", 1e-5, 1e-2)\n",
" trial.suggest_uniform(\"lstm_dropout\", 0, 0.75)\n",
" trial.suggest_categorical(\"hidden_size\", [1, 2, 4, 8, 16, 32, 64, 128]) \n",
" trial.suggest_categorical(\"lstm_layers\", [1, 2, 4, 8]) \n",
" trial.suggest_categorical(\"bidirectional\", [False, True]) \n",
" \n",
"\n",
" trial._user_attrs = {\n",
" 'batch_size': 16,\n",
" 'grad_clip': 40,\n",
" 'max_nb_epochs': 200,\n",
" 'num_workers': 4,\n",
" 'num_extra_target': 24*4,\n",
" 'vis_i': '670',\n",
" 'num_context': 24*4,\n",
" 'input_size': 18,\n",
" 'input_size_decoder': 17,\n",
" 'context_in_target': True,\n",
" 'output_size': 1\n",
" }\n",
" \n",
" # For manual experiment we will start at -1 and deincr by 1\n",
" versions = [int(s.stem.split('_')[-1]) for s in (MODEL_DIR / name).glob('version_*')] + [-1]\n",
" trial.number = min(versions)-1\n",
" print('trial.number', trial.number)\n",
" return trial"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:41:41.723534Z",
"start_time": "2020-03-01T03:41:41.655316Z"
}
},
"outputs": [],
"source": [
"\n",
"def objective(trial):\n",
" # see https://github.com/optuna/optuna/blob/cf6f02d/examples/pytorch_lightning_simple.py\n",
" trial = add_suggest(trial)\n",
"\n",
" \n",
" print('trial', trial.number, 'params', trial.params)\n",
" \n",
" model, trainer = main(trial)\n",
" \n",
" # also report to tensorboard & print\n",
" print('logger.metrics', model.logger.metrics[-1:])\n",
" model.logger.experiment.add_hparams(trial.params, logger.metrics[-1])\n",
" model.logger.save()\n",
" \n",
" return model.logger.metrics[-1]['val_loss']\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Train"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:41:41.777701Z",
"start_time": "2020-03-01T03:41:41.726164Z"
}
},
"outputs": [],
"source": [
"PERCENT_TEST_EXAMPLES = 0.3\n",
"EPOCHS = 2\n",
"DIR = Path(os.getcwd())\n",
"MODEL_DIR = DIR/ 'optuna_result'/ 'lstm'\n",
"name = \"lstm1\"\n",
"MODEL_DIR.mkdir(parents=True, exist_ok=True)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:41:41.829950Z",
"start_time": "2020-03-01T03:41:41.779861Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"now run `tensorboard --logdir /media/wassname/Storage5/projects2/3ST/attentive-neural-processes/optuna_result/lstm\n"
]
}
],
"source": [
"print(f\"now run `tensorboard --logdir {MODEL_DIR}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[I 2020-01-29 08:42:54,398] Finished trial#8 resulted in value: 0.005635036621242762. Current best value is 0.005635036621242762 with parameters: {'batch_size': 16, 'bidirectional': False, 'grad_clip': 40, 'hidden_size': 128, 'input_size': 17, 'learning_rate': 0.00019134834148401144, 'lstm_dropout': 0.4080689425353674, 'lstm_layers': 8, 'max_nb_epochs': 20, 'num_workers': 4, 'target_length': 24, 'vis_i': 670, 'window_length': 48}."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-02-01T12:52:22.492191Z",
"start_time": "2020-02-01T12:52:22.416653Z"
}
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2020-02-16T01:47:59.598921Z",
"start_time": "2020-02-16T01:47:02.100Z"
}
},
"source": [
"Note that the LSTM has access to the y values for the first half of the plot (the context) to match the NP setup."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"start_time": "2020-03-01T03:47:34.500Z"
},
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"trial.number -21\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:root:gpu available: True, used: True\n",
"INFO:root:VISIBLE GPUS: 0\n"
]
}
],
"source": [
"trial = optuna.trial.FixedTrial(\n",
" params={\n",
" 'bidirectional': False,\n",
" 'hidden_size': 128,\n",
" 'learning_rate': 2e-5,\n",
" 'lstm_dropout': 0.0,\n",
" 'lstm_layers': 2,\n",
" })\n",
"trial._user_attrs = {\n",
" 'batch_size': 16,\n",
" 'grad_clip': 40,\n",
" 'max_nb_epochs': 200,\n",
" 'num_workers': 4,\n",
" 'num_extra_target': 24*4,\n",
" 'vis_i': '670',\n",
" 'num_context': 24*4,\n",
" 'input_size': 18,\n",
" 'input_size_decoder': 17,\n",
" 'context_in_target': True,\n",
" 'output_size': 1\n",
"}\n",
"trial = add_suggest(trial)\n",
"model, trainer = main(trial, train=False)\n",
"trainer.fit(model)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:31:43.522361Z",
"start_time": "2020-03-01T03:31:15.800Z"
}
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.307396Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"# test\n",
"trainer.test(model)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.308984Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"loader = model.val_dataloader()[0]\n",
"dset_test = loader.dataset\n",
"label_names = dset_test.label_names\n",
"plot_from_loader(loader, model, i=670)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.310698Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"# Look at input data, low temp, and holidays imply \n",
"rows_x, rows_y = dset_test.get_rows(670)\n",
"rows_x[['apparentTemperature', 'holiday', 'dayofweek']].plot()"
]
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2020-01-27T09:03:28.792465Z",
"start_time": "2020-01-27T09:03:28.346446Z"
}
},
"source": [
"# Hyperparam opt"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.312313Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"import argparse \n",
"\n",
"parser = argparse.ArgumentParser(description='PyTorch Lightning example.')\n",
"parser.add_argument('--pruning', '-p', action='store_true',\n",
" help='Activate the pruning feature. `MedianPruner` stops unpromising '\n",
" 'trials at the early stages of training.')\n",
"args = parser.parse_args(['-p'])\n",
"\n",
"pruner = optuna.pruners.MedianPruner() if args.pruning else optuna.pruners.NopPruner()\n",
"\n",
"study = optuna.create_study(direction='minimize', pruner=pruner, storage=f'sqlite:///optuna_result/{name}.db', study_name='no-name-b60e37fc-4ab6-4793-8a0a-c87a1b40c5c0', load_if_exists=True)\n",
"\n",
"# shutil.rmtree(MODEL_DIR)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-01-27T23:38:16.813496Z",
"start_time": "2020-01-27T23:38:16.766674Z"
}
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.313923Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"study.optimize(objective, n_trials=200, timeout=6000)\n",
"\n",
"print('Number of finished trials: {}'.format(len(study.trials)))\n",
"\n",
"print('Best trial:')\n",
"trial = study.best_trial\n",
"\n",
"print(' Value: {}'.format(trial.value))\n",
"\n",
"print(' Params: ')\n",
"for key, value in trial.params.items():\n",
" print(' {}: {}'.format(key, value))\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.315413Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"study.optimize(objective, n_trials=200, timeout=6000)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.317152Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"df = study.trials_dataframe(attrs=('number', 'value', 'params', 'state'))\n",
"df.sort_values('value')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Scratch"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.318533Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"model, trainer = main(trial, train=False)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.319880Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"loader = model.val_dataloader()[0]\n",
"dset_test = loader.dataset\n",
"label_names = dset_test.label_names"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.321408Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"x_rows, y_rows = dset_test.iloc(10)\n",
"x_rows.loc[x_rows.index[model.hparams.window_length:], dset_test.label_names] = 0.\n",
"x_rows"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.322849Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"x_rows.loc[x_rows.index[model.hparams.window_length:]]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.324307Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"self=dset_test\n",
"idx=10\n",
"k = idx + self.hparams.window_length + self.hparams.target_length\n",
"j = k - self.hparams.target_length\n",
"i = j - self.hparams.window_length\n",
"idx, k, j, i, self.hparams.window_length + self.hparams.target_length"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.325661Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"j-i"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-03-01T03:47:33.327059Z",
"start_time": "2020-03-01T03:41:28.300Z"
}
},
"outputs": [],
"source": [
"self.hparams.window_length + self.hparams.target_length"
]
},
{
"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"
},
"mimetype": "text/x-python",
"name": "python",
"npconvert_exporter": "python",
"pygments_lexer": "ipython3",
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {
"height": "calc(100% - 180px)",
"left": "10px",
"top": "150px",
"width": "384px"
},
"toc_section_display": true,
"toc_window_display": true
},
"version": 3
},
"nbformat": 4,
"nbformat_minor": 2
}