How to use outputs from previous time steps as input along with other inputs in RNN using tensorflow?
Asked Answered
C

0

3

In the following example, there are three time series and I want to predict another time series y which is a function of the three. How can I use four inputs to predict the time series where the fourth input is the output at previous time step?

import tensorflow as tf
import numpy as np
import pandas as pd

#clean computation graph
tf.reset_default_graph()

tf.set_random_seed(777)  # reproducibility
np.random.seed(0)

import matplotlib.pyplot as plt


def MinMaxScaler(data):    
    numerator = data - np.min(data, 0)
    denominator = np.max(data, 0) - np.min(data, 0)
    # noise term prevents the zero division
    return numerator / (denominator + 1e-7)


class generate_data(object):

    def __init__(self, data_len,  in_series, y_pred, seq_lengths, method='sum' ):
        self.data_len = data_len
        self.data = None
        self.in_series = in_series #number of input series
        self.y_pred = y_pred  #number of final outputs from model
        self.seq_lengths = seq_lengths
        self.method = method

    def _f(self, x):
        y = 0
        result = []
        for _ in x:
            result.append(y)
            y += np.random.normal(scale=1)
        return np.array(result)

    def _runningMean(self, x, N):
        return np.convolve(x, np.ones((N,))/N)[(N-1):]


    def sine(self):
        DATA = np.zeros((self.data_len, self.in_series))
        xx = [None]
        data_0 = np.sin(np.arange(self.data_len*self.in_series))
        xx = data_0.reshape(self.data_len, self.in_series)
        DATA[:,0: self.in_series] = xx            
        y = self._get_y(DATA)
        return xx,y, DATA


    def _get_y(self, xx):
        if self.method=='sum':
            yy = np.array([np.sum(xx[i,:]) for i in range(np.shape(xx)[0])])
        elif self.method == 'mean':
              yy = np.array([np.mean(xx[i,:]) for i in range(np.shape(xx)[0])])

        elif self.method == 'self_mul':
            yy = np.array([np.prod(xx[i,:]) for i in range(np.shape(xx)[0])])
        elif self.method == 'mean_mirror':
            yy = np.array([np.mean(xx[i,:]) for i in range(np.shape(xx)[0])])
        return yy


    def normalize(self, xx1,yy1):

        yy = [None]*len(yy1)
        YMinMax = {}

        xx = MinMaxScaler(xx1)
        for i in range(self.y_pred):
            YMinMax['ymin_' + str(i)] = np.min(yy1[0])
            YMinMax['ymax_' + str(i)] = np.max(yy1[0])
            yy[i] = MinMaxScaler(yy1[0])
        setattr(self, 'YMinMax', YMinMax)
        return xx,yy


    def create_dataset(self, xx, yy):
        '''creates a dataset consisting of windows for x and y data'''
        dataX = self._build_input_windows(xx, self.seq_lengths)

        if self.y_pred > 1:
            pass
        elif self.y_pred > 1 and self.seq_lengths != any(self.seq_lengths):
            pass
        else: 
            dataY = self._build_y_windows(yy[0] , self.seq_lengths)        
        return dataX, dataY


    def _build_input_windows(self, time_series, seq_length):
        dataX = []
        for i in range(0, len(time_series) - seq_length):
            _x = time_series[i:i + seq_length, :]
            dataX.append(_x)
        return np.array(dataX)   


    def _build_y_windows(self, iny, seq_length):        
        dataY = []
        for i in range(0, len(iny) - seq_length):
            _y = iny[i + seq_length, ]  # Next close price           
            dataY.append(_y)
        return  np.array(dataY)


    def TrainTestSplit(self, dataX, dataY, train_frac):

        train_size = int(len(dataY) * train_frac)            
        trainX, testX = np.array(dataX[0:train_size]), np.array(dataX[train_size:len(dataX)])

        trainY, testY = np.array(dataY[0:train_size]), np.array(dataY[train_size:len(dataY)])
        trainY = trainY.reshape(len(trainY), 1)
        testY = testY.reshape(len(testY), 1)  
        return trainX, trainY, testX, testY, train_size


