In machine learning, a recurrent neural network (RNN or LSTM) is a class of neural networks that have successfully been applied to Natural Language Processing. In this tutorial, I will explain how to build an RNN model with LSTM or GRU cell to predict the prices of the New York Stock Exchange.

The implementation of the network has been made using TensorFlow High-level API like Dataset API to feed data into model and Estimators API to train and predict model. I will describe the following steps: dataset creation, RNN training and prediction.

Download Data


The dataset can be downloaded from Kaggle. Data found on Kaggle is a collection of CSV files. You don’t have to do any preprocessing. You can directly load the data into a Pandas DataFrame.Stock prices come in several different flavours. They are, Open, Close, High and Low.

import numpy as np
import pandas as pd
import sklearn
import sklearn.preprocessing
import tensorflow as tf
from matplotlib import pyplot as plt

tf.logging.set_verbosity(tf.logging.INFO)

tf.logging.log(tf.logging.INFO, "TensorFlow version " + tf.__version__)

DATA_PATH = 'data/nyse/prices-split-adjusted.csv'

df = pd.read_csv(DATA_PATH, index_col=0)

SYMBOL_NAME = 'GOOG'
df_stock = df[df.symbol == SYMBOL_NAME].copy()

df_stock.drop(['symbol'], 1, inplace=True)
df_stock.drop(['volume'], 1, inplace=True)

Data scaling


Most common activation functions of the network’s neurons such as tanh or sigmoid are defined on the [-1, 1] or [0, 1] interval respectively. Scaling can be easily accomplished in Python using sklearn’s MinMaxScaler.

def scale_data(df):
    min_max_scaler = sklearn.preprocessing.MinMaxScaler()

    df['open'] = min_max_scaler.fit_transform(df.open.values.reshape(-1, 1))
    df['high'] = min_max_scaler.fit_transform(df.high.values.reshape(-1, 1))
    df['low'] = min_max_scaler.fit_transform(df.low.values.reshape(-1, 1))
    df['close'] = min_max_scaler.fit_transform(df.close.values.reshape(-1, 1))

    return df

df_stock_norm = df_stock.copy()
df = scale_data(df_stock_norm)

Target Data


We will give it a sequence of stock prices and ask it to predict the next day price using GRU cells. We put our sequence of stock prices on the inputs. It will produce some kind of number on the output. To teach it we force a sequence on the outputs which is the same sequence shifted by one number. This is what we will be teaching.

RNN Time series input

SEQLEN = 20

df_input = df
df_target = df.shift(-1)

df_input = df_input[:-2].values
df_target = df_target[:-2].values

X = np.reshape(df_input, (-1, SEQLEN, 4))
Y = np.reshape(df_target, (-1, SEQLEN, 4))

Split Data

The dataset was split into training and test data. The training data contained 80% of the total dataset. The data was not shuffled but sequentially sliced.

train_split = 0.8

num_data = X.shape[0]

num_train = int(train_split * num_data)

x_train = X[0:num_train]
y_train = Y[0:num_train]

y_test = Y[num_train:]
x_test = X[num_train:]

Dataset Input Function


In this tutorial, we will use Dataset API to input data in model and Estimator API to train model. You need to provide an input_fn to read your data. You provide a function that returns inputs and labels. The inputs are a dictionary of all your inputs and the labels is a tensor.

def train_input():

    dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
    dataset = dataset.repeat()
    dataset = dataset.shuffle(SHUFFLE_SIZE)
    dataset = dataset.batch(BATCHSIZE)
    samples, labels = dataset.make_one_shot_iterator().get_next()

    return samples, labels


def test_input():

    dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test))
    dataset = dataset.repeat(1)
    dataset = dataset.batch(BATCHSIZE)
    samples, labels = dataset.make_one_shot_iterator().get_next()

    return samples, labels

Create LSTM Model


There is a full API for working with RNN in TensorFlow. It starts with a GRU cell. This defines all the weights and biases. The only parameter you need to specify is this internal size of the vectors in this cell.

RNN_CELLSIZE = 80
N_LAYERS = 2
DROPOUT_PKEEP = 0.7

def model_rnn_fn(features, labels, mode):
    batchsize = tf.shape(features)[0]

    seqlen = tf.shape(features)[1]

    cells = [tf.nn.rnn_cell.GRUCell(RNN_CELLSIZE) for _ in range(N_LAYERS)]

    cells[:-1] = [tf.nn.rnn_cell.DropoutWrapper(cell, output_keep_prob=DROPOUT_PKEEP) for cell in cells[:-1]]

RNN Time series input

If you want to deep neural network. Let’s stack it, there is a function for that it’s called MultiRNNCell you pass it a cell and how many times you want this cell and it creates a new cell which is a stacked cell.

cell = tf.nn.rnn_cell.MultiRNNCell(cells, state_is_tuple=False)

In TensorFlow you can unroll cell using the dynamic RNN function you give it a stacked cell that you just produced. How many times do you unroll? That will depend on the shape of X. X here my input is a sequence of the number. If I feed it with sequences of 16 numbers my network will be unrolled 16 times. what I get as an output are results? It’s all the ages on the bottom.

Yn, H = tf.nn.dynamic_rnn(cell, features, dtype=tf.float64)

    Yn = tf.reshape(Yn, [batchsize * seqlen, RNN_CELLSIZE])

    Yr = tf.layers.dense(Yn, 4)  # Yr l[BATCHSIZE*SEQLEN, 1]
    Yr = tf.reshape(Yr, [batchsize, seqlen, 4])  # Yr [BATCHSIZE, SEQLEN, 1]

    Yout = Yr[:, -1, :]  # Last output Yout [BATCHSIZE, 1]

    loss = train_op = None
    if mode != tf.estimator.ModeKeys.PREDICT:
        loss = tf.losses.mean_squared_error(Yr, labels)  # la  bels[BATCHSIZE, SEQLEN, 1]
        lr = 0.001
        optimizer = tf.train.AdamOptimizer(learning_rate=lr)

        train_op = tf.contrib.training.create_train_op(loss, optimizer)

    return tf.estimator.EstimatorSpec(
        mode=mode,
        predictions={"Yout": Yout},
        loss=loss,
        train_op=train_op
    )

you need to apply an activation layer on those to obtain my result sequence and I get also the last state H which is the state that will need to pass back in the beginning as I continue my training.

Create the Estimator

The estimator is a TensorFlow class for performing high-level model training, evaluation, and inference for our model. The model_fn argument specifies the model function to use for training, evaluation, and prediction pass it the model_rnn_fn. The model_dir argument specifies the directory where model data and checkpoints will be saved.

training_config = tf.estimator.RunConfig(model_dir="./output")

estimator = tf.estimator.Estimator(model_fn=model_rnn_fn, config=training_config)

Train RNN Model

Now we’re ready to train our model, which we can do by calling train() on estimator.

estimator.train(input_fn=train_input, steps=10000)

Train TensorFlow Model using Estimetor API

Predictions from Trained Model

We now have a trained model. We can now use the trained model to predict time series data based on some unlabeled data. As with training, we make predictions using a single function call.

results = estimator.predict(test_input)

Yout_ = [result["Yout"] for result in results]

predict = np.array(Yout_)

actual = y_test[:, -1]

colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
plt.plot(actual[:, 0], label="Actual Values", color='red')
plt.plot(predict[:, 0], label="Predicted Values", color='green', )

plt.title('stock')
plt.xlabel('time [days]')
plt.ylabel('normalized price')
plt.legend(loc='best')

plt.show()

Tensorflow stock prices prediction