In [1]:
from __future__ import print_function, division
import matplotlib
matplotlib.use('nbagg') # interactive plots in iPython. New in matplotlib v1.4
# %matplotlib inline

In [2]:
import matplotlib.pyplot as plt
from nilmtk import DataSet, MeterGroup
import pandas as pd
import numpy as np
from time import time
import gc


Couldn't import dot_parser, loading of dot files will not be possible.
/usr/local/lib/python2.7/dist-packages/bottleneck/__init__.py:13: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility
  from .func import (nansum, nanmax, nanmin, nanmean, nanstd, nanvar, median,
/usr/local/lib/python2.7/dist-packages/bottleneck/__init__.py:19: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility
  from .move import (move_sum, move_nansum,

In [3]:
from pybrain.supervised import RPropMinusTrainer
from pybrain.datasets import SequentialDataSet
from pybrain.structure import RecurrentNetwork, FullConnection
from pybrain.structure.modules import LSTMLayer, BiasUnit, LinearLayer, TanhLayer, SigmoidLayer

In [4]:
CONFIG = dict(
    EPOCHS_PER_CYCLE = 5,
    CYCLES = 20,
    HIDDEN_LAYERS = [50, 50],
    PEEPHOLES = True,
    TRAINERCLASS = RPropMinusTrainer,
    # instead, you may also try
    # TRAINERCLASS = BackpropTrainer(net, dataset=trndata, verbose=True, 
    #                                momentum=0.9, learningrate=0.00001)
    INPUTS = [], #, 'hour of day (int)', 'outside temperature', 'is business day (-1, 1)'
    EXPERIMENT_NUMBER = 25
)

In [5]:
# Load dataset
dataset = DataSet('/data/mine/vadeec/merged/ukdale.h5')
dataset.set_window("2014-01-01", "2014-02-01")
elec = dataset.buildings[1].elec

In [6]:
# Select top-5 meters identified in UK-DALE paper
# APPLIANCES = ['kettle', 'dish washer', 'HTPC', 'washer dryer', 'fridge freezer']
APPLIANCES = ['kettle', 'toaster']
selected_meters = [elec[appliance] for appliance in APPLIANCES]
selected_meters.append(elec.mains())
selected = MeterGroup(selected_meters)

In [18]:
df = selected.dataframe_of_meters()

In [19]:
# Use human-readable column names
df.columns = selected.get_labels(df.columns)

In [20]:
mains = (df['Toaster'] + df['Kettle']).fillna(0).diff().dropna()
appliances = df['Toaster'].fillna(0).diff().dropna()
del df
gc.collect()


Out[20]:
558

In [21]:
# Constrain outputs to [-1,1] because we're using TanH
maximum = appliances.abs().max()
appliances /= maximum
mains_same_scale_as_appliances = mains / maximum

# standardise input
mains = (mains - mains.mean()) / mains.std()

In [11]:
#ax = mains.plot()
#ax = appliances.plot(ax=ax)
#plt.show()

In [12]:
# Build PyBrain dataset
N_OUTPUTS = 1
N_INPUTS = 1
N = len(mains)
ds = SequentialDataSet(N_INPUTS, N_OUTPUTS)
ds.newSequence()
ds.setField('input', pd.DataFrame(mains).values)
ds.setField('target', pd.DataFrame(appliances).values)
del mains
del appliances
del mains_same_scale_as_appliances
gc.collect()


Out[12]:
35

In [13]:
ds.getSequence(0)


/usr/local/lib/python2.7/dist-packages/PyBrain-0.3.3-py2.7.egg/pybrain/datasets/sequential.py:45: DeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
  return self.getField(field)[seq[index]:]
Out[13]:
[array([[  3.85928275e-08],
        [  3.85928275e-08],
        [  3.85928275e-08],
        ..., 
        [  3.85928275e-08],
        [  3.85928275e-08],
        [  3.85928275e-08]]), array([[ 0.],
        [ 0.],
        [ 0.],
        ..., 
        [ 0.],
        [ 0.],
        [ 0.]])]

In [14]:
# Build network
net = RecurrentNetwork()

def lstm_layer_name(i):
    return 'LSTM{:d}'.format(i)

# Add modules
net.addInputModule(LinearLayer(dim=ds.indim, name='in'))
net.addOutputModule(TanhLayer(dim=ds.outdim, name='out'))
net.addModule(TanhLayer(10, name='tanh_input')) 
net.addModule(TanhLayer(10, name='tanh_output')) 
for i, n_cells in enumerate(CONFIG['HIDDEN_LAYERS']):
    net.addModule(LSTMLayer(n_cells, name=lstm_layer_name(i+1), peepholes=CONFIG['PEEPHOLES']))   

# Bias
bias = BiasUnit()
net.addModule(bias)

#c_output_bias = FullConnection(bias, net['out'], name='c_output_bias')
#c_output_bias._setParameters(np.zeros(1))
#net.addConnection(c_output_bias)

c_tanh_input_bias = FullConnection(bias, net['tanh_input'], name='c_tanh_input_bias')
c_tanh_input_bias._params = np.random.uniform(-0.1, 0.1, size=c_tanh_input_bias.paramdim)
net.addConnection(c_tanh_input_bias)

forwards_connection = FullConnection(net['in'], net['tanh_input'], name='c_in_to_tanh')
forwards_connection._params = np.random.uniform(-0.2, 0.2, size=forwards_connection.paramdim)
net.addConnection(forwards_connection)

# Add other connections
n_hidden_layers = len(CONFIG['HIDDEN_LAYERS'])
prev_layer_name = 'tanh_input'
for i in range(n_hidden_layers):
    hidden_layer_i = i + 1
    layer_name = lstm_layer_name(hidden_layer_i)
    
    recurrent_connection = FullConnection(net[layer_name], net[layer_name], name='c_' + layer_name + '_to_' + layer_name)
    recurrent_connection._params = np.random.uniform(-0.05, 0.05, size=recurrent_connection.paramdim)
    net.addRecurrentConnection(recurrent_connection)
    
    #bias_connection = FullConnection(bias, net[layer_name], name='c_' + layer_name + '_bias')
    #bias_connection._params = np.zeros(bias_connection.paramdim)
    #net.addConnection(bias_connection)
    
    forwards_connection = FullConnection(net[prev_layer_name], net[layer_name], name='c_' + prev_layer_name + '_to_' + layer_name)
    forwards_connection._params = np.random.uniform(-0.2, 0.2, size=forwards_connection.paramdim)
    net.addConnection(forwards_connection)
    prev_layer_name = layer_name
    
layer_name = lstm_layer_name(n_hidden_layers)
connect_to_out = FullConnection(net[layer_name], net['out'], name='c_' + layer_name + '_to_out')
connect_to_out._params = np.random.uniform(-0.2, 0.2, size=connect_to_out.paramdim)
net.addConnection(connect_to_out)

net.sortModules()
print(net)


RecurrentNetwork-8
   Modules:
    [<BiasUnit 'BiasUnit-7'>, <LinearLayer 'in'>, <TanhLayer 'tanh_output'>, <TanhLayer 'tanh_input'>, <LSTMLayer 'LSTM1'>, <LSTMLayer 'LSTM2'>, <TanhLayer 'out'>]
   Connections:
    [<FullConnection 'c_LSTM1_to_LSTM2': 'LSTM1' -> 'LSTM2'>, <FullConnection 'c_LSTM2_to_out': 'LSTM2' -> 'out'>, <FullConnection 'c_in_to_tanh': 'in' -> 'tanh_input'>, <FullConnection 'c_tanh_input_bias': 'BiasUnit-7' -> 'tanh_input'>, <FullConnection 'c_tanh_input_to_LSTM1': 'tanh_input' -> 'LSTM1'>]
   Recurrent Connections:
    [<FullConnection 'c_LSTM1_to_LSTM1': 'LSTM1' -> 'LSTM1'>, <FullConnection 'c_LSTM2_to_LSTM2': 'LSTM2' -> 'LSTM2'>]

In [15]:
# define a training method
trainer = CONFIG['TRAINERCLASS'](net, dataset=ds, verbose=True, delta0=0.01)

In [16]:
# carry out the training
net.reset()
# train_errors = []
t0 = time()
EPOCHS = CONFIG['EPOCHS_PER_CYCLE'] * CONFIG['CYCLES']
# trainer.trainUntilConvergence(maxEpochs=EPOCHS, verbose=True)
# start_time = time()
print("Starting training with", EPOCHS, "epochs...")
for i in xrange(CONFIG['CYCLES']):
    trainer.trainEpochs(CONFIG['EPOCHS_PER_CYCLE'])
#    train_errors.append(trainer.testOnData())
    # epoch = (i+1) * CONFIG['EPOCHS_PER_CYCLE']
    # seconds_elapsed = time() - start_time
    # seconds_per_epoch = seconds_elapsed / epoch
    # seconds_remaining = (EPOCHS - epoch) * seconds_per_epoch
    # td_elapsed = timedelta(seconds=seconds_elapsed)
    # td_elapsed_str = str(td_elapsed).split('.')[0]
    # eta = (datetime.now() + timedelta(seconds=seconds_remaining)).time()
    # eta = eta.strftime("%H:%M:%S")
    # print("\r epoch = {}/{}    error = {}  elapsed = {}   ETA = {}"
    #       .format(epoch, EPOCHS, train_errors[-1], td_elapsed_str, eta),
    #       end="")
    # stdout.flush()
print("Finished training.  total seconds =", time() - t0)


Starting training with 100 epochs...
epoch      0  total error   0.00013338   avg weight       0.12037
epoch      1  total error   0.00014616   avg weight       0.12085
epoch      2  total error   0.00030286   avg weight       0.12119
epoch      3  total error   0.00012211   avg weight       0.12136
epoch      4  total error   0.00016324   avg weight        0.1217
epoch      5  total error   0.00011634   avg weight       0.12221
epoch      6  total error   0.00011654   avg weight       0.12302
epoch      7  total error   0.00011354   avg weight       0.12414
epoch      8  total error    0.0001035   avg weight       0.12581
epoch      9  total error   9.6817e-05   avg weight       0.12834
epoch     10  total error   9.1014e-05   avg weight       0.13202
epoch     11  total error   8.8338e-05   avg weight       0.13427
epoch     12  total error   8.5348e-05   avg weight       0.13865
epoch     13  total error   8.6189e-05   avg weight         0.139
epoch     14  total error   8.4605e-05   avg weight       0.14071
epoch     15  total error   8.4255e-05   avg weight       0.14354
epoch     16  total error   8.4603e-05   avg weight        0.1453
epoch     17  total error   8.3755e-05   avg weight       0.14724
epoch     18  total error   8.3838e-05   avg weight       0.14774
epoch     19  total error   8.3594e-05   avg weight       0.15307
epoch     20  total error   8.3468e-05   avg weight       0.15409
epoch     21  total error   8.3405e-05   avg weight       0.15773
epoch     22  total error   8.3259e-05   avg weight       0.16336
epoch     23  total error   8.3155e-05   avg weight       0.16964
epoch     24  total error   8.3059e-05   avg weight       0.17884
epoch     25  total error   8.2958e-05   avg weight       0.18604
epoch     26  total error   8.2811e-05   avg weight       0.19771
epoch     27  total error   8.2651e-05   avg weight       0.21414
epoch     28  total error   8.2471e-05   avg weight       0.23261
epoch     29  total error   8.2272e-05   avg weight       0.25487
epoch     30  total error    8.206e-05   avg weight       0.28132
epoch     31  total error   8.1807e-05   avg weight       0.31692
epoch     32  total error   8.1527e-05   avg weight       0.35652
epoch     33  total error   8.1212e-05   avg weight       0.41033
epoch     34  total error   8.0882e-05   avg weight       0.45712
epoch     35  total error   8.0507e-05   avg weight       0.51704
epoch     36  total error   7.9928e-05   avg weight       0.56382
epoch     37  total error   7.9061e-05   avg weight       0.62086
epoch     38  total error   7.9214e-05   avg weight        0.6973
epoch     39  total error   7.5995e-05   avg weight        0.7383
epoch     40  total error   8.8376e-05   avg weight       0.78097
epoch     41  total error   7.6008e-05   avg weight       0.79798
epoch     42  total error   7.5388e-05   avg weight       0.83094
epoch     43  total error    7.515e-05   avg weight        0.8323
epoch     44  total error   7.3028e-05   avg weight       0.88289
epoch     45  total error   7.2603e-05   avg weight       0.91703
epoch     46  total error   7.2051e-05   avg weight        0.9508
epoch     47  total error   7.0194e-05   avg weight        1.0085
epoch     48  total error   6.9105e-05   avg weight        1.0736
epoch     49  total error   6.8324e-05   avg weight        1.1356
epoch     50  total error   6.6412e-05   avg weight        1.1975
epoch     51  total error    6.488e-05   avg weight        1.2706
epoch     52  total error   6.4088e-05   avg weight        1.3142
epoch     53  total error   6.2475e-05   avg weight        1.3487
epoch     54  total error   6.1504e-05   avg weight        1.3939
epoch     55  total error   6.0465e-05   avg weight         1.426
epoch     56  total error   5.9693e-05   avg weight        1.4688
epoch     57  total error   5.9357e-05   avg weight        1.5128
epoch     58  total error   5.8333e-05   avg weight        1.5592
epoch     59  total error   5.7558e-05   avg weight        1.6181
epoch     60  total error   5.6784e-05   avg weight        1.6894
epoch     61  total error   5.6135e-05   avg weight        1.7461
epoch     62  total error   5.5992e-05   avg weight        1.7902
epoch     63  total error   5.5228e-05   avg weight        1.8093
epoch     64  total error   5.4821e-05   avg weight        1.8439
epoch     65  total error   5.4306e-05   avg weight        1.8821
epoch     66  total error   5.3735e-05   avg weight        1.9251
epoch     67  total error   5.3206e-05   avg weight        1.9439
epoch     68  total error   5.2773e-05   avg weight        1.9736
epoch     69  total error   5.2235e-05   avg weight        2.0127
epoch     70  total error   5.1514e-05   avg weight        2.0627
epoch     71  total error   5.1156e-05   avg weight        2.0657
epoch     72  total error   5.1172e-05   avg weight        2.0897
epoch     73  total error   5.0348e-05   avg weight        2.1015
epoch     74  total error   5.0303e-05   avg weight        2.1035
epoch     75  total error   4.9604e-05   avg weight        2.1282
epoch     76  total error   4.9004e-05   avg weight        2.1549
epoch     77  total error   4.8576e-05   avg weight        2.1813
epoch     78  total error   4.8432e-05   avg weight        2.2197
epoch     79  total error   4.8287e-05   avg weight        2.2245
epoch     80  total error   4.7355e-05   avg weight        2.2341
epoch     81  total error   4.6894e-05   avg weight        2.2623
epoch     82  total error    4.669e-05   avg weight        2.2953
epoch     83  total error   4.6324e-05   avg weight        2.2999
epoch     84  total error   4.5794e-05   avg weight        2.3284
epoch     85  total error   4.5158e-05   avg weight          2.36
epoch     86  total error   0.00011102   avg weight        2.3992
epoch     87  total error     4.49e-05   avg weight        2.4003
epoch     88  total error   6.3968e-05   avg weight        2.4189
epoch     89  total error   4.4577e-05   avg weight        2.4296
epoch     90  total error   4.3954e-05   avg weight        2.4495
epoch     91  total error   5.8784e-05   avg weight         2.473
epoch     92  total error   4.3626e-05   avg weight        2.4943
epoch     93  total error    4.313e-05   avg weight        2.5173
epoch     94  total error   5.3817e-05   avg weight         2.549
epoch     95  total error    4.277e-05   avg weight        2.5722
epoch     96  total error   4.2388e-05   avg weight        2.5873
epoch     97  total error   4.2136e-05   avg weight        2.6187
epoch     98  total error    4.174e-05   avg weight        2.6458
epoch     99  total error   4.1378e-05   avg weight        2.6813
Finished training.  total seconds = 65443.7497811

In [22]:
# Disaggregate!
START = "2014-01-01"
END = "2014-01-03"
print("Starting disaggregation...")
net.reset()
estimates = pd.Series(index=appliances[START:END].index)
for date, mains_value in mains[START:END].iteritems():
    estimates[date] = net.activate(mains_value)


Starting disaggregation...

In [23]:
estimates.plot()
plt.show()



In [24]:
mains[START:END].plot()
plt.show()



In [25]:
appliances[START:END].plot()
plt.show()



In [26]:
ax = estimates[START:END].cumsum().plot(label='estimates')
ax = mains_same_scale_as_appliances[START:END].cumsum().plot(ax=ax, label='aggregate')
ax = appliances[START:END].cumsum().plot(ax=ax)
plt.legend()
plt.show()



In [27]:
estimates.cumsum().to_hdf('neuronilm_estimates_{:03d}.hdf'.format(CONFIG['EXPERIMENT_NUMBER']), 'df')

In [ ]: