'Backward propagation of errors through recurrent layer.
Arguments:
deltas (Tensor): tensors containing the errors for
each step of model unrolling.  Expected 2D shape
is (output_size, sequence_length * batch_size)
alpha (float, optional): scale to apply to input for activation
gradient bprop.  Defaults to 1.0
beta (float, optional): scale to apply to output activation
gradient bprop.  Defaults to 0.0
Returns:
Tensor: back propagated errors for each step of time unrolling
for each mini-batch element
shape: (input_size, sequence_length * batch_size)'

def bprop(self, deltas, alpha=1.0, beta=0.0):

    self.dW[:] = 0
    if (self.in_deltas is None):
        self.in_deltas = get_steps(deltas, self.out_shape)
        self.prev_in_deltas = (self.in_deltas[(-1):] + self.in_deltas[:(-1)])
    params = (self.xs, self.h, self.h_prev_bprop, self.h_delta, self.in_deltas, self.prev_in_deltas, self.out_delta)
    for (xs, hs, h_prev, h_delta, in_deltas, prev_in_deltas, out_delta) in reversed(list(zip(*params))):
        in_deltas[:] = (self.activation.bprop(hs) * in_deltas)
        self.be.compound_dot(self.W_recur.T, in_deltas, h_delta)
        prev_in_deltas[:] = (prev_in_deltas + h_delta)
        if (h_prev != 0):
            self.be.compound_dot(in_deltas, h_prev.T, self.dW_recur, beta=1.0)
        self.be.compound_dot(in_deltas, xs.T, self.dW_input, beta=1.0)
        self.db[:] = (self.db + self.be.sum(in_deltas, axis=1))
        if out_delta:
            self.be.compound_dot(self.W_input.T, in_deltas, out_delta, alpha=alpha, beta=beta)
    self.final_hidden_error[:] = self.h_delta[0]
    return self.out_deltas_buffer
