Files
seq2seq-time/notebooks/02.0-mike-RNN_Timeseries_Seq2Seq.ipynb
T
2020-10-20 06:49:15 +08:00

5.0 MiB

Sequence to Sequence Models for Timeseries Regression

In this notebook we are going to tackle a harder problem:

  • predicting the future on a timeseries
  • using an LSTM
  • with rough uncertainty (uncalibrated)
  • outputing sequence of predictions

https://medium.com/@boitemailjeanmid/smart-meters-in-london-part1-description-and-first-insights-jean-michel-d-db97af2de71b

In [1]:
# OPTIONAL: Load the "autoreload" extension so that code can change. But blacklist large modules
%load_ext autoreload
%autoreload 2
%aimport -pandas
%aimport -torch
%aimport -numpy
%aimport -matplotlib
%aimport -dask
%aimport -tqdm
%matplotlib inline
In [2]:
# Imports
import torch
from torch import nn, optim
from torch.nn import functional as F
from torch.autograd import Variable
import torch
import torch.utils.data

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = (12.0, 3.0)
plt.style.use('ggplot')

from pathlib import Path
from tqdm.auto import tqdm

import pytorch_lightning as pl
In [3]:
import warnings
warnings.simplefilter('once')
In [4]:
from seq2seq_time.data.dataset import Seq2SeqDataSet, Seq2SeqDataSets
from seq2seq_time.predict import predict, predict_multi
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)
In [5]:
import logging, sys
# logging.basicConfig(stream=sys.stdout, level=logging.INFO)
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)

Parameters

In [6]:
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f'using {device}')

columns_target=['energy(kWh/hh)']
window_past = 48*2
window_future = 48*2
batch_size = 256
num_workers = 5
freq = '30T'
max_rows = 5e5
using cuda

Load data

In [7]:

def get_smartmeter_df(indir=Path('../data/raw/smart-meters-in-london'), max_files=8):
    """
    Data loading and cleanding is always messy, so understand this code is optional.
    """
    
    # Load csv files
    csv_files = sorted((indir/'halfhourly_dataset').glob('*.csv'))[:max_files]
    
    dfs = []
    for f in csv_files:
        df = (pd.read_csv(f, parse_dates=[1], na_values=['Null'])
              .groupby('tstp')
              .sum()
              .sort_index()
             )
        df['block'] = f.stem

        # Drop nan and 0's
        df = df[df['energy(kWh/hh)']!=0]
        df = df.dropna()
        
        # Add time features 
        time = df.index.to_series()
        df["month"] = time.dt.month
        df['day'] = time.dt.day
        df['week'] = time.dt.week
        df['hour'] = time.dt.hour
        df['minute'] = time.dt.minute
        df['dayofweek'] = time.dt.dayofweek

        # Load weather data
        df_weather = pd.read_csv(indir/'weather_hourly_darksky.csv', parse_dates=[3])
        use_cols = ['visibility', 'windBearing', 'temperature', 'time', 'dewPoint',
               'pressure', 'apparentTemperature', 'windSpeed', 
               'humidity']
        df_weather = df_weather[use_cols].set_index('time')
        
        # Resample to match energy data   
        # Use first, since we have bearing, and you can't take mean
        df_weather = df_weather.resample(freq).first().ffill()  

        # Join weather and energy data
        df = pd.merge(df, df_weather, how='inner', left_index=True, right_index=True, sort=True)

        # Holidays
        df_hols = pd.read_csv(indir/'uk_bank_holidays.csv', parse_dates=[0])
        holidays = set(df_hols['Bank holidays'].dt.round('D'))  
        def is_holiday(dt):
            return dt in holidays
        days = df.index.floor('D')
        holiday_mapping = days.unique().to_series().apply(is_holiday).astype(int).to_dict()
        df['holiday'] = days.to_series().map(holiday_mapping).values

        # sort
        df.index.name = 'Date'
        df = df.loc['2012-09':] # Weird value before this
    
        dfs.append(df)
    
    return pd.concat(dfs)
In [ ]:

Our dataset is the london smartmeter data. But at half hour intervals

In [8]:
df = get_smartmeter_df(max_files=12)

# # Just get the first one for now
# dfs = list(dfs)

# # df = df.resample(freq).first().dropna() # Where empty we will backfill, this will respect causality, and mostly maintain the mean

df = df.tail(int(max_rows)).copy() # Just use last X rows
# df = pd.concat(dfs[:6], 0)
# # df = dfs[0]
print(df.block.value_counts())
df
Out [8]:
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel_launcher.py:26: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated.  Please use Series.dt.isocalendar().week instead.
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel_launcher.py:26: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated.  Please use Series.dt.isocalendar().week instead.
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel_launcher.py:26: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated.  Please use Series.dt.isocalendar().week instead.
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel_launcher.py:26: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated.  Please use Series.dt.isocalendar().week instead.
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel_launcher.py:26: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated.  Please use Series.dt.isocalendar().week instead.
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel_launcher.py:26: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated.  Please use Series.dt.isocalendar().week instead.
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel_launcher.py:26: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated.  Please use Series.dt.isocalendar().week instead.
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel_launcher.py:26: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated.  Please use Series.dt.isocalendar().week instead.
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel_launcher.py:26: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated.  Please use Series.dt.isocalendar().week instead.
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel_launcher.py:26: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated.  Please use Series.dt.isocalendar().week instead.
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel_launcher.py:26: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated.  Please use Series.dt.isocalendar().week instead.
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel_launcher.py:26: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated.  Please use Series.dt.isocalendar().week instead.
block_107    26161
block_100    26161
block_10     26161
block_1      26161
block_105    26161
block_0      26161
block_102    26161
block_103    26161
block_108    26161
block_106    26161
block_101    26161
block_104    26161
Name: block, dtype: int64
energy(kWh/hh) block month day week hour minute dayofweek visibility windBearing temperature dewPoint pressure apparentTemperature windSpeed humidity holiday
Date
2012-09-01 00:00:00 5.013 block_0 9 1 35 0 0 5 13.36 302.0 14.08 9.74 1028.27 14.08 1.89 0.75 0
2012-09-01 00:30:00 5.157 block_0 9 1 35 0 30 5 13.36 302.0 14.08 9.74 1028.27 14.08 1.89 0.75 0
2012-09-01 01:00:00 6.360 block_0 9 1 35 1 0 5 13.50 298.0 13.93 9.81 1027.96 13.93 1.59 0.76 0
2012-09-01 01:30:00 5.511 block_0 9 1 35 1 30 5 13.50 298.0 13.93 9.81 1027.96 13.93 1.59 0.76 0
2012-09-01 02:00:00 4.922 block_0 9 1 35 2 0 5 13.21 274.0 13.52 9.94 1028.04 13.52 0.82 0.79 0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
2014-02-27 22:00:00 9.819 block_108 2 27 9 22 0 3 14.00 216.0 4.10 1.64 1005.67 1.41 3.02 0.84 0
2014-02-27 22:30:00 8.792 block_108 2 27 9 22 30 3 14.00 216.0 4.10 1.64 1005.67 1.41 3.02 0.84 0
2014-02-27 23:00:00 8.087 block_108 2 27 9 23 0 3 14.03 200.0 3.93 1.61 1004.62 1.42 2.75 0.85 0
2014-02-27 23:30:00 7.114 block_108 2 27 9 23 30 3 14.03 200.0 3.93 1.61 1004.62 1.42 2.75 0.85 0
2014-02-28 00:00:00 7.287 block_108 2 28 9 0 0 4 12.63 190.0 3.81 1.53 1003.57 1.47 2.53 0.85 0

