'Batch Normalization layer
Arguments:
lib (Class): NervanaGPU instance
dtype (Dtype): Data type
N (int): batch size
C (int): Number of input feature maps
D (int): Depth  of input feature maps
H (int): Height of input feature maps
W (int): Width  of input feature maps
nIn (int): Number on inputs for fully connected layer
rho (float): Exponential window averaging factor
eps (float): Constant added for numerical stability
relu (bool): Flag for rectified linear activation function
bsum (bool): PQN sum precomputed in conv kernel'

def __init__(self, lib, dtype, N, C=None, D=1, H=1, W=1, nIn=None, rho=0.99, eps=1e-06, relu=False, bsum=False):

    super(BatchNorm, self).__init__(lib, dtype, N)
    self.rho = rho
    self.eps = eps
    self.relu = relu
    self.bsum = bsum
    if (C is not None):
        self.C = C
        self.K = C
        self.M = D
        self.P = H
        self.Q = W
        self.dimI = (C, D, H, W, N)
        self.dimO = (C, D, H, W, N)
        self.dimO2 = ((((C * D) * H) * W), N)
        self.dim2 = (C, (((D * H) * W) * N))
        self.nOut = (((C * D) * H) * W)
    elif (nIn is not None):
        self.nOut = nIn
        self.K = nIn
        self.dimI = (nIn, N)
        self.dimO = (nIn, N)
        self.dimO2 = (nIn, N)
        self.dim2 = (nIn, N)
    else:
        raise ValueError('missing    C    or    nIn')
    self.rcp_depth = (1.0 / self.dim2[1])