#training/hyper parameters
tot_epochs = 500 
batch_size = 32
learning_rate = 0.01
seq_lengths = 5  #sequence lengths/window size for  RNN
rnn_inputs = 3 # no of inputs for  RNN
y_pred = 1
data_length = 105  #this can be overwritten or useless
gen_data = generate_data(data_length,  rnn_inputs, y_pred, seq_lengths, 'sum')
xx,yy,data_1 = gen_data.sine() 

train_frac = 0.8
xx1,yy1 = gen_data.normalize(xx,[yy])
dataX, dataY = gen_data.create_dataset(xx1,yy1)
trainX, trainY, testX, testY, train_size = gen_data.TrainTestSplit( dataX, dataY, train_frac)

keep_prob = tf.placeholder(tf.float32)
x_placeholders = tf.placeholder(tf.float32, [None, 5, 3])
Y =  tf.placeholder(tf.float32, [None, 1])

with tf.variable_scope('scope0'):  #defining  RNN
    cell = tf.contrib.rnn.BasicLSTMCell(num_units= 7, state_is_tuple=True, activation=tf.tanh)
    outputs1, _states = tf.nn.dynamic_rnn(cell, x_placeholders, dtype=tf.float32)
    Y_pred1 = tf.contrib.layers.fully_connected(outputs1[:, -1], 1, activation_fn=None)
Y_pred = Y_pred1

## cost/loss
loss = tf.reduce_sum(tf.square(Y_pred - Y))  # sum of the squares
## optimizer
optimizer = tf.train.AdamOptimizer(learning_rate)
train = optimizer.minimize(loss)
#
## RMSE
targets = tf.placeholder(tf.float32, [None, 1])
predictions = tf.placeholder(tf.float32, [None, 1])
rmse = tf.sqrt(tf.reduce_mean(tf.square(targets - predictions)))


with tf.Session() as sess:
    saver = tf.train.Saver(max_to_keep=41)
    writer = tf.summary.FileWriter('./laos_2out/cnntest', sess.graph)

    init = tf.global_variables_initializer()
    sess.run(init)

    # Training step
    for epoch in range(tot_epochs):

      total_batches = int(train_size / batch_size)  ##total batches/ no. of steps in an epoch

      #for batch in range(total_batches):
      _, step_loss = sess.run([train, loss], feed_dict= {x_placeholders:trainX, Y:trainY, keep_prob:0.5} )

#    # evaluating on test data
    test_predict = sess.run(Y_pred, feed_dict= {x_placeholders:testX, Y:trainY, keep_prob:0.5} )

    #evaluating on training data
    train_predict = sess.run(Y_pred, feed_dict={x_placeholders:trainX, Y:trainY, keep_prob:0.5})

    rmse_val = sess.run(rmse, feed_dict={targets: testY, predictions: test_predict})
    print("RMSE: {}".format(rmse_val))

    # Plot predictions
    fig, (ax1,ax2) = plt.subplots(1,2, sharey=True)
    fig.set_figwidth(14)
    fig.set_figheight(5)
    ax2.plot(testY, 'b', label='observed')
    ax2.plot(test_predict, 'k', label='predicted')
    ax2.legend(loc="best")
    ax2.set_xlabel("Time Period")
    ax2.set_title('Testing')
    ax1.plot(trainY, 'b', label='observed')
    ax1.plot(train_predict, 'k',label= 'predicted')
    ax1.legend(loc="best")
    ax1.set_xlabel("Time Period")
    ax1.set_ylabel("discharge (cms)")
    ax1.set_title('Training')
    plt.show()

I have looked at answers here and here which make use of tf.nn.raw_rnn but in those cases only the predicted output at previous time steps is used but I want the predicted output at previous timesteps plus other three inputs to be used for prediction.

Cheesy answered 5/3, 2019 at 14:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.