313932 rows × 17 columns

In [ ]:

Plot/explore

In [ ]:
In [ ]:
In [9]:
import holoviews as hv
from holoviews import opts

from holoviews.plotting.links import RangeToolLink

import datashader as ds

from holoviews.operation.datashader import datashade, shade, dynspread, rasterize
from holoviews.operation import decimate

hv.extension('bokeh')


# def house_curve(Name=None):
#     if isinstance(Name, int):
#         name = df.block.unique()[Name]
#     d = df[df.block == Name]
#     d_curve = hv.Curve(d, 'Date', 'energy(kWh/hh)', label=Name).opts(framewise=True)
#     return d_curve


# dmap = hv.DynamicMap(house_curve, kdims=['Name'])
# dmap = dmap.redim.values(Name=list(df.block.unique()))
# dynspread(datashade(dmap).opts(width=800,
#                      height=300,
#                      tools=['xwheel_zoom', 'pan'],
#                      active_tools=['xwheel_zoom', 'pan'],
#                      default_tools=['reset', 'save', 'hover']
#                     ))
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/holoviews/operation/datashader.py:5: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3,and in 3.9 it will stop working
  from collections import Callable
[JavaScript output - execution disabled for security]
[JavaScript output - execution disabled for security]
In [ ]:

Profiling

In [10]:
# from pandas_profiling import ProfileReport
# profile = ProfileReport(df, title="Pandas Profiling Report", minimal=True)
# profile
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)

Norm

In [11]:
df.describe()
Out [11]:
energy(kWh/hh) month day week hour minute dayofweek visibility windBearing temperature dewPoint pressure apparentTemperature windSpeed humidity holiday
count 313932.000000 313932.000000 313932.000000 313932.000000 313932.00000 313932.000000 313932.000000 313932.000000 313932.000000 313932.000000 313932.000000 313932.000000 313932.000000 313932.000000 313932.000000 313932.000000
mean 10.304546 6.878713 15.659187 27.962578 11.49956 14.999427 2.998203 11.203636 194.973128 10.196924 6.316654 1012.613350 8.845714 3.968334 0.784663 0.022018
std 6.425374 3.797205 8.768608 16.528737 6.92243 15.000024 2.001349 3.087941 91.343087 5.891891 5.118656 11.278742 7.116397 2.073511 0.140025 0.146741
min 1.634000 1.000000 1.000000 1.000000 0.00000 0.000000 0.000000 0.270000 0.000000 -3.860000 -8.920000 975.740000 -8.880000 0.040000 0.230000 0.000000
25% 6.121000 3.000000 8.000000 11.000000 5.00000 0.000000 1.000000 10.120000 119.000000 6.050000 2.560000 1005.900000 3.360000 2.450000 0.710000 0.000000
50% 8.502000 8.000000 16.000000 31.000000 11.00000 0.000000 3.000000 12.230000 216.000000 9.580000 6.460000 1013.600000 7.990000 3.720000 0.810000 0.000000
75% 12.126000 10.000000 23.000000 43.000000 17.00000 30.000000 5.000000 13.080000 255.000000 14.070000 10.060000 1020.550000 14.070000 5.160000 0.890000 0.000000
max 53.965000 12.000000 31.000000 52.000000 23.00000 30.000000 6.000000 16.090000 359.000000 32.400000 18.950000 1040.130000 32.420000 14.800000 1.000000 1.000000
In [12]:
import sklearn
from sklearn.preprocessing import StandardScaler, OrdinalEncoder
from sklearn_pandas import DataFrameMapper

columns_input_numeric = list(df.drop(columns=columns_target)._get_numeric_data().columns)
columns_categorical = list(set(df.columns)-set(columns_input_numeric)-set(columns_target))

