'Backward propagate pooling layer.
Arguments:
layer (PoolLayer): The pool layer object. Different backends have
different pool layers.
I (Tensor): Input tensor.
E (Tensor): Error tensor.
delta (Tensor): Gradient tensor (delta)
denom (Tensor): denominator tensor computed during bprop
ascale (float): scaling parameter (alpha) to multiply the pooled sum (1.25e-5 in AK)
bpower (float): exponential parameter (beta) to raise denominator by (0.75 in AK)'

def bprop_lrn(self, layer, I, O, E, delta, denom, alpha=None, beta=None, ascale=1, bpower=1):

    assert (layer.sizeI == I.size)
    assert (layer.sizeO == E.size)
    assert (layer.sizeI == delta.size)
    (J, T, R, S) = layer.JTRS
    (C, D, H, W, N) = layer.dimI
    (K, M, P, Q, N) = layer.dimO
    (pad_c, pad_d, pad_h, pad_w) = layer.padding
    (str_c, str_d, str_h, str_w) = layer.strides
    array_I = I._tensor.reshape(layer.dimI)
    array_E = E._tensor.reshape(layer.dimO)
    array_O = O._tensor.reshape(layer.dimO)
    array_delta = delta._tensor.reshape(layer.dimI)
    array_denom = denom._tensor.reshape(layer.dimO)
    for k in range(K):
        (sliceC, _) = layer.kSlice[k]
        for m in range(M):
            (sliceD, _) = layer.mSlice[m]
            for p in range(P):
                (sliceH, _) = layer.pSlice[p]
                for q in range(Q):
                    (sliceW, _) = layer.qSlice[q]
                    _O = array_O[sliceC, sliceD, sliceH, sliceW, :].reshape((-1), N)
                    _E = array_E[sliceC, sliceD, sliceH, sliceW, :].reshape((-1), N)
                    _den = array_denom[sliceC, sliceD, sliceH, sliceW, :].reshape((-1), N)
                    array_delta[k, m, p, q, :] = np.sum(((_O * _E) / _den), axis=0)
    array_delta[:] = ((((((-2) * bpower) * (ascale / float(J))) * array_delta) * array_I) + (array_E * np.power(array_denom, (- bpower))))
