'Forward propagation of input to bi-directional recurrent layer.
Arguments:
inputs (Tensor): input to the model for each time step of
unrolling for each input in minibatch
shape: (feature_size, sequence_length * batch_size)
where:
* feature_size: input size
* sequence_length: degree of model unrolling
* batch_size: number of inputs in each mini-batch
inference (bool, optional): Set to true if you are running
inference (only care about forward
propagation without associated backward
propagation).  Default is False.
Returns:
Tensor: layer output activations for each time step of
unrolling and for each input in the minibatch
shape: (output_size, sequence_length * batch_size)'

def fprop(self, inputs, inference=False):

    self.init_buffers(inputs)
    if self.reset_cells:
        self.h_f_last[:] = 0
        self.h_b_last[:] = 0
    else:
        self.h_f_last[:] = self.h_f[(-1)]
        self.h_b_last[:] = self.h_b[0]
    self.be.compound_dot(self.W_input_f, self.x_f_v, self.h_ff_buffer_f)
    self.be.compound_dot(self.W_input_b, self.x_b_v, self.h_ff_buffer_b)
    self._fprop_bn(self.h_ff_buffer, inference)
    self.be.compound_rnn_unroll_fprop(self.W_recur_f, self.h_prev, self.h_ff_f, self.h_f, self.b_f, self.nout, self.nsteps, self.nsteps, self.activation, False)
    self.be.compound_rnn_unroll_fprop(self.W_recur_b, self.h_next, self.h_ff_b, self.h_b, self.b_b, self.nout, self.nsteps, self.nsteps, self.activation, True)
    return self.h_buffer