output_scalers = [([n], StandardScaler()) for n in columns_target]
transformers=output_scalers + \
[([n], StandardScaler()) for n in columns_input_numeric] + \
[([n], OrdinalEncoder()) for n in columns_categorical]
scaler = DataFrameMapper(transformers, df_out=True)
df_norm = scaler.fit_transform(df)
df_norm
Out [12]:
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)
energy(kWh/hh) month day week hour minute dayofweek visibility windBearing temperature dewPoint pressure apparentTemperature windSpeed humidity holiday block
Date
2012-09-01 00:00:00 -0.823540 0.558645 -1.671783 0.425770 -1.661205 -0.999962 1.000225 0.698319 1.171704 0.659055 0.668799 1.388158 0.735526 -1.002328 -0.247549 -0.150044 0.0
2012-09-01 00:30:00 -0.801129 0.558645 -1.671783 0.425770 -1.661205 1.000038 1.000225 0.698319 1.171704 0.659055 0.668799 1.388158 0.735526 -1.002328 -0.247549 -0.150044 0.0
2012-09-01 01:00:00 -0.613902 0.558645 -1.671783 0.425770 -1.516747 -0.999962 1.000225 0.743657 1.127913 0.633597 0.682474 1.360673 0.714448 -1.147010 -0.176133 -0.150044 0.0
2012-09-01 01:30:00 -0.746035 0.558645 -1.671783 0.425770 -1.516747 1.000038 1.000225 0.743657 1.127913 0.633597 0.682474 1.360673 0.714448 -1.147010 -0.176133 -0.150044 0.0
2012-09-01 02:00:00 -0.837703 0.558645 -1.671783 0.425770 -1.372289 -0.999962 1.000225 0.649743 0.865167 0.564009 0.707872 1.367766 0.656834 -1.518362 0.038114 -0.150044 0.0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
2014-02-27 22:00:00 -0.075567 -1.284819 1.293344 -1.147251 1.516874 -0.999962 0.000898 0.905577 0.230197 -1.034801 -0.913650 -0.615615 -1.044872 -0.457357 0.395193 -0.150044 11.0
2014-02-27 22:30:00 -0.235402 -1.284819 1.293344 -1.147251 1.516874 1.000038 0.000898 0.905577 0.230197 -1.034801 -0.913650 -0.615615 -1.044872 -0.457357 0.395193 -0.150044 11.0
2014-02-27 23:00:00 -0.345124 -1.284819 1.293344 -1.147251 1.661332 -0.999962 0.000898 0.915292 0.055033 -1.063654 -0.919511 -0.708710 -1.043467 -0.587572 0.466609 -0.150044 11.0
2014-02-27 23:30:00 -0.496555 -1.284819 1.293344 -1.147251 1.661332 1.000038 0.000898 0.915292 0.055033 -1.063654 -0.919511 -0.708710 -1.043467 -0.587572 0.466609 -0.150044 11.0
2014-02-28 00:00:00 -0.469630 -1.284819 1.407388 -1.147251 -1.661205 -0.999962 0.500561 0.461915 -0.054445 -1.084021 -0.935140 -0.801806 -1.036441 -0.693672 0.466609 -0.150044 11.0

313932 rows × 17 columns

In [13]:
output_scaler = next(filter(lambda r:r[0][0] in columns_target, scaler.features))[-1]
output_scaler
Out [13]:
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)
StandardScaler()

Split

In [14]:
# split data, with the test in the future

d0 =df_norm.index.min()
d1 = df_norm.index.max()
split_time = d0+(d1-d0)*0.8
split_time = split_time.round('1D')
print(split_time)
df_train = df_norm.groupby('block').apply(lambda d:d.loc[:split_time]).reset_index(level=0, drop=True)
df_test = df_norm.groupby('block').apply(lambda d:d.loc[split_time:]).reset_index(level=0, drop=True)
# df_test
2013-11-11 00:00:00
In [15]:
# # Show split
# df_train['energy(kWh/hh)'].plot(label='train')
# df_test['energy(kWh/hh)'].plot(label='test')
# plt.ylabel('energy(kWh/hh)')
# plt.legend()
In [16]:
# # Show split
scatter = dynspread(datashade(hv.Curve(df_train, kdims=['Date'], vdims=['energy(kWh/hh)', 'block']).groupby('block'), cmap='blue'))
scatter *= dynspread(datashade(hv.Curve(df_test, kdims=['Date'], vdims=['energy(kWh/hh)', 'block']).groupby('block'), cmap='red'))
scatter = scatter.opts(plot=dict(width=800))
scatter
Out [16]:
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/bokeh/core/property/bases.py:241: DeprecationWarning: elementwise comparison failed; this will raise an error in the future.
  return new == old

Dataset

In [17]:

# ### Dataset
# These are the columns that we wont know in the future
# We need to blank them out in x_future
columns_blank=['visibility',
       'windBearing', 'temperature', 'dewPoint', 'pressure',
       'apparentTemperature', 'windSpeed', 'humidity']
df_trains = [d.resample(freq).first().ffill().dropna() for _,d in df_train.groupby('block')]
df_tests = [d.resample(freq).first().ffill().dropna() for _,d in df_test.groupby('block')]
ds_train = Seq2SeqDataSets(df_trains,
                          window_past=window_past,
                          window_future=window_future,
                          columns_blank=columns_blank)
ds_test = Seq2SeqDataSets(df_tests,
                         window_past=window_past,
                         window_future=window_future,
                         columns_blank=columns_blank)
