'Apply the forward pass transformation to the input data.  The input data is a list of
inputs with an element for each time step of model unrolling.
Arguments:
inputs (Tensor): input data as 3D tensors, then converted into a list of 2D tensors.
The dimension is (input_size, sequence_length * batch_size)
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: GRU output for each model time step'

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

    self.init_buffers(inputs)
    if self.reset_cells:
        self.h[(-1)][:] = 0
        self.rz[(-1)][:] = 0
        self.hcan[(-1)][:] = 0
    if (init_state is not None):
        if (init_state.shape != self.h[(-1)].shape):
            raise ValueError('init_state    shape    mismatch.        Expected:    {expected},    found:    {found}.'.format(expected=self.h[(-1)].shape, found=init_state.shape))
        self.h[(-1)][:] = init_state
        self.h_prev_bprop[0] = init_state
    self.be.compound_dot(self.W_input, self.x, self.rzhcan_buffer)
    for (h, h_prev, rh_prev, xs, rz, r, z, hcan, rz_rec, hcan_rec, rzhcan) in zip(self.h, self.h_prev, self.rh_prev, self.xs, self.rz, self.r, self.z, self.hcan, self.rz_rec, self.hcan_rec, self.rzhcan):
        self.be.compound_dot(self.Wrz_recur, h_prev, rz_rec)
        rz[:] = self.gate_activation(((rz + rz_rec) + self.b_rz))
        rh_prev[:] = (r * h_prev)
        self.be.compound_dot(self.Whcan_recur, rh_prev, hcan_rec)
        hcan[:] = self.activation(((hcan_rec + hcan) + self.b_hcan))
        h[:] = (((1 - z) * h_prev) + (z * hcan))
    self.final_state_buffer[:] = self.h[(-1)]
    return self.outputs
