class_docstr: Batch normalisation layer, with trainable mean value 'beta' and
  std 'gamma'.  'beta' is initialised to 0.0 and 'gamma' is initialised
  to 1.0.  This class assumes 'beta' and 'gamma' share the same type_str of
  regulariser.
code: def layer_op(self, inputs, is_training, use_local_stats=False):
      input_shape = inputs.shape
  
      # operates on all dims except the last dim
      params_shape = input_shape[-1:]
      axes = list(range(input_shape.ndims - 1))
  
      # create trainable variables and moving average variables
      beta = tf.get_variable(
          "beta",
          shape=params_shape,
          initializer=self.initializers["beta"],
          regularizer=self.regularizers["beta"],
          dtype=tf.float32,
          trainable=True,
      )
      gamma = tf.get_variable(
          "gamma",
          shape=params_shape,
          initializer=self.initializers["gamma"],
          regularizer=self.regularizers["gamma"],
          dtype=tf.float32,
          trainable=True,
      )
  
      collections = [tf.GraphKeys.GLOBAL_VARIABLES]
      moving_mean = tf.get_variable(
          "moving_mean",
          shape=params_shape,
          initializer=self.initializers["moving_mean"],
          dtype=tf.float32,
          trainable=False,
          collections=collections,
      )
      moving_variance = tf.get_variable(
          "moving_variance",
          shape=params_shape,
          initializer=self.initializers["moving_variance"],
          dtype=tf.float32,
          trainable=False,
          collections=collections,
      )
  
      # mean and var
      mean, variance = tf.nn.moments(inputs, axes)
      update_moving_mean = moving_averages.assign_moving_average(
          moving_mean, mean, self.moving_decay
      ).op
      update_moving_variance = moving_averages.assign_moving_average(
          moving_variance, variance, self.moving_decay
      ).op
      tf.add_to_collection(BN_COLLECTION, update_moving_mean)
      tf.add_to_collection(BN_COLLECTION, update_moving_variance)
  
      # call the normalisation function
      if is_training or use_local_stats:
          # with tf.control_dependencies(
          #         [update_moving_mean, update_moving_variance]):
          outputs = tf.nn.batch_normalization(
              inputs,
              mean,
              variance,
              beta,
              gamma,
              self.eps,
              name="batch_norm",
          )
      else:
          outputs = tf.nn.batch_normalization(
              inputs,
              moving_mean,
              moving_variance,
              beta,
              gamma,
              self.eps,
              name="batch_norm",
          )
      outputs.set_shape(inputs.get_shape())
      return outputs
  
file_path: NiftyNet/niftynet/layer/bn.py
imports: from __future__ import absolute_import, print_function
  import tensorflow
  from tensorflow.python.training import moving_averages
  from niftynet.layer.base_layer import TrainableLayer
label_desc: Use image node_id 2 for calling the BNLayer obj's underlying member method code with example usage: obj.layer_op(inputs, is_training, use_local_stats) and returns: outputs