'Backward propagate pooling layer.
Arguments:
layer (PoolLayer): The pool layer object. Different backends have
different pool layers.
I (Tensor): Input (error) tensor.
O (Tensor): Output (delta) tensor.
argmax (Tensor): tensor to store location of the maximum
alpha (float): linear scaling (does not work for l2 pooling)
beta (float): accumulation value into grad_I'

def bprop_pool(self, layer, I, O, argmax=None, alpha=1.0, beta=0.0):

    assert (layer.sizeI == O.size)
    assert (layer.sizeO == I.size)
    if (layer.op == 'max'):
        assert (layer.sizeO == argmax.size)
    op = layer.op
    (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_E = I._tensor.reshape(layer.dimO)
    array_E[:] = (array_E * alpha)
    array_delta = O._tensor.reshape(layer.dimI)
    array_delta[:] = (array_delta * beta)
    if (op == 'max'):
        array_argmax = argmax._tensor.reshape(layer.dimO)
    for k in range(K):
        (sliceC, clen) = layer.kSlice[k]
        for m in range(M):
            (sliceD, dlen) = layer.mSlice[m]
            for p in range(P):
                (sliceH, hlen) = layer.pSlice[p]
                for q in range(Q):
                    (sliceW, wlen) = layer.qSlice[q]
                    patch_in = (sliceC, sliceD, sliceH, sliceW, slice(None))
                    patch_out = (k, m, p, q, slice(None))
                    sliceB = array_delta[patch_in].reshape(((-1), N))
                    if (op == 'max'):
                        max_n = array_argmax[patch_out]
                        sliceB[(max_n, list(range(N)))] += array_E[patch_out]
                    elif (op == 'avg'):
                        sliceB += (array_E[patch_out] * (1.0 / sliceB.shape[0]))
                    else:
                        raise NotImplementedError
                    array_delta[patch_in] = sliceB.reshape((clen, dlen, hlen, wlen, N))