print(ds_train)
print(ds_test)
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)
<Seq2SeqDataSets([<Seq2SeqDataSet(shape=(20929, 17), times=2012-09-01 00:00:00 to 2012-09-01 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(20929, 17), times=2012-09-01 00:00:00 to 2012-09-01 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(20929, 17), times=2012-09-01 00:00:00 to 2012-09-01 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(20929, 17), times=2012-09-01 00:00:00 to 2012-09-01 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(20929, 17), times=2012-09-01 00:00:00 to 2012-09-01 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(20929, 17), times=2012-09-01 00:00:00 to 2012-09-01 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(20929, 17), times=2012-09-01 00:00:00 to 2012-09-01 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(20929, 17), times=2012-09-01 00:00:00 to 2012-09-01 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(20929, 17), times=2012-09-01 00:00:00 to 2012-09-01 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(20929, 17), times=2012-09-01 00:00:00 to 2012-09-01 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(20929, 17), times=2012-09-01 00:00:00 to 2012-09-01 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(20929, 17), times=2012-09-01 00:00:00 to 2012-09-01 00:30:00 at 30T)>])>
<Seq2SeqDataSets([<Seq2SeqDataSet(shape=(5233, 17), times=2013-11-11 00:00:00 to 2013-11-11 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(5233, 17), times=2013-11-11 00:00:00 to 2013-11-11 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(5233, 17), times=2013-11-11 00:00:00 to 2013-11-11 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(5233, 17), times=2013-11-11 00:00:00 to 2013-11-11 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(5233, 17), times=2013-11-11 00:00:00 to 2013-11-11 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(5233, 17), times=2013-11-11 00:00:00 to 2013-11-11 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(5233, 17), times=2013-11-11 00:00:00 to 2013-11-11 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(5233, 17), times=2013-11-11 00:00:00 to 2013-11-11 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(5233, 17), times=2013-11-11 00:00:00 to 2013-11-11 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(5233, 17), times=2013-11-11 00:00:00 to 2013-11-11 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(5233, 17), times=2013-11-11 00:00:00 to 2013-11-11 00:30:00 at 30T)>, <Seq2SeqDataSet(shape=(5233, 17), times=2013-11-11 00:00:00 to 2013-11-11 00:30:00 at 30T)>])>
In [18]:
# we can treat it like an array
ds_train[0]
len(ds_train)
ds_train[-1]
Out [18]:
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)
[array([[ 1.0853493 , -0.9875229 ,  1.0307775 , ...,  0.        ,
         -2.        ,  1.        ],
        [ 1.0853493 , -0.9875229 ,  1.0307775 , ...,  0.        ,
         -1.9791666 ,  1.        ],
        [ 1.0853493 , -0.9875229 ,  1.0307775 , ...,  0.        ,
         -1.9583334 ,  1.        ],
        ...,
        [ 1.0853493 , -0.87347955,  1.0307775 , ...,  0.        ,
         -0.0625    ,  1.        ],
        [ 1.0853493 , -0.75943613,  1.0307775 , ...,  0.        ,
         -0.04166667,  1.        ],
        [ 1.0853493 , -0.75943613,  1.0307775 , ...,  0.        ,
         -0.02083333,  1.        ]], dtype=float32),
 array([[ 0.21577835],
        [ 0.15010113],
        [ 0.13095824],
        [ 0.02481639],
        [ 0.02030303],
        [-0.0716762 ],
        [ 0.15803841],
        [ 0.02917414],
        [-0.0674741 ],
        [ 0.20052628],
        [ 0.19009887],
        [ 0.6498394 ],
        [ 1.2491828 ],
        [ 1.628461  ],
        [ 1.5388163 ],
        [ 1.9378599 ],
        [ 1.5101798 ],
        [ 1.8061942 ],
        [ 1.569943  ],
        [ 1.4147766 ],
        [ 1.5297896 ],
        [ 0.9147271 ],
        [ 0.5668869 ],
        [ 0.6613563 ],
        [ 0.8767526 ],
        [ 1.2315964 ],
        [ 1.4297174 ],
        [ 1.279687  ],
        [ 1.4004583 ],
        [ 1.1357263 ],
        [ 0.991143  ],
        [ 1.7546796 ],
        [ 1.8547517 ],
        [ 2.5337794 ],
        [ 2.6925254 ],
        [ 3.1499314 ],
        [ 3.0293155 ],
        [ 3.4837644 ],
        [ 3.7531657 ],
        [ 3.8403203 ],
        [ 3.7007172 ],
        [ 2.7031083 ],
        [ 3.0036361 ],
        [ 2.3289661 ],
        [ 1.6462032 ],
        [ 1.4122865 ],
        [ 1.1221862 ],
        [ 0.47366259],
        [ 0.43179724],
        [ 0.1378061 ],
        [ 0.10450058],
        [ 0.05890007],
        [-0.01922781],
        [ 0.01361078],
        [ 0.25001764],
        [ 0.20379458],
        [ 0.15912783],
        [ 0.03804521],
        [ 0.0112763 ],
        [ 0.40020368],
        [ 0.9962789 ],
        [ 1.5427071 ],
        [ 1.4130647 ],
        [ 1.1237426 ],
        [ 1.6356201 ],
        [ 2.0203454 ],
        [ 1.6363983 ],
        [ 1.2048274 ],
        [ 1.2031155 ],
        [ 1.6057385 ],
        [ 1.4756292 ],
        [ 0.93324745],
        [ 1.3648183 ],
        [ 2.0363758 ],
        [ 1.6476039 ],
        [ 2.2405665 ],
        [ 2.4416447 ],
        [ 2.1408055 ],
        [ 1.6493158 ],
        [ 2.2284272 ],
        [ 2.4018025 ],
        [ 2.8567183 ],
        [ 2.898895  ],
        [ 3.9316769 ],
        [ 3.660097  ],
        [ 3.2076712 ],
        [ 3.409839  ],
        [ 3.2286818 ],
        [ 3.0336733 ],
        [ 2.8353965 ],
        [ 2.9273758 ],
        [ 2.1327126 ],
        [ 1.6311067 ],
        [ 1.6121196 ],
        [ 0.8972962 ],
        [ 0.5648636 ]], dtype=float32),
 array([[ 1.0853493 , -0.75943613,  1.0307775 , ...,  0.        ,
          0.        ,  0.        ],
        [ 1.0853493 , -0.75943613,  1.0307775 , ...,  0.        ,
          0.02083333,  0.        ],
        [ 1.0853493 , -0.75943613,  1.0307775 , ...,  0.        ,
          0.04166667,  0.        ],
        ...,
        [ 1.0853493 , -0.6453928 ,  1.0307775 , ...,  0.        ,
          1.9166666 ,  0.        ],
        [ 1.0853493 , -0.6453928 ,  1.0307775 , ...,  0.        ,
          1.9375    ,  0.        ],
        [ 1.0853493 , -0.5313494 ,  1.0912782 , ...,  0.        ,
          1.9583334 ,  0.        ]], dtype=float32),
 array([[ 1.9492349e-01],
        [ 7.5397186e-02],
        [ 2.3336489e-01],
        [ 1.2053080e-01],
        [ 2.2355998e-01],
        [ 2.9982027e-01],
        [ 1.5866096e-01],
        [ 1.1866322e-01],
        [ 1.0512313e-01],
        [ 3.0122095e-01],
        [ 2.1468890e-01],
        [ 5.3949541e-01],
        [ 8.2181406e-01],
        [ 1.5501775e+00],
        [ 1.8349863e+00],
        [ 1.6644123e+00],
        [ 2.1366036e+00],
        [ 2.1674187e+00],
        [ 1.9316344e+00],
        [ 1.8812094e+00],
        [ 2.2492819e+00],
        [ 2.3697419e+00],
        [ 1.8332744e+00],
        [ 1.7370930e+00],
        [ 2.1202619e+00],
        [ 2.6394544e+00],
        [ 2.0871119e+00],
        [ 1.7694647e+00],
        [ 2.0368426e+00],
        [ 2.1297555e+00],
        [ 2.0472701e+00],
        [ 3.0395873e+00],
        [ 3.2934251e+00],
        [ 3.4733372e+00],
        [ 3.8921461e+00],
        [ 3.5867937e+00],
        [ 3.4696019e+00],
        [ 3.4269586e+00],
        [ 2.8092501e+00],
        [ 2.9440286e+00],
        [ 2.4144087e+00],
        [ 2.0331073e+00],
        [ 2.2208011e+00],
        [ 1.8822988e+00],
        [ 1.5588930e+00],
        [ 1.4409230e+00],
        [ 1.1388389e+00],
        [ 1.0885694e+00],
        [ 5.5381370e-01],
        [ 3.4310017e-02],
        [ 1.3157757e-03],
        [-1.2521403e-01],
        [-7.3855065e-02],
        [-1.2101193e-01],
        [ 3.9912798e-02],
        [ 1.2270970e-01],
        [ 4.5204341e-02],
        [-1.2677038e-01],
        [-1.6115144e-02],
        [ 2.1842413e-01],
        [ 5.3249198e-01],
        [ 4.2136979e-01],
        [ 7.1224833e-01],
        [ 1.4854342e+00],
        [ 1.8214462e+00],
        [ 1.6490046e+00],
        [ 2.0604987e+00],
        [ 2.0366869e+00],
        [ 1.6323519e+00],
        [ 1.3979683e+00],
        [ 1.3878522e+00],
        [ 1.4852785e+00],
        [ 1.5033319e+00],
        [ 1.9745893e+00],
        [ 2.0606544e+00],
        [ 1.8254926e+00],
        [ 1.8941269e+00],
        [ 2.4310615e+00],
        [ 2.7108901e+00],
        [ 2.6917472e+00],
        [ 2.9974108e+00],
        [ 3.7825804e+00],
        [ 3.2772393e+00],
        [ 3.5678065e+00],
        [ 3.8865433e+00],
        [ 3.7761993e+00],
        [ 3.8535490e+00],
        [ 3.9933076e+00],
        [ 3.0651112e+00],
        [ 2.7614708e+00],
        [ 2.6290269e+00],
        [ 2.4046037e+00],
        [ 1.4166442e+00],
        [ 1.4624003e+00],
        [ 9.4772130e-01]], dtype=float32)]
