'Implements loading of given data into backend tensor objects. If the backend is specific
to an accelerator device, the data is copied over to that device.
Args:
X (ndarray): Input sequence with feature size within the dataset.
Shape should be specified as (num examples, feature size]
time_steps (int): The number of examples to be put into one sequence.
forward (int, optional): how many forward steps the sequence should predict. default
is 1, which is the next example
return_sequences (boolean, optional): whether the target is a sequence or single step.
Also determines whether data will be formatted
as strides or rolling windows.
If true, target value be a sequence, input data
will be reshaped as strides.  If false, target
value will be a single step, input data will be
a rolling_window'

def __init__(self, X, time_steps, forward=1, return_sequences=True):

    self.seq_length = time_steps
    self.forward = forward
    self.batch_index = 0
    self.nfeatures = self.nclass = X.shape[1]
    self.nsamples = X.shape[0]
    self.shape = (self.nfeatures, time_steps)
    self.return_sequences = return_sequences
    target_steps = (time_steps if return_sequences else 1)
    self.X_dev = self.be.iobuf((self.nfeatures, time_steps))
    self.y_dev = self.be.iobuf((self.nfeatures, target_steps))
    if (return_sequences is True):
        extra_examples = (self.nsamples % (self.be.bsz * time_steps))
        if extra_examples:
            X = X[:(- extra_examples)]
        self.nsamples -= extra_examples
        self.nbatches = (self.nsamples // (self.be.bsz * time_steps))
        self.ndata = ((self.nbatches * self.be.bsz) * time_steps)
        y = np.concatenate((X[forward:], X[:forward]))
        self.y_series = y
        self.X = X.reshape(self.be.bsz, self.nbatches, time_steps, self.nfeatures)
        self.y = y.reshape(self.be.bsz, self.nbatches, time_steps, self.nfeatures)
    else:
        self.X = rolling_window(X, time_steps)
        self.X = self.X[:(-1)]
        self.y = X[time_steps:]
        self.nsamples = self.X.shape[0]
        extra_examples = (self.nsamples % self.be.bsz)
        if extra_examples:
            self.X = self.X[:(- extra_examples)]
            self.y = self.y[:(- extra_examples)]
        self.nsamples -= extra_examples
        self.nbatches = (self.nsamples // self.be.bsz)
        self.ndata = (self.nbatches * self.be.bsz)
        self.y_series = self.y
        Xshape = (self.nbatches, self.be.bsz, time_steps, self.nfeatures)
        Yshape = (self.nbatches, self.be.bsz, 1, self.nfeatures)
        self.X = self.X.reshape(Xshape).transpose(1, 0, 2, 3)
        self.y = self.y.reshape(Yshape).transpose(1, 0, 2, 3)
