class_docstr: Convert graph shape from Channel last (NHWC) to Channel first (NCHW) format.
  
  Supported functions: `Convolution`, `Deconvolution`, `BatchNormalization`,
  `MaxPooling`, `AveragePooling`, `SumPooling`, `Unpooling`, `Concatenate`
  
  Args:
      inputs (list of nn.Variable): Original channel last version of very beginning inputs (NHWC) of a network.
      inputs_cf (list of nn.Variable): Channel first version of very beginning inputs (NCHW) of a network.
        If this is not given, `inputs_cf` are generated internally and holded.
  
  Examples:
  
  .. code-block:: python
  
     pred = Model(...)
  
     import nnabla.experimental.graph_converters as GC
  
     modifiers = [GC.ChannelFirstModifier(<inputs of pred>)]
     gc = GC.GraphConverter(modifiers)
     pred = gc.convert(pred)
code: def connect(self, fname, inputs, args):
      if fname in ["Convolution", "Deconvolution"]:
          # TODO: address leading batch dimension
          args["channel_last"] = False
          x = inputs[0]
          w = inputs[1]
          b = inputs[2] if len(inputs) == 3 else None
          scope = self.get_parameter_scope(w)
          with nn.parameter_scope(scope):
              wd = w.d.copy().transpose(0, 3, 1, 2)
              w = nn.parameter.get_parameter_or_create(
                  "W_cl", wd.shape, wd
              )
          o = F.convolution(x, w, b, **args)
      elif fname == "BatchNormalization":
          # TODO: address leading batch dimension
          x = inputs[0]
          beta = inputs[1]
          gamma = inputs[2]
          mean = inputs[3]
          var = inputs[4]
          args["axes"] = [1]
          if "no_scale" in args:
              del args["no_scale"]
          if "no_bias" in args:
              del args["no_bias"]
          scope = self.get_parameter_scope(beta)
          with nn.parameter_scope(scope):
              beta_d = beta.d.copy().transpose(0, 3, 1, 2)
              gamma_d = gamma.d.copy().transpose(0, 3, 1, 2)
              mean_d = mean.d.copy().transpose(0, 3, 1, 2)
              var_d = var.d.copy().transpose(0, 3, 1, 2)
              beta = nn.parameter.get_parameter_or_create(
                  "beta_cf", beta_d.shape, beta_d, beta.need_grad
              )
              gamma = nn.parameter.get_parameter_or_create(
                  "gamma_cf", gamma_d.shape, gamma_d, gamma.need_grad
              )
              mean = nn.parameter.get_parameter_or_create(
                  "mean_cf", mean_d.shape, mean_d, mean.need_grad
              )
              var = nn.parameter.get_parameter_or_create(
                  "var_cf", var_d.shape, var_d, var.need_grad
              )
          o = F.batch_normalization(x, beta, gamma, mean, var, **args)
      elif fname in ["MaxPooling", "AveragePooling", "SumPooling"]:
          args["channel_last"] = False
          o = self._call_function(fname, inputs, args)
      elif fname in ["Concatenate"]:
          args["axis"] = 1
          o = self._call_function(fname, inputs, args)
      elif fname == "Affine":
          x = inputs[0]
  
          _, c_s, h_s, w_s = inputs[0].shape
          _, b_s = inputs[1].shape
          wd = inputs[1].d.copy()
          wd = np.reshape(wd, (h_s, w_s, c_s, b_s))
          wd = np.transpose(wd, (2, 0, 1, 3))
          wd = np.reshape(wd, (-1, b_s))
          w = nn.parameter.get_parameter_or_create(
              "w_cl", wd.shape, wd, False
          )
  
          b = inputs[2] if len(inputs) == 3 else None
          o = F.affine(x, w, b, **args)
      else:
          o = self._call_function(fname, inputs, args)
      return o
  
file_path: nnabla/python/src/nnabla/experimental/graph_converters/channel_first.py
imports: import nnabla
  import nnabla.functions
  import numpy
  from .graph_converter import FunctionModifier
label_desc: Use image node_id 3 for calling the ChannelFirstModifier obj's underlying member method code with example usage: obj.connect(fname, inputs, args) and returns: o