In [19]:
# We can get rows
x_past, y_past, x_future, y_future = ds_train.get_rows(10)

# Plot one instance, this is what the model sees
y_past['energy(kWh/hh)'].plot(label='past')
y_future['energy(kWh/hh)'].plot(ax=plt.gca(), label='future')
plt.legend()
plt.ylabel('energy(kWh/hh)')

# Notice we've added on two new columns tsp (time since present) and is_past
x_past.tail()
Out [19]:
month day week hour minute dayofweek visibility windBearing temperature dewPoint pressure apparentTemperature windSpeed humidity holiday block tsp_days is_past
Date
2013-11-08 17:00:00 1.085349 -0.87348 1.030777 0.794583 -0.999962 0.500561 -0.205197 0.700950 -0.350809 0.160852 -0.928594 -0.347889 -0.539344 1.037935 -0.150044 0.0 -0.104167 1.0
2013-11-08 17:30:00 1.085349 -0.87348 1.030777 0.794583 1.000038 0.500561 -0.205197 0.700950 -0.350809 0.160852 -0.928594 -0.347889 -0.539344 1.037935 -0.150044 0.0 -0.083333 1.0
2013-11-08 18:00:00 1.085349 -0.87348 1.030777 0.939042 -0.999962 0.500561 0.176935 0.919905 -0.349112 0.139362 -0.896675 -0.442038 0.034563 1.037935 -0.150044 0.0 -0.062500 1.0
2013-11-08 18:30:00 1.085349 -0.87348 1.030777 0.939042 1.000038 0.500561 0.176935 0.919905 -0.349112 0.139362 -0.896675 -0.442038 0.034563 1.037935 -0.150044 0.0 -0.041667 1.0
2013-11-08 19:00:00 1.085349 -0.87348 1.030777 1.083500 -0.999962 0.500561 0.118644 0.952749 -0.391543 -0.048187 -0.821312 -0.517919 0.270877 0.680856 -0.150044 0.0 -0.020833 1.0
In [20]:
# Notice we've hidden some future columns to prevent cheating
x_future.tail()
Out [20]:
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)
month day week hour minute dayofweek visibility windBearing temperature dewPoint pressure apparentTemperature windSpeed humidity holiday block tsp_days is_past
Date
2013-11-10 17:00:00 1.085349 -0.645393 1.030777 0.794583 -0.999962 1.499889 -0.328257 0.36157 0.77956 1.225586 -1.236252 0.835296 2.180685 0.609441 -0.150044 0.0 1.895833 0.0
2013-11-10 17:30:00 1.085349 -0.645393 1.030777 0.794583 1.000038 1.499889 -0.328257 0.36157 0.77956 1.225586 -1.236252 0.835296 2.180685 0.609441 -0.150044 0.0 1.916667 0.0
2013-11-10 18:00:00 1.085349 -0.645393 1.030777 0.939042 -0.999962 1.499889 -0.328257 0.36157 0.77956 1.225586 -1.236252 0.835296 2.180685 0.609441 -0.150044 0.0 1.937500 0.0
2013-11-10 18:30:00 1.085349 -0.645393 1.030777 0.939042 1.000038 1.499889 -0.328257 0.36157 0.77956 1.225586 -1.236252 0.835296 2.180685 0.609441 -0.150044 0.0 1.958333 0.0
2013-11-10 19:00:00 1.085349 -0.645393 1.030777 1.083500 -0.999962 1.499889 -0.328257 0.36157 0.77956 1.225586 -1.236252 0.835296 2.180685 0.609441 -0.150044 0.0 1.979167 0.0

Plot helpers

