├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── autocorrelation-learning-example.ipynb ├── requirements.txt ├── setup.py ├── tests ├── features │ └── test_irregular_prediction.py ├── layers │ ├── test_input_lstm_layer.py │ ├── test_lstm_layer.py │ ├── test_multi_layer_perceptron.py │ ├── test_output_lstm_layer.py │ └── test_regression_layer.py └── trainer │ └── test_automated_training_monitor.py ├── timeflow-examples.ipynb └── timeflow ├── __init__.py ├── features ├── __init__.py └── irregular_prediction.py ├── layers ├── __init__.py ├── input_lstm_layer.py ├── lstm_layer.py ├── multi_layer_perceptron.py ├── nn_layer.py ├── output_lstm_layer.py └── regression_layer.py ├── placeholders ├── __init__.py └── prediction.py ├── trainer ├── __init__.py └── automated_training_monitor.py └── utils ├── __init__.py ├── autocorr.py ├── metrics.py └── plotting.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | 91 | # Adding tmp and data folder to gitignore 92 | /tmp/ 93 | /data/ 94 | data/ 95 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | 5 | before_install: 6 | - sudo apt-get update 7 | - wget http://launchpadlibrarian.net/151925896/libc6_2.17-0ubuntu5.1_amd64.deb 8 | - sudo dpkg -i libc6_2.17-0ubuntu5.1_amd64.deb 9 | 10 | 11 | install: 12 | - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then 13 | wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh; 14 | else 15 | wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; 16 | fi 17 | - bash miniconda.sh -b -p $HOME/miniconda 18 | - export PATH="$HOME/miniconda/bin:$PATH" 19 | - hash -r 20 | - conda config --set always_yes yes --set changeps1 no 21 | - conda update -q conda 22 | # Useful for debugging any issues with conda 23 | - conda info -a 24 | - conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib pandas pytest h5py 25 | - source activate test-environment 26 | - pip install pytest-cov pytest-xdist coverage==3.7.1 27 | - pip install --user codecov 28 | - "pip install -r requirements.txt" 29 | # install TensorFlow 30 | - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then 31 | pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.0.0-cp27-none-linux_x86_64.whl; 32 | elif [[ "$TRAVIS_PYTHON_VERSION" == "3.4" ]]; then 33 | pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.0.0-cp34-cp34m-linux_x86_64.whl; 34 | fi 35 | - python setup.py install 36 | script: 37 | - PYTHONPATH=$PWD:$PYTHONPATH py.test --cov timeflow 38 | 39 | after_success: 40 | - codecov 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Abhishek Malali 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/abhishekmalali/TimeFlow.svg?branch=master)](https://travis-ci.org/abhishekmalali/TimeFlow) [![codecov](https://codecov.io/gh/abhishekmalali/TimeFlow/branch/master/graph/badge.svg)](https://codecov.io/gh/abhishekmalali/TimeFlow) 2 | # TimeFlow 3 | Tensorflow for Time Series Applications 4 | 5 | **TimeFlow** is a library for building tensorflow models for time series problems. It can be used for time series prediction as well as time series classification. The key features of this library are 6 | 7 | * Allows stacking of pre built layers. The layers currently available are 8 | * LSTM(Long Short Term Memory) 9 | * Regression 10 | * Deep Neural networks 11 | * Automated training monitor 12 | * Feature generation for irregular time series 13 | * Other utility functions to facilitate building models 14 | 15 | ### Installation 16 | Preinstall Tensorflow before installing TimeFlow. To install the package via github, 17 | ```{bash} 18 | git clone https://github.com/abhishekmalali/TimeFlow.git 19 | cd TimeFlow 20 | python setup.py install 21 | ``` 22 | 23 | ###Notes 24 | * Auto correlation reduction network is now included in the package. 25 | * The library works on Tensorflow v1.0 26 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | pytest 3 | matplotlib 4 | pytest-cov 5 | seaborn 6 | coverage==3.7.1 7 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | from setuptools import setup 4 | from setuptools import find_packages 5 | 6 | setup(name='timeflow', 7 | version='0.1', 8 | description='Library for using tensorflow for time series', 9 | url='https://github.com/abhishekmalali/TimeFlow', 10 | author='Abhishek Malali, Pavlos Protopapas', 11 | author_email='anon@anon.com', 12 | license='MIT', 13 | include_package_data=True, 14 | packages=find_packages(), 15 | install_requires=['numpy', 'pytest', 'pytest-cov', 'matplotlib']) 16 | -------------------------------------------------------------------------------- /tests/features/test_irregular_prediction.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import timeflow as tflow 3 | import numpy as np 4 | 5 | 6 | def irregular_prediction_test(): 7 | size = 100 8 | time_samples = sorted(np.random.normal(size=size)) 9 | samples = np.random.normal(size=size) 10 | features, response, time_vector = \ 11 | tflow.features.irregular_prediction(time_samples, samples) 12 | return features, response, time_vector 13 | 14 | 15 | def test_irregular_prediction(): 16 | features, response, time_vector = irregular_prediction_test() 17 | assert features.shape == (99, 4) 18 | assert response.shape == (99, 1) 19 | assert len(time_vector) == 99 20 | -------------------------------------------------------------------------------- /tests/layers/test_input_lstm_layer.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import timeflow as tflow 3 | 4 | 5 | def input_lstm_layer_test(): 6 | input_dim = 10 7 | batch_size = 10 8 | test_placeholder = tflow.placeholders.prediction.input_placeholder(input_dim) 9 | batch_test_placeholder = tflow.placeholders.prediction.input_batch_placeholder(input_dim, batch_size) 10 | in_layer = tflow.layers.InputLSTMLayer(test_placeholder, input_dim, batch_input=False) 11 | in_layer_batch = tflow.layers.InputLSTMLayer(batch_test_placeholder, input_dim, batch_input=True) 12 | return in_layer.get_outputs(), in_layer_batch.get_outputs() 13 | 14 | 15 | def test_input_lstm_layer(): 16 | in_layer_out, in_layer_batch_out = input_lstm_layer_test() 17 | assert len(in_layer_out.get_shape()) == 3 18 | assert len(in_layer_batch_out.get_shape()) == 3 19 | -------------------------------------------------------------------------------- /tests/layers/test_lstm_layer.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import timeflow as tflow 3 | 4 | 5 | def lstm_layer_test(): 6 | input_dim = 10 7 | batch_size = 10 8 | hidden_layer_size = 10 9 | test_placeholder = tflow.placeholders.prediction.input_placeholder(input_dim) 10 | batch_test_placeholder = tflow.placeholders.prediction.input_batch_placeholder(input_dim, batch_size) 11 | in_layer = tflow.layers.InputLSTMLayer(test_placeholder, input_dim, batch_input=False) 12 | in_layer_batch = tflow.layers.InputLSTMLayer(batch_test_placeholder, input_dim, batch_input=True) 13 | lstm_layer = tflow.layers.LSTMLayer(input_dim, hidden_layer_size, in_layer) 14 | lstm_layer_batch = tflow.layers.LSTMLayer(input_dim, hidden_layer_size, in_layer_batch) 15 | return lstm_layer.get_outputs(), lstm_layer_batch.get_outputs(), hidden_layer_size, batch_size 16 | 17 | 18 | def test_lstm_layer(): 19 | lstm_layer_out, lstm_layer_batch_out, hsize, bsize = lstm_layer_test() 20 | shape = lstm_layer_out.get_shape() 21 | assert len(lstm_layer_out.get_shape()) == 3 22 | # Checking if hidden size is accurate for non batched inputs 23 | assert int(shape[2]) == hsize 24 | shape = lstm_layer_batch_out.get_shape() 25 | assert len(lstm_layer_batch_out.get_shape()) == 4 26 | # Checking if hidden size is accurate if input and output are batched 27 | assert int(shape[3]) == hsize 28 | # Checking if batch size is accurate 29 | assert int(shape[0]) == bsize 30 | -------------------------------------------------------------------------------- /tests/layers/test_multi_layer_perceptron.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import timeflow as tflow 3 | 4 | 5 | def mulitnnlayer_test(): 6 | input_dim = 10 7 | output_dim = 10 8 | test_placeholder = tflow.placeholders.prediction.input_placeholder(input_dim) 9 | in_layer = tflow.layers.InputLSTMLayer(test_placeholder, input_dim, batch_input=False) 10 | multinnlayer = tflow.layers.MultiNNLayer(input_dim, output_dim, 11 | in_layer) 12 | multinnlayer_cls = tflow.layers.MultiNNLayer(input_dim, output_dim, 13 | in_layer, 14 | outfunc='classification') 15 | return multinnlayer.get_outputs(), multinnlayer_cls.get_outputs() 16 | 17 | 18 | def test_multinnlayer(): 19 | regout, clsout = mulitnnlayer_test() 20 | assert int(regout.get_shape()[2]) == 10 21 | assert int(clsout.get_shape()[2]) == 10 22 | -------------------------------------------------------------------------------- /tests/layers/test_output_lstm_layer.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import timeflow as tflow 3 | 4 | 5 | def output_lstm_layer_test(): 6 | input_dim = 10 7 | output_dim = 10 8 | test_placeholder = tflow.placeholders.prediction.input_placeholder(input_dim) 9 | in_layer = tflow.layers.InputLSTMLayer(test_placeholder, input_dim, batch_input=False) 10 | out_layer = tflow.layers.OutputLSTMLayer(output_dim, in_layer, batch_output=False) 11 | out_layer_batch = tflow.layers.OutputLSTMLayer(output_dim, in_layer, batch_output=True) 12 | return out_layer.get_outputs(), out_layer_batch.get_outputs() 13 | 14 | 15 | def test_output_lstm_layer(): 16 | out_layer_out, out_layer_batch_out = output_lstm_layer_test() 17 | assert len(out_layer_batch_out.get_shape()) == 3 18 | assert len(out_layer_out.get_shape()) == 2 19 | -------------------------------------------------------------------------------- /tests/layers/test_regression_layer.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import timeflow as tflow 3 | 4 | 5 | def regression_layer_test(): 6 | input_dim = 10 7 | output_dim = 20 8 | test_placeholder = tflow.placeholders.prediction.input_placeholder(input_dim) 9 | in_layer = tflow.layers.InputLSTMLayer(test_placeholder, input_dim, batch_input=False) 10 | reg_layer = tflow.layers.RegressionLayer(input_dim, output_dim, in_layer) 11 | return reg_layer.get_outputs() 12 | 13 | 14 | def test_regression_layer(): 15 | regout = regression_layer_test() 16 | assert int(regout.get_shape()[2]) == 20 17 | assert len(regout.get_shape()) == 3 18 | -------------------------------------------------------------------------------- /tests/trainer/test_automated_training_monitor.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import timeflow as tflow 3 | import numpy as np 4 | import tensorflow as tf 5 | 6 | 7 | def run_automated_monitor(): 8 | size = 300 9 | time_samples = sorted(np.random.normal(size=size)) 10 | samples = np.random.normal(size=size) 11 | X, Y, time_vector = \ 12 | tflow.features.irregular_prediction(time_samples, samples) 13 | num_training_points = 100 14 | num_validation_points = 100 15 | X_train = X[:num_training_points, :] 16 | Y_train = Y[:num_training_points, :] 17 | X_valid = X[num_training_points:num_training_points+num_validation_points, :] 18 | Y_valid = Y[num_training_points:num_training_points+num_validation_points, :] 19 | X_test = X[num_training_points+num_validation_points:, :] 20 | Y_test = Y[num_training_points+num_validation_points:, :] 21 | input_size = 4 22 | hidden_size = 10 23 | output_size = 1 24 | with tf.variable_scope('Input'): 25 | inputs = tflow.placeholders.prediction.input_placeholder(input_size) 26 | with tf.variable_scope('Input_LSTM_Layer'): 27 | input_lstm_layer = tflow.layers.InputLSTMLayer(inputs, input_size) 28 | with tf.variable_scope('LSTM_Layer'): 29 | lstm_layer = tflow.layers.LSTMLayer(input_size, hidden_size, input_lstm_layer) 30 | with tf.variable_scope('Regression_Layer'): 31 | reg_layer = tflow.layers.RegressionLayer(hidden_size, output_size, lstm_layer) 32 | with tf.variable_scope('Output_LSTM_Layer'): 33 | output_layer = tflow.layers.OutputLSTMLayer(output_size, reg_layer) 34 | y = tflow.placeholders.prediction.output_placeholder(output_size) 35 | outputs = output_layer.get_outputs() 36 | # Defining MSE as the loss function 37 | with tf.variable_scope('RMSE'): 38 | loss_func = tflow.utils.metrics.RMSE(outputs, y) 39 | train_step = tf.train.RMSPropOptimizer(learning_rate=0.05).minimize(loss_func) 40 | sess = tf.InteractiveSession() 41 | sess.run(tf.initialize_all_variables()) 42 | monitor = tflow.trainer.AutomatedTrainingMonitor(inputs, y, X_train, Y_train, 43 | train_step, loss_func, sess, training_steps=500, 44 | validation_input=X_valid, validation_output=Y_valid, 45 | early_stopping_rounds=60) 46 | monitor.train() 47 | return 48 | 49 | 50 | def test_automated_training_monitor(): 51 | run_automated_monitor() 52 | -------------------------------------------------------------------------------- /timeflow/__init__.py: -------------------------------------------------------------------------------- 1 | import layers as layers 2 | import placeholders as placeholders 3 | import trainer as trainer 4 | import features as features 5 | import utils as utils 6 | -------------------------------------------------------------------------------- /timeflow/features/__init__.py: -------------------------------------------------------------------------------- 1 | from irregular_prediction import * 2 | -------------------------------------------------------------------------------- /timeflow/features/irregular_prediction.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | # Function to generate the irregular time prediction features 5 | def irregular_prediction(time_samples, samples): 6 | """Initialize input placeholder for prediction networks 7 | 8 | Parameters 9 | ---------- 10 | time_samples : np.array 11 | Time samples 12 | samples : np.array 13 | Signal samples 14 | 15 | Returns 16 | ---------- 17 | np.array 18 | Data with features 19 | np.array 20 | Response 21 | np.array 22 | Time vector 23 | 24 | """ 25 | delta_t = [0] + list(np.array(time_samples[1:]) - np.array(time_samples[:-1])) 26 | derivative = np.divide(np.diff(samples), np.diff(time_samples)) 27 | first_derivative = np.lib.pad(derivative, (1, 0), 'constant', 28 | constant_values=(0, 0)) 29 | second_derivative = np.lib.pad(np.diff(first_derivative), (1, 0), 30 | 'constant', constant_values=(0, 0)) 31 | data_mat = np.matrix([list(samples), delta_t, list(first_derivative), 32 | list(second_derivative)]).T 33 | data_mat = data_mat[:-1, :] 34 | resp_mat = np.matrix(np.roll(samples, -1)[:-1]).T 35 | time_vec = time_samples[1:] 36 | return data_mat, resp_mat, time_vec 37 | -------------------------------------------------------------------------------- /timeflow/layers/__init__.py: -------------------------------------------------------------------------------- 1 | # Importing the dependencies 2 | from os.path import dirname as _dirname, basename as _basename,\ 3 | isfile as _isfile 4 | import glob as _glob 5 | 6 | exec('\n'.join(map(lambda name: "from ." + name + " import *", 7 | [_basename(f)[:-3] for f in 8 | _glob.glob(_dirname(__file__) + "/*.py") 9 | if _isfile(f) and not _basename(f).startswith('_')]))) 10 | -------------------------------------------------------------------------------- /timeflow/layers/input_lstm_layer.py: -------------------------------------------------------------------------------- 1 | from .nn_layer import NNLayer 2 | import tensorflow as tf 3 | 4 | __all__ = ['InputLSTMLayer'] 5 | 6 | 7 | class InputLSTMLayer(NNLayer): 8 | """ 9 | This layer expands dimensions inorder for the LSTM to function. 10 | The input data has a shape of (?,input_dimensions) and the output 11 | for this layer is a tensor of the shape (1, ?, input_dimensions) 12 | """ 13 | def __init__(self, X, input_dim, batch_input=False): 14 | """Initialize InputLSTMLayer class 15 | 16 | Parameters 17 | ---------- 18 | X : tf.Tensor 19 | Input tensor to be transformed 20 | input_dim : integer 21 | Input dimensions 22 | batch_input : boolean (default False) 23 | If input is batch 24 | """ 25 | self.X = X 26 | self.input_dim = input_dim 27 | self.batch_input = batch_input 28 | 29 | def get_outputs(self): 30 | """Generate outputs for InputLSTMLayer class 31 | 32 | Returns 33 | ---------- 34 | tf.Tensor 35 | Transformed input tensor 36 | """ 37 | if self.batch_input is True: 38 | return tf.expand_dims(self.X, 0)[0, :, :, :] 39 | else: 40 | return tf.expand_dims(self.X, 0) 41 | -------------------------------------------------------------------------------- /timeflow/layers/lstm_layer.py: -------------------------------------------------------------------------------- 1 | from .nn_layer import NNLayer 2 | import tensorflow as tf 3 | __all__ = ['LSTMLayer'] 4 | 5 | 6 | class LSTMLayer(NNLayer): 7 | """ 8 | This layer implements the LSTM cell. 9 | """ 10 | def __init__(self, input_dim, hidden_layer_size, input_layer): 11 | """Initialize LSTMLayer class. 12 | 13 | Parameters 14 | ---------- 15 | input_dim : integer 16 | Input dimensions 17 | hidden_layer_size : integer 18 | Size of the memory in LSTM cell 19 | input_layer : layers object 20 | Preceding layers object 21 | 22 | """ 23 | self.input_dim = input_dim 24 | self.hidden_layer_size = hidden_layer_size 25 | self.inputs = input_layer.get_outputs() 26 | 27 | # Initializing the weights and biases 28 | self.Wi = tf.Variable(tf.zeros([self.input_dim, self.hidden_layer_size])) 29 | self.Ui = tf.Variable(tf.zeros([self.hidden_layer_size, self.hidden_layer_size])) 30 | self.bi = tf.Variable(tf.zeros([self.hidden_layer_size])) 31 | 32 | self.Wf = tf.Variable(tf.zeros([self.input_dim, self.hidden_layer_size])) 33 | self.Uf = tf.Variable(tf.zeros([self.hidden_layer_size, self.hidden_layer_size])) 34 | self.bf = tf.Variable(tf.zeros([self.hidden_layer_size])) 35 | 36 | self.Wog = tf.Variable(tf.zeros([self.input_dim, self.hidden_layer_size])) 37 | self.Uog = tf.Variable(tf.zeros([self.hidden_layer_size, self.hidden_layer_size])) 38 | self.bog = tf.Variable(tf.zeros([self.hidden_layer_size])) 39 | 40 | self.Wc = tf.Variable(tf.zeros([self.input_dim, self.hidden_layer_size])) 41 | self.Uc = tf.Variable(tf.zeros([self.hidden_layer_size, self.hidden_layer_size])) 42 | self.bc = tf.Variable(tf.zeros([self.hidden_layer_size])) 43 | 44 | self.initial_hidden = tf.zeros([1, self.hidden_layer_size]) 45 | self.initial_hidden= tf.stack([self.initial_hidden, self.initial_hidden]) 46 | 47 | def forward_step(self, previous_memory, input_): 48 | """ 49 | Generates the next forward LSTM operation. 50 | 51 | Parameters 52 | ---------- 53 | previous_memory : list 54 | List of the previous memory and hidden output tensors 55 | input_ : tf.tensor 56 | Input tensor 57 | 58 | Returns 59 | ---------- 60 | list 61 | New updated memory and hidden output tensors 62 | 63 | """ 64 | previous_hidden_state, c_prev = tf.unstack(previous_memory) 65 | # Input gate 66 | i= tf.sigmoid( 67 | tf.matmul(input_,self.Wi)+tf.matmul(previous_hidden_state,self.Ui) + self.bi 68 | ) 69 | # Forget Gate 70 | f= tf.sigmoid( 71 | tf.matmul(input_,self.Wf)+tf.matmul(previous_hidden_state,self.Uf) + self.bf 72 | ) 73 | # Output Gate 74 | o= tf.sigmoid( 75 | tf.matmul(input_,self.Wog)+tf.matmul(previous_hidden_state,self.Uog) + self.bog 76 | ) 77 | # New Memory Cell 78 | c_= tf.nn.tanh( 79 | tf.matmul(input_,self.Wc)+tf.matmul(previous_hidden_state,self.Uc) + self.bc 80 | ) 81 | # Final Memory cell 82 | c= f*c_prev + i*c_ 83 | 84 | # Current Hidden state 85 | current_hidden_state = o*tf.nn.tanh(c) 86 | return tf.stack([current_hidden_state,c]) 87 | 88 | # Function for getting all hidden state. 89 | def get_outputs(self): 90 | """ 91 | Iterates through time/ sequence to get all hidden states. 92 | 93 | Returns 94 | ---------- 95 | tf.Tensor 96 | Output tensor 97 | 98 | """ 99 | # Getting all hidden state throuh time 100 | inputs_shape = self.inputs.get_shape() 101 | if inputs_shape[0] == 1: 102 | self.inputs = tf.expand_dims(self.inputs[0, :, :], 1) 103 | all_hidden_states = tf.scan(self.forward_step, 104 | self.inputs, 105 | initializer=self.initial_hidden, 106 | name='states') 107 | all_hidden_states = all_hidden_states[:, 0, :, :] 108 | else: 109 | all_hidden_states = tf.map_fn(self.get_batch_outputs, 110 | self.inputs) 111 | return all_hidden_states 112 | 113 | def get_batch_outputs(self, single_input): 114 | """ 115 | Iterates through time/ sequence to get all hidden states for all 116 | batches. 117 | 118 | Returns 119 | ---------- 120 | tf.Tensor 121 | Output tensor 122 | 123 | """ 124 | single_input = tf.expand_dims(single_input, 1) 125 | all_hidden_states = tf.scan(self.forward_step, 126 | single_input, 127 | initializer=self.initial_hidden, 128 | name='states') 129 | all_hidden_states = all_hidden_states[:, 0, :, :] 130 | return all_hidden_states 131 | -------------------------------------------------------------------------------- /timeflow/layers/multi_layer_perceptron.py: -------------------------------------------------------------------------------- 1 | from .nn_layer import NNLayer 2 | import tensorflow as tf 3 | __all__ = ['MultiNNLayer'] 4 | 5 | 6 | class MultiNNLayer(NNLayer): 7 | """ 8 | Layer implements the Multiple layer neural network. 9 | """ 10 | def __init__(self, input_size, output_size, input_layer, layers=2, 11 | layer_size=[10, 10], func='sigmoid', outfunc='regression'): 12 | """Initialize MultiNNLayer class 13 | 14 | Parameters 15 | ---------- 16 | input_size : integer 17 | Input dimensions 18 | output_size : integer 19 | Output dimensions 20 | input_layer : layers object 21 | Preceding layers object 22 | layers : integer (default 2) 23 | Number of layers 24 | layer_size : list (default [10, 10]) 25 | Size of layers 26 | func : string (default 'sigmoid') 27 | Layer function. Available choices are 'sigmoid', 'tanh' and 'relu' 28 | outfunc : string (default 'regression') 29 | Output type. Available choices are 'regression' and 'classification' 30 | 31 | """ 32 | if layers != len(layer_size): 33 | raise ValueError("Layer information incorrect") 34 | self.inputs = input_layer.get_outputs() 35 | self.layers = layers 36 | self.layer_size = layer_size 37 | self.func = {'sigmoid': tf.nn.sigmoid, 38 | 'tanh': tf.nn.tanh, 39 | 'relu': tf.nn.relu}[func] 40 | self.outfunc = outfunc 41 | self.weights = {} 42 | self.biases = {} 43 | self.next_input = input_size 44 | self.next_output = layer_size[0] 45 | for i in range(layers): 46 | self.weights['h'+str(i+1)] = tf.Variable(tf.truncated_normal([self.next_input, 47 | self.next_output],mean=0,stddev=.01)) 48 | self.biases['b'+str(i+1)] = tf.Variable(tf.truncated_normal([self.next_output],mean=0,stddev=.01)) 49 | self.next_input = layer_size[i] 50 | if i+1 >= layers: 51 | self.next_output = output_size 52 | else: 53 | self.next_output = layer_size[i+1] 54 | self.weights['out'] = tf.Variable(tf.truncated_normal([self.next_input, 55 | self.next_output],mean=0,stddev=.01)) 56 | self.biases['out'] = tf.Variable(tf.truncated_normal([self.next_output],mean=0,stddev=.01)) 57 | 58 | def get_output(self, input_): 59 | """ 60 | Generates the output for a single step 61 | 62 | Parameters 63 | ---------- 64 | input_ : tf.tensor 65 | Input tensor 66 | 67 | Returns 68 | ---------- 69 | tf.tensor 70 | Output tensor 71 | 72 | """ 73 | variables = {} 74 | for i in range(self.layers): 75 | if i == 0: 76 | variables[i] = tf.add(tf.matmul(input_, self.weights['h'+str(i+1)]), self.biases['b'+str(i+1)]) 77 | variables[i] = self.func(variables[i]) 78 | else: 79 | variables[i] = tf.add(tf.matmul(variables[i-1], self.weights['h'+str(i+1)]), self.biases['b'+str(i+1)]) 80 | variables[i] = self.func(variables[i]) 81 | if self.outfunc == 'regression': 82 | output = tf.matmul(variables[self.layers-1], self.weights['out']) + self.biases['out'] 83 | elif self.outfunc == 'classification': 84 | output = tf.nn.softmax(tf.matmul(variables[self.layers-1], self.weights['out']) + self.biases['out']) 85 | else: 86 | raise ValueError("Wrong output function provided") 87 | return output 88 | 89 | def get_outputs(self): 90 | """ 91 | Iterates through all inputs to generate outputs 92 | 93 | Returns 94 | ---------- 95 | tf.Tensor 96 | Output tensor 97 | 98 | """ 99 | all_outputs = tf.map_fn(self.get_output, self.inputs) 100 | return all_outputs 101 | -------------------------------------------------------------------------------- /timeflow/layers/nn_layer.py: -------------------------------------------------------------------------------- 1 | __all__ = [] 2 | 3 | class NNLayer(): 4 | """NNLayer class 5 | 6 | Base class for Neural Network layers 7 | """ 8 | def get_outputs(self): 9 | """ 10 | Function for generating outputs considering the entire network 11 | structure for a layer. 12 | """ 13 | return NotImplementedError 14 | 15 | def reset_state(self): 16 | """ 17 | Function for resetting the state parameters in case the network 18 | is to be reset to initial network states. 19 | """ 20 | return NotImplementedError 21 | -------------------------------------------------------------------------------- /timeflow/layers/output_lstm_layer.py: -------------------------------------------------------------------------------- 1 | from .nn_layer import NNLayer 2 | import tensorflow as tf 3 | __all__ = ['OutputLSTMLayer'] 4 | 5 | 6 | class OutputLSTMLayer(NNLayer): 7 | """ 8 | This layer squashes dimensions for the LSTM output to be usable. 9 | The input data has a shape of (1, ?, output_dimensions) and the output 10 | for this layer is a tensor of the shape (?, output_dimensions). 11 | If output is batched, the tensor is not squashed. 12 | """ 13 | def __init__(self, output_dim, input_layer, batch_output=False): 14 | """Initialize InputLSTMLayer class 15 | 16 | Parameters 17 | ---------- 18 | output_dim : integer 19 | Output dimensions 20 | input_layer : layers object 21 | Preceding layers object 22 | batch_output : boolean (default) 23 | If output was batched 24 | """ 25 | self.output_dim = output_dim 26 | self.outputs = input_layer.get_outputs() 27 | self.batch_output = batch_output 28 | 29 | def get_outputs(self): 30 | """Generate outputs for InputLSTMLayer class 31 | 32 | Returns 33 | ---------- 34 | tf.Tensor 35 | Transformed output tensor 36 | """ 37 | if self.batch_output is True: 38 | return self.outputs 39 | else: 40 | return self.outputs[:, 0, :] 41 | -------------------------------------------------------------------------------- /timeflow/layers/regression_layer.py: -------------------------------------------------------------------------------- 1 | from .nn_layer import NNLayer 2 | import tensorflow as tf 3 | __all__ = ['RegressionLayer'] 4 | 5 | 6 | class RegressionLayer(NNLayer): 7 | """ 8 | Layer implements the Simple regression. 9 | """ 10 | def __init__(self, input_size, output_size, input_layer): 11 | """Initialize RegressionLayer class 12 | 13 | Parameters 14 | ---------- 15 | input_size : integer 16 | Input dimensions 17 | output_size : integer 18 | Output dimensions 19 | input_layer : layers object 20 | Preceding layers object 21 | 22 | """ 23 | self.inputs = input_layer.get_outputs() 24 | self.input_size = input_size 25 | self.output_size = output_size 26 | self.Wo = tf.Variable(tf.truncated_normal([self.input_size, self.output_size], mean=0, stddev=.01)) 27 | self.bo = tf.Variable(tf.truncated_normal([self.output_size], mean=0, stddev=.01)) 28 | 29 | def get_output(self, input_): 30 | """ 31 | Generates the output for a single step 32 | 33 | Parameters 34 | ---------- 35 | input_ : tf.tensor 36 | Input tensor 37 | 38 | Returns 39 | ---------- 40 | tf.tensor 41 | Output tensor 42 | 43 | """ 44 | output = tf.matmul(input_, self.Wo) + self.bo 45 | return output 46 | 47 | def get_outputs(self): 48 | """ 49 | Iterates through all inputs to generate outputs 50 | 51 | Returns 52 | ---------- 53 | tf.Tensor 54 | Output tensor 55 | 56 | """ 57 | if len(self.inputs.get_shape()) == 3: 58 | all_outputs = tf.map_fn(self.get_output, self.inputs) 59 | else: 60 | all_outputs = tf.map_fn(self.get_batch_outputs, self.inputs) 61 | return all_outputs 62 | 63 | def get_batch_outputs(self, single_input): 64 | """ 65 | Iterates through all inputs to generate outputs for all batches 66 | 67 | Returns 68 | ---------- 69 | tf.Tensor 70 | Output tensor 71 | 72 | """ 73 | all_single_outputs = tf.map_fn(self.get_output, single_input) 74 | return all_single_outputs 75 | -------------------------------------------------------------------------------- /timeflow/placeholders/__init__.py: -------------------------------------------------------------------------------- 1 | import prediction 2 | -------------------------------------------------------------------------------- /timeflow/placeholders/prediction.py: -------------------------------------------------------------------------------- 1 | # Input and output placeholders for prediction placeholders 2 | import tensorflow as tf 3 | 4 | 5 | def input_placeholder(input_dim, name='inputs'): 6 | """Initialize input placeholder for prediction networks 7 | 8 | Parameters 9 | ---------- 10 | input_dim : integer 11 | Input dimensions 12 | name : string 13 | Placeholder name 14 | 15 | Returns 16 | ---------- 17 | tf.placeholder 18 | Input placeholder 19 | 20 | """ 21 | input = tf.placeholder(tf.float32, shape=[None, input_dim], 22 | name=name) 23 | return input 24 | 25 | 26 | def input_batch_placeholder(input_dim, batch_size, name='inputs'): 27 | """Initialize input placeholder for prediction networks for batch training 28 | 29 | Parameters 30 | ---------- 31 | input_dim : integer 32 | Input dimensions 33 | batch_size : integer 34 | Input dimensions 35 | name : string 36 | Placeholder name 37 | 38 | Returns 39 | ---------- 40 | tf.placeholder 41 | Input placeholder 42 | 43 | """ 44 | input = tf.placeholder(tf.float32, shape=[batch_size, None, input_dim], 45 | name=name) 46 | return input 47 | 48 | 49 | def output_placeholder(output_dim, name='outputs'): 50 | """Initialize output placeholder for prediction networks 51 | 52 | Parameters 53 | ---------- 54 | output_dim : integer 55 | Input dimensions 56 | name : string 57 | Placeholder name 58 | 59 | Returns 60 | ---------- 61 | tf.placeholder 62 | Input placeholder 63 | 64 | """ 65 | output = tf.placeholder(tf.float32, shape=[None, output_dim], 66 | name=name) 67 | return output 68 | -------------------------------------------------------------------------------- /timeflow/trainer/__init__.py: -------------------------------------------------------------------------------- 1 | # Importing the dependencies 2 | from os.path import dirname as _dirname, basename as _basename,\ 3 | isfile as _isfile 4 | import glob as _glob 5 | 6 | exec('\n'.join(map(lambda name: "from ." + name + " import *", 7 | [_basename(f)[:-3] for f in 8 | _glob.glob(_dirname(__file__) + "/*.py") 9 | if _isfile(f) and not _basename(f).startswith('_')]))) 10 | -------------------------------------------------------------------------------- /timeflow/trainer/automated_training_monitor.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | __all__ = ['AutomatedTrainingMonitor'] 3 | 4 | 5 | class AutomatedTrainingMonitor: 6 | 7 | def __init__(self, input_var, output_var, training_input, training_output, 8 | train, cost, sess, training_steps=100, 9 | validation_input=None, validation_output=None, 10 | early_stopping_rounds=None, burn_in=50, 11 | summary_op=None, writer_obj=None): 12 | """Initialize AutomatedTrainingMonitor class 13 | 14 | Parameters 15 | ---------- 16 | input_var : tf.tensor 17 | Input tensor 18 | output_var : tf.tensor 19 | Output tensor 20 | training_input : np.array 21 | Training input 22 | training_output : np.array 23 | Training output 24 | train : tf.Optimizer 25 | Optimizer for the network 26 | cost : tf.constant 27 | Cost/Loss function operation 28 | sess : tf.Session 29 | Tensorflow Session 30 | training_steps : integer (default 100) 31 | Training steps 32 | validation_input : np.array 33 | Validation input 34 | validation_output : np.array 35 | Validation output 36 | early_stopping_rounds : integer (default None) 37 | Number of iterations to check for early stopping 38 | burn_in : integer (default 50) 39 | Burn in period for the training 40 | summary_op: summary operation (default None) 41 | Summary operation for tensorboard 42 | writer_obj: SummaryWriter object (default None) 43 | SummaryWriter object for tensorboard 44 | """ 45 | 46 | self.input_var = input_var 47 | self.output_var = output_var 48 | self.sess = sess 49 | self.cost = cost 50 | self.train_step = train 51 | self.training_input = training_input 52 | self.training_output = training_output 53 | self.training_steps = training_steps 54 | self.validation_input = validation_input 55 | self.validation_output = validation_output 56 | self.early_stopping_rounds = early_stopping_rounds 57 | self._best_value_step = None 58 | self._best_value = None 59 | self._early_stopped = False 60 | self.burn_in = burn_in 61 | self.summary_op = summary_op 62 | self.writer_obj = writer_obj 63 | 64 | @property 65 | def early_stopped(self): 66 | """Returns True if this monitor caused an early stop.""" 67 | return self._early_stopped 68 | 69 | @property 70 | def best_step(self): 71 | """Returns the step at which the best early stopping metric was found.""" 72 | return self._best_value_step 73 | 74 | @property 75 | def best_value(self): 76 | """Returns the best early stopping metric value found so far.""" 77 | return self._best_value 78 | 79 | def validate_every_step(self, step): 80 | if self.early_stopping_rounds is not None: 81 | current_value = float(self.sess.run(self.cost,feed_dict={self.input_var:self.validation_input, 82 | self.output_var:self.validation_output})) 83 | if (self._best_value is None or current_value < self._best_value): 84 | self._best_value = current_value 85 | self._best_value_step = step 86 | stop_now = (step - self._best_value_step >= self.early_stopping_rounds) 87 | if stop_now: 88 | self._early_stopped = True 89 | return 90 | 91 | def train(self): 92 | for iter_num in range(self.training_steps): 93 | if self.summary_op is not None: 94 | _, summary = self.sess.run([self.train_step, self.summary_op], 95 | feed_dict={self.input_var:self.training_input, 96 | self.output_var:self.training_output}) 97 | self.writer_obj.add_summary(summary, iter_num) 98 | else: 99 | self.sess.run(self.train_step, feed_dict={self.input_var: self.training_input, 100 | self.output_var: self.training_output}) 101 | if iter_num >= self.burn_in: 102 | self.validate_every_step(iter_num) 103 | if self._early_stopped is True: 104 | break 105 | print "Final Validation loss: ",\ 106 | float(self.sess.run(self.cost,feed_dict={self.input_var:self.validation_input, 107 | self.output_var:self.validation_output})) 108 | print "Number of Iterations: ",\ 109 | iter_num 110 | if self.summary_op is not None: 111 | return self.writer_obj 112 | else: 113 | return 114 | 115 | def reset_early_stopped(self): 116 | self._best_value_step = None 117 | self._best_value = None 118 | self._early_stopped = False 119 | -------------------------------------------------------------------------------- /timeflow/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Utils is for all helper functions for TimeFlow 2 | import plotting 3 | import metrics 4 | import autocorr 5 | -------------------------------------------------------------------------------- /timeflow/utils/autocorr.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | class AutoCorrInitializer(): 4 | """ 5 | AutoCorrInitializer class does data munging on the outputs to bring them 6 | to the right dimensions to be fed into AutoCorr. 7 | """ 8 | def __init__(self, inputs, outputs, y): 9 | self.inputs = inputs 10 | self.outputs = outputs 11 | self.y = y 12 | 13 | def create_tensor_output(self): 14 | # Separating out the time differences from the input vector 15 | time_diff = tf.expand_dims(self.inputs[:,1], axis=1) 16 | # Calculating the residuals 17 | residuals = tf.subtract(self.y, self.outputs) 18 | # Calculating the signal vector 19 | next_residual = residuals[1:] 20 | prev_residual = residuals[:-1] 21 | time_diff_residual = time_diff[1:] 22 | sign_res = tf.concat([next_residual, prev_residual], 1) 23 | return time_diff_residual, sign_res 24 | 25 | class AutoCorr(): 26 | """ 27 | AutoCorr class estimates the autocorrelation coefficient from residuals. 28 | """ 29 | def __init__(self, time_input, signal_input): 30 | """Initialize AutoCorr class 31 | 32 | Parameters 33 | ---------- 34 | time_input : tf.Tensor 35 | Input vector/tensor with time difference values 36 | time_input : tf.Tensor 37 | Input vector/tensor with signal magnitude values 38 | """ 39 | self.time_input = time_input 40 | self.signal_input = signal_input 41 | with tf.variable_scope('phi'): 42 | self.phi_tf = tf.Variable(tf.truncated_normal([1], mean=0.5, stddev=.01)) 43 | with tf.variable_scope('sigma'): 44 | self.sigma_tf = tf.Variable(tf.truncated_normal([1], mean=0.5, stddev=.01), 45 | trainable=False) 46 | self.next_signal, self.prev_signal = tf.unstack(self.signal_input, axis=1) 47 | # Extending the dimensions of both the vectors 48 | self.next_signal = tf.expand_dims(self.next_signal, axis=1) 49 | self.prev_signal = tf.expand_dims(self.prev_signal, axis=1) 50 | # Packing all the three tensors for computation 51 | self.input_ = tf.stack([self.time_input, self.next_signal, self.prev_signal], axis=2) 52 | 53 | 54 | def generate_log_loss(self): 55 | """ 56 | Returns 57 | ---------- 58 | tf.Tensor 59 | Tensor with log-likelihood value 60 | """ 61 | nu = tf.multiply(self.sigma_tf, tf.sqrt(tf.subtract(1., tf.pow(self.phi_tf, tf.multiply(2., self.time_input))))) 62 | e = tf.subtract(tf.multiply(tf.pow(self.phi_tf, self.time_input), self.prev_signal), self.next_signal) 63 | nu_sq = tf.pow(nu, 2.) 64 | e_sq = tf.pow(e, 2.) 65 | # Calculating all steps of LL 66 | log_lik = tf.log(tf.multiply(2.51, nu)) + tf.div(e_sq, tf.multiply(2., nu_sq)) 67 | return tf.reduce_sum(log_lik) 68 | -------------------------------------------------------------------------------- /timeflow/utils/metrics.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | 4 | def RMSE(predicted_tensor, response_tensor): 5 | 6 | """Initialize InputLSTMLayer class 7 | 8 | Parameters 9 | ---------- 10 | predicted_tensor : tf.Tensor 11 | Predicted tensor 12 | response_tensor: tf.Tensor 13 | Response tensor 14 | 15 | Response 16 | ---------- 17 | tf.Tensor 18 | RMSE operation tensor 19 | """ 20 | return tf.reduce_mean(tf.pow(tf.subtract(predicted_tensor, response_tensor), 2)) 21 | 22 | 23 | def R2(predicted_tensor, response_tensor): 24 | 25 | """Initialize InputLSTMLayer class 26 | 27 | Parameters 28 | ---------- 29 | predicted_tensor : tf.Tensor 30 | Predicted tensor 31 | response_tensor: tf.Tensor 32 | Response tensor 33 | 34 | Response 35 | ---------- 36 | tf.Tensor 37 | R2 operation tensor 38 | """ 39 | pred_mean = tf.expand_dims(tf.reduce_mean(predicted_tensor, 40 | reduction_indices=[0]), 1) 41 | rse = tf.reduce_mean(tf.pow(tf.subtract(predicted_tensor, pred_mean), 2)) 42 | mse = tf.reduce_mean(tf.pow(tf.subtract(predicted_tensor, response_tensor), 2)) 43 | R2 = 1 - tf.div(mse, rse) 44 | return R2 45 | -------------------------------------------------------------------------------- /timeflow/utils/plotting.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import seaborn as sns 3 | import numpy as np 4 | from matplotlib import gridspec 5 | sns.set_style("whitegrid") 6 | 7 | 8 | def plot_residuals(predicted_series, 9 | actual_series, 10 | time_vector, 11 | num_training_points, 12 | num_validation_points, 13 | base_path=None, 14 | file_name=None): # pragma: no cover 15 | """Plotting function for plotting the predicted series with the residuals. 16 | 17 | Parameters 18 | ---------- 19 | predicted_series : np.array 20 | Predicted vector 21 | actual_series : np.array 22 | Actual response vector 23 | time_vector : np.array 24 | Time vector 25 | num_training_points : integer 26 | Number of points used for training 27 | num_validation_points : integer 28 | Number of points used for validation 29 | base_path: string (default None) 30 | Base path for saving the plot 31 | base_path: string (default None) 32 | Base path for saving the plot 33 | file_name: string (default None) 34 | File name for the plot 35 | 36 | """ 37 | 38 | fig = plt.figure(figsize=(15, 15)) 39 | residuals = actual_series - predicted_series 40 | gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1]) 41 | axarr = [0, 0] 42 | axarr[0] = plt.subplot(gs[0]) 43 | axarr[0].plot(time_vector, predicted_series, 44 | marker='o', label='Predicted', markersize=5, 45 | alpha=0.9, linestyle='-', linewidth=.5) 46 | axarr[0].plot(time_vector, actual_series, marker='o', label='Actual', 47 | markersize=5, linestyle='--') 48 | xlim = plt.xlim() 49 | axarr[0].set_ylim((min(predicted_series)-1, max(predicted_series)+1)) 50 | axarr[0].axvspan(xlim[0], time_vector[num_training_points], alpha=0.1, 51 | label='Training set', color='r') 52 | axarr[0].axvspan(time_vector[num_training_points], 53 | time_vector[num_training_points + num_validation_points], 54 | alpha=0.1, 55 | label='Validation set', color='b') 56 | axarr[0].legend() 57 | axarr[0].set_title('Predicted vs Actual plot', fontsize=24) 58 | axarr[0].set_xlabel('Time', fontsize=20) 59 | axarr[0].set_ylabel('Magnitude', fontsize=20) 60 | 61 | axarr[1] = plt.subplot(gs[1]) 62 | axarr[1].scatter(time_vector.tolist(), residuals.tolist()) 63 | xlim = plt.xlim() 64 | ax2_ylim = axarr[1].get_ylim() 65 | axarr[1].axvspan(xlim[0], time_vector[num_training_points], alpha=0.1, 66 | label='Training set', color='r') 67 | axarr[1].axvspan(time_vector[num_training_points], 68 | time_vector[num_training_points + num_validation_points], 69 | alpha=0.1, 70 | label='Validation set', color='b') 71 | axarr[1].legend() 72 | axarr[1].set_title('Residual plot', fontsize=24) 73 | axarr[1].set_xlabel('Time', fontsize=20) 74 | axarr[1].set_ylabel('Residuals', fontsize=20) 75 | axarr[1].set_xlim([min(time_vector), max(time_vector)]) 76 | axarr[1].set_ylim(ax2_ylim[0]-1, ax2_ylim[1]+1) 77 | if (base_path is not None and file_name is not None): 78 | plt.savefig(base_path+file_name) 79 | plt.close() 80 | --------------------------------------------------------------------------------