class_docstr: ConvLayer parameter object.
  This then is passed as an argument to all the convolution operations.
  
  N: Number of images in mini-batch
  C: Number of input feature maps
  K: Number of output feature maps
  
  D: Depth  of input image
  H: Height of input image
  W: Width  of input image
  
  T: Depth  of filter kernel
  R: Height of filter kernel
  S: Width  of filter kernel
  
  padding: amount of zero-padding around the given edge
  strides: factor to step the filters by in a given direction
  dilation: dilation factor for each dimension
code: def xprop_conv(
      self,
      I,
      F,
      O,
      X=None,
      bias=None,
      bsum=None,
      alpha=1.0,
      beta=0.0,
      relu=False,
      brelu=False,
      slope=0.0,
      backward=False,
      layer_op=None,
  ):
      if X is None:
          X = O
  
      if backward:
          I = I._tensor.reshape(self.dimO)
          O = O._tensor.reshape(self.dimI)
          X = X._tensor.reshape(self.dimI)
      else:
          I = I._tensor.reshape(self.dimI)
          O = O._tensor.reshape(self.dimO)
          X = X._tensor.reshape(self.dimO)
      F = F._tensor.reshape(self.dimF)
      if bias is not None:
          bias = bias._tensor.reshape((O.shape[0], 1))
      if bsum is not None:
          bsum = bsum._tensor.reshape((O.shape[0], 1))
  
      # 1x1 conv can be cast as a simple dot operation
      if self.dot:
          C = F.shape[0]
          K = F.shape[-1]
          if backward:
              # CxHWN = CxK . KxHWN
              F = F.reshape((C, K))
              I = I.reshape((K, -1))
          else:
              # KxHWN = CxK.T . CxHWN
              F = F.reshape((C, K)).T
              I = I.reshape((C, -1))
  
          if beta:
              O[:] = alpha * np.dot(F, I).reshape(O.shape) + beta * X
          else:
              O[:] = np.dot(F, I).reshape(O.shape)
              self.compound_ops(O, X, bias, bsum, relu, brelu, slope)
          return
  
      if backward:
          # C <=> K and mirror T, R, S  (0, 1, 2, 3, 4) => (4, 1, 2, 3, 0)
          F = np.transpose(
              F[:, ::-1, ::-1, ::-1], (4, 1, 2, 3, 0)
          ).copy()
          mSlice, pSlice, qSlice = self.dSlice, self.hSlice, self.wSlice
      else:
          mSlice, pSlice, qSlice = self.mSlice, self.pSlice, self.qSlice
  
      K, M, P, Q, N = O.shape
  
      for m in range(M):
          sliceT, sliceD, _ = mSlice[m]
          for p in range(P):
              sliceR, sliceH, _ = pSlice[p]
              for q in range(Q):
                  sliceS, sliceW, _ = qSlice[q]
  
                  slicedF = F[:, sliceT, sliceR, sliceS].reshape(
                      (-1, K)
                  )
                  slicedI = I[:, sliceD, sliceH, sliceW].reshape(
                      (-1, N)
                  )
  
                  if beta:
                      O[:, m, p, q] = (
                          alpha * np.dot(slicedF.T, slicedI)
                          + beta * X[:, m, p, q]
                      )
                  else:
                      O[:, m, p, q] = np.dot(slicedF.T, slicedI)
  
      if not beta:
          self.compound_ops(O, X, bias, bsum, relu, brelu, slope)
  
imports: from __future__ import division
  from builtins import object
  import math
  from operator import mul
  import numpy
  from functools import reduce
label_desc: Use image node_id 8 for calling the ConvLayer obj's underlying member method code with example usage: obj.xprop_conv(I, F, O, X, bias, bsum, alpha, beta, relu, brelu, slope, backward, layer_op) without return types