In [21]:
def plot_prediction(ds_preds, i):
    """Plot a prediction into the future, at a single point in time."""
    d = ds_preds.isel(t_source=i)

    # Get arrays
    xf = d.t_target
    yp = d.y_pred
    s = d.y_pred_std
    yt = d.y_true
    now = d.t_source.squeeze()
    
    
    plt.figure(figsize=(12, 4))
    
    plt.scatter(xf, yt, label='true', c='k', s=6)
    ylim = plt.ylim()

    # plot prediction
    plt.fill_between(xf, yp-2*s, yp+2*s, alpha=0.25,
            facecolor="b",
            interpolate=True,
            label="2 std",)
    plt.plot(xf, yp, label='pred', c='b')

    # plot true
    plt.scatter(
        d.t_past,
        d.y_past,
        c='k',
        s=6
    )
    
    # plot a red line for now
    plt.vlines(x=now, ymin=0, ymax=1, label='now', color='r')
    plt.ylim(*ylim)

    now=pd.Timestamp(now.values)
    plt.title(f'Prediction NLL={d.nll.mean().item():2.2g}')
    plt.xlabel(f'{now.date()}')
    plt.ylabel('energy(kWh/hh)')
    plt.legend()
    plt.xticks(rotation=45)
    plt.show()
    
def plot_performance(ds_preds, full=False):
    """Multiple plots using xr_preds"""
    plot_prediction(ds_preds, 24)

    ds_preds.mean('t_source').plot.scatter('t_ahead_hours', 'nll') # Mean over all predictions
    n = len(ds_preds.t_source)
    plt.ylabel('Negative Log Likelihood (lower is better)')
    plt.xlabel('Hours ahead')
    plt.title(f'NLL vs time ahead (no. samples={n})')
    plt.show()

    # Make a plot of the NLL over time. Does this solution get worse with time?
    if full:
        d = ds_preds.mean('t_ahead').groupby('t_source').mean().plot.scatter('t_source', 'nll')
        plt.xticks(rotation=45)
        plt.title('NLL over source time (lower is better)')
        plt.show()

    # A scatter plot is easy with xarray
    if full:
        plt.figure(figsize=(5, 5))
        ds_preds.plot.scatter('y_true', 'y_pred', s=.01)
        plt.show()
    
    
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)
In [ ]:
In [22]:
def plot_hist(trainer):
    try:
        df_hist = pd.read_csv(trainer.logger.experiment.metrics_file_path)
        df_hist['epoch'] = df_hist['epoch'].ffill()
        df_histe = df_hist.set_index('epoch').groupby('epoch').mean()
        if len(df_histe)>1:
            df_histe[['loss/train', 'loss/val']].plot(title='history')
        return df_histe
    except Exception:
        pass

Lightning

In [23]:
import pytorch_lightning as pl

class PL_MODEL(pl.LightningModule):
    def __init__(self, model, lr=3e-4, patience=2):
        super().__init__()
        self._model = model
        self.lr = lr
        self.patience = patience

    def forward(self, x_past, y_past, x_future, y_future=None):
        """Eval/Predict"""
        y_dist, extra = self._model(x_past, y_past, x_future, y_future)
        return y_dist, extra

    def training_step(self, batch, batch_idx, phase='train'):
        x_past, y_past, x_future, y_future = batch
        y_dist, extra = self.forward(*batch)
        loss = -y_dist.log_prob(y_future).mean()
        self.log_dict({f'loss/{phase}':loss})
        if ('loss' in extra) and (phase=='train'):
            # some models have a special loss
            loss = extra['loss']
            self.log_dict({f'model_loss/{phase}':loss})
        return loss

    def validation_step(self, batch, batch_idx):
        return self.training_step(batch, batch_idx, phase='val')

    def configure_optimizers(self):
        optim = torch.optim.Adam(self.parameters(), lr=self.lr)
        scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(
            optim,
            patience=self.patience,
            verbose=True,
            min_lr=1e-7,
        )
        return {'optimizer': optim, 'lr_scheduler': scheduler, 'monitor': 'loss/val'}
In [24]:
# # Run
from torch.utils.data import DataLoader
from pytorch_lightning.loggers import CSVLogger
from pytorch_lightning.callbacks.early_stopping import EarlyStopping
In [25]:
# Init data
x_past, y_past, x_future, y_future = ds_train.get_rows(10)
input_size = x_past.shape[-1]
output_size = y_future.shape[-1]

dl_train = DataLoader(ds_train,
                      batch_size=batch_size,
                      shuffle=True,
                      pin_memory=num_workers==0,
                      num_workers=num_workers)
dl_test = DataLoader(ds_test, batch_size=batch_size, num_workers=num_workers)
In [30]:
from seq2seq_time.models.lstm_seq2seq import LSTMSeq2Seq
from seq2seq_time.models.lstm_seq import LSTMSeq
from seq2seq_time.models.lstm import LSTM
from seq2seq_time.models.baseline import BaselineLast
from seq2seq_time.models.transformer import Transformer
from seq2seq_time.models.transformer_seq2seq import TransformerSeq2Seq
from seq2seq_time.models.transformer_seq import TransformerSeq
from seq2seq_time.models.neural_process import RANP
# ## Plots
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)
In [27]:
models = [
    RANP(input_size,
                output_size),
    LSTM(input_size,
         output_size,
         hidden_size=80,
         lstm_layers=3,
         lstm_dropout=0.3),

    LSTMSeq2Seq(input_size,
                output_size,
                hidden_size=64,
                lstm_layers=2,
                lstm_dropout=0.25),
    TransformerSeq2Seq(input_size,
                       output_size,
                       hidden_size=64,
                       nhead=8,
                       nlayers=4,
                       attention_dropout=0.3),
    Transformer(input_size,
                output_size,
                attention_dropout=0.3,
                nhead=8,
                nlayers=6,
                hidden_size=64),
    TransformerSeq(input_size,
                output_size),
    LSTMSeq(input_size,
                output_size),
    
]
In [28]:
# Baseline model
pt_model = BaselineLast()
model = PL_MODEL(pt_model).to(device)
trainer = pl.Trainer(gpus=1,
                     max_epochs=1, 
                     limit_train_batches=0.01,
                     logger=CSVLogger("logs",
                                      name=type(pt_model).__name__),
                    )
trainer.fit(model, dl_train, dl_test)
print(plot_hist(trainer))
ds_predss = predict_multi(model.to(device),
                   ds_test.datasets,
                   batch_size*8,
                   device=device,
                   scaler=output_scaler)
print(f'baseline nll: {ds_preds.nll.mean().item():2.2g}')
GPU available: True, used: True
TPU available: False, using: 0 TPU cores
LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0]

  | Name   | Type         | Params
----------------------------------------
0 | _model | BaselineLast | 1     
HBox(children=(HTML(value='Validation sanity check'), FloatProgress(value=1.0, bar_style='info', layout=Layout…
HBox(children=(HTML(value='Training'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), max…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
None
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=20.0), HTML(value='')))
baseline nll: 2.3
In [29]:
for pt_model in models:
    name = type(pt_model).__name__
    print(name)

    # Wrap in lightning
    patience = 2
    model = PL_MODEL(pt_model, patience=patience, lr=3e-4).to(device)

    # Trainer    
    trainer = pl.Trainer(gpus=1,
                         min_epochs=2,
                         max_epochs=10,
                         amp_level='O1',
                         precision=16,
                         gradient_clip_val=1,
                         logger=CSVLogger("logs",
                                          name=type(pt_model).__name__),
                         callbacks=[
                             EarlyStopping(monitor='loss/val', patience=patience*2),
#                              PrintTableMetricsCallback2()
                         ],
    )

    # Train
    trainer.fit(model, dl_train, dl_test)



    ds_predss = predict_multi(model.to(device),
                       ds_test.datasets,
                       batch_size*8,
                       device=device,
                       scaler=output_scaler)
    
    print(name)
    print(f'mean_NLL {ds_predss.nll.mean().item():2.2f}')
    
    # Performance
    ds_preds = ds_predss.isel(block=0)
    print(plot_hist(trainer))
    plot_performance(ds_preds)
/home/wassname/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)
GPU available: True, used: True
TPU available: False, using: 0 TPU cores
LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0]
Using native 16bit precision.

  | Name   | Type | Params
--------------------------------
0 | _model | RANP | 58 K  
RANP
HBox(children=(HTML(value='Validation sanity check'), FloatProgress(value=1.0, bar_style='info', layout=Layout…
HBox(children=(HTML(value='Training'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), max…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
Epoch     8: reducing learning rate of group 0 to 3.0000e-05.
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value=''), FloatProgress(value=0.0, max=12.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
RANP
mean_NLL -0.03
       loss/train  model_loss/train         step  loss/val
epoch                                                     
0.0      0.156459          0.156764   522.650000  0.053744
1.0     -0.129233         -0.128922  1473.800000 -0.003657
2.0     -0.164016         -0.163826  2447.523810 -0.012628
3.0     -0.174735         -0.174592  3423.600000 -0.031114
4.0     -0.197001         -0.196890  4397.333333 -0.043655
5.0     -0.207953         -0.207857  5373.400000 -0.041250
6.0     -0.225731         -0.225642  6347.142857 -0.038535
7.0     -0.233150         -0.233063  7323.200000 -0.024135
8.0     -0.247012         -0.246924  8296.952381 -0.033753
mean_NLL 0.55
GPU available: True, used: True
TPU available: False, using: 0 TPU cores
LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0]
Using native 16bit precision.

  | Name   | Type | Params
--------------------------------
0 | _model | LSTM | 136 K 
LSTM
HBox(children=(HTML(value='Validation sanity check'), FloatProgress(value=1.0, bar_style='info', layout=Layout…
HBox(children=(HTML(value='Training'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), max…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
Epoch     6: reducing learning rate of group 0 to 3.0000e-05.
HBox(children=(HTML(value='Validating'), FloatProgress(value=1.0, bar_style='info', layout=Layout(flex='2'), m…
HBox(children=(HTML(value=''), FloatProgress(value=0.0, max=12.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
HBox(children=(HTML(value='predict'), FloatProgress(value=0.0, max=3.0), HTML(value='')))
LSTM
mean_NLL 0.35
       loss/train         step  loss/val
epoch                                   
0.0      0.225341   522.650000  0.327770
1.0     -0.098921  1473.800000  0.319602
2.0     -0.172654  2447.523810  0.228442
3.0     -0.213030  3423.600000  0.382066
4.0     -0.225637  4397.333333  0.311360
5.0     -0.257630  5373.400000  0.379025
6.0     -0.264004  6347.142857  0.347051
mean_NLL 1.38
GPU available: True, used: True
TPU available: False, using: 0 TPU cores
LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0]
Using native 16bit precision.

  | Name   | Type        | Params
---------------------------------------
0 | _model | LSTMSeq2Seq | 109 K 
LSTMSeq2Seq
HBox(children=(HTML(value='Validation sanity check'), FloatProgress(value=1.0, bar_style='info', layout=Layout…
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-29-74f32e8df344> in <module>
     23 
     24     # Train
---> 25     trainer.fit(model, dl_train, dl_test)
     26 
     27 

~/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/pytorch_lightning/trainer/trainer.py in fit(self, model, train_dataloader, val_dataloaders, datamodule)
    438         self.call_hook('on_fit_start')
    439 
--> 440         results = self.accelerator_backend.train()
    441         self.accelerator_backend.teardown()
    442 

~/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/pytorch_lightning/accelerators/gpu_accelerator.py in train(self)
     52 
     53         # train or test
---> 54         results = self.train_or_test()
     55         return results
     56 

~/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/pytorch_lightning/accelerators/accelerator.py in train_or_test(self)
     64             results = self.trainer.run_test()
     65         else:
---> 66             results = self.trainer.train()
     67         return results
     68 

~/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/pytorch_lightning/trainer/trainer.py in train(self)
    460 
    461     def train(self):
--> 462         self.run_sanity_check(self.get_model())
    463 
    464         # enable train mode

~/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/pytorch_lightning/trainer/trainer.py in run_sanity_check(self, ref_model)
    646 
    647             # run eval step
--> 648             _, eval_results = self.run_evaluation(test_mode=False, max_batches=self.num_sanity_val_batches)
    649 
    650             # allow no returns from eval

~/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/pytorch_lightning/trainer/trainer.py in run_evaluation(self, test_mode, max_batches)
    566 
    567                 # lightning module methods
--> 568                 output = self.evaluation_loop.evaluation_step(test_mode, batch, batch_idx, dataloader_idx)
    569                 output = self.evaluation_loop.evaluation_step_end(output)
    570 

~/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/pytorch_lightning/trainer/evaluation_loop.py in evaluation_step(self, test_mode, batch, batch_idx, dataloader_idx)
    169             output = self.trainer.accelerator_backend.test_step(args)
    170         else:
--> 171             output = self.trainer.accelerator_backend.validation_step(args)
    172 
    173         # track batch size for weighted average

~/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/pytorch_lightning/accelerators/gpu_accelerator.py in validation_step(self, args)
     74         if self.trainer.amp_backend == AMPType.NATIVE:
     75             with torch.cuda.amp.autocast():
---> 76                 output = self.__validation_step(args)
     77         else:
     78             output = self.__validation_step(args)

~/anaconda/envs/seq2seq-time/lib/python3.7/site-packages/pytorch_lightning/accelerators/gpu_accelerator.py in __validation_step(self, args)
     84         batch = self.to_device(batch)
     85         args[0] = batch
---> 86         output = self.trainer.model.validation_step(*args)
     87         return output
     88 

<ipython-input-23-a397a13f8c11> in validation_step(self, batch, batch_idx)
     25 
     26     def validation_step(self, batch, batch_idx):
---> 27         return self.training_step(batch, batch_idx, phase='val')
     28 
     29     def configure_optimizers(self):

<ipython-input-23-a397a13f8c11> in training_step(self, batch, batch_idx, phase)
     15     def training_step(self, batch, batch_idx, phase='train'):
     16         x_past, y_past, x_future, y_future = batch
---> 17         y_dist, extra = self.forward(*batch)
     18         loss = -y_dist.log_prob(y_future).mean()
     19         self.log_dict({f'loss/{phase}':loss})

<ipython-input-23-a397a13f8c11> in forward(self, x_past, y_past, x_future, y_future)
     10     def forward(self, x_past, y_past, x_future, y_future=None):
     11         """Eval/Predict"""
---> 12         y_dist, extra = self._model(x_past, y_past, x_future, y_future)
     13         return y_dist, extra
     14 

TypeError: cannot unpack non-iterable Normal object
In [ ]:
# ds_preds = predict(model.to(device),
#                    ds_test.datasets[0],
#                    batch_size*8,
#                    device=device,
#                    scaler=output_scaler)
In [ ]:
ds_predss = predict_multi(model.to(device),
                   ds_test.datasets,
                   batch_size*8,
                   device=device,
                   scaler=output_scaler)
In [ ]:
ds_pred_block = ds_predss.isel(block=1)

holoviews pred

In [ ]:
import holoviews as hv
from holoviews import opts
In [ ]:
def plot_prediction_now(t_source):
    """Plot predictions with holoviews"""

    # Let us pass in an int
    if isinstance(t_source, int):
        t_source = ds_pred_block.t_source[t_source].to_pandas()

    d = ds_pred_block.sel(t_source=t_source)

    # Sometimes there are duplicate times, take the first
    if len(d.t_source.shape) and d.t_source.shape[0] > 0:
        d = d.isel(t_source=0)
    if len(d.t_source.shape) and d.t_source.shape[0] == 0:
        return None

    now = d.t_source.to_pandas()

    # Plot true
    x = np.concatenate([d.t_past, d.t_target])
    yt = np.concatenate([d.y_past, d.y_true])
    p = hv.Scatter({
        'x': x,
        'y': yt
    }, label='true').opts(color='black')

    # Get arrays
    xf = d.t_target.values
    yp = d.y_pred
    s = d.y_pred_std
    p *= hv.Curve({
        'x': xf,
        'y': yp
    }, label='pred').opts(color='blue')
    p *= hv.Area((xf, yp - 2 * s, yp + 2 * s),
                 vdims=['y', 'y2'],
                 label='2*std').opts(alpha=0.5, line_width=0)

    # plot now line
    p *= hv.VLine(now, label='now').opts(color='red', framewise=True)
    return p.opts(title=f'Prediction at {now}. NLL={d.nll.mean().item():2.2f}')


dmap_pred = (hv.DynamicMap(plot_prediction_now, kdims=['t_source'])
        .redim.values(t_source=ds_pred_block.t_source.to_pandas())
        .opts(width=800,
                     height=300, 
                    ))
dmap_pred
In [ ]:
d = ds_preds.mean(['t_source', 'block'])['nll'].groupby('t_ahead_hours').mean()
nll_vs_tahead = hv.Curve((d.t_ahead_hours, d)).redim(x='hours ahead', y='nll').opts(width=800)
nll_vs_tahead
In [ ]:
# def plot_predictions_vs_time(it_ahead):
#     """Plot predictions vs time with holoviews"""

#     d = ds_pred_block.isel(t_ahead=it_ahead).groupby('t_source').first()
# #     print(d)

#     p = hv.Scatter({
#         'x': d.t_source,
#         'y': d.y_true
#     }, label='true').opts(color='black')

#     # Get arrays
#     xf = d.t_source.values
#     yp = d.y_pred
#     s = d.y_pred_std
#     p *= hv.Curve({
#         'x': xf,
#         'y': yp
#     }, label='pred').opts(color='blue')
#     p *= hv.Area((xf, yp - 2 * s, yp + 2 * s),
#                  vdims=['y', 'y2'],
#                  label='2*std').opts(alpha=0.5, line_width=0)


#     return p.opts(title=f'Prediction at {it_ahead * pd.Timedelta(freq)} ahead. NLL={d.nll.mean().item():2.2f}')


# dmap_preds = (hv.DynamicMap(plot_predictions_vs_time, kdims=['it_ahead'])
#         .redim.values(it_ahead=range(ds_pred_block.t_ahead.shape[0]))
#         .opts(width=800,
#                      height=300, 
#                     ))
# dmap_preds
# # TODO fixme
In [ ]:
In [ ]:
# d = ds_preds.mean(['t_ahead', 'block'])['nll'].groupby('t_source').mean()
# nll_vs_time = hv.Curve(d).opts(width=800)
# nll_vs_time
In [ ]:
# true_vs_pred = hv.Scatter((ds_preds.y_true, ds_preds.y_pred))
# dynspread(datashade(true_vs_pred))

Summarize experiments

LR finder

In [ ]:

# # Run learning rate finder
# lr_finder = trainer.tuner.lr_find(model)

# # Results can be found in
# lr_finder.results

# # Plot with
# fig = lr_finder.plot(suggest=True)
# fig.show()

# # Pick point based on plot, or get suggestion
# new_lr = lr_finder.suggestion()
In [ ]: