class_docstr: Channel sparse convolutions perform convolutions over
  a subset of image channels and generate a subset of output
  channels. This enables spatial dropout without wasted computations
class_docstr_tok: ["Channel","sparse","convolutions","perform","convolutions","over","a","subset","of","image","channels","and","generate","a","subset","of","output","channels",".","This","enables","spatial","dropout","without","wasted","computations"]
docstr: :param inputs: image to normalize. This typically represents a sparse
      subset of channels from a sparse convolution.
  :param is_training: boolean that is True during training.
      When True, the layer uses batch statistics for normalization and
      records a moving average of means and variances.
      When False, the layer uses previously computed moving averages
      for normalization.
  :param mask: 1-Tensor with a binary mask identifying the sparse
      channels represented in inputs
  :param use_local_stats:
  :return:
docstr_tok: [":","param","inputs",":","image","to","normalize",".","This","typically","represents","a","sparse","subset","of","channels","from","a","sparse","convolution",".",":","param","is_training",":","boolean","that","is","True","during","training",".","When","True",",","the","layer","uses","batch","statistics","for","normalization","and","records","a","moving","average","of","means","and","variances",".","When","False",",","the","layer","uses","previously","computed","moving","averages","for","normalization",".",":","param","mask",":","1-Tensor","with","a","binary","mask","identifying","the","sparse","channels","represented","in","inputs",":","param","use_local_stats",":",":","return",":"]
code: def layer_op(self, inputs, is_training, mask, use_local_stats=False):
      """
  
      :param inputs: image to normalize. This typically represents a sparse
          subset of channels from a sparse convolution.
      :param is_training: boolean that is True during training.
          When True, the layer uses batch statistics for normalization and
          records a moving average of means and variances.
          When False, the layer uses previously computed moving averages
          for normalization.
      :param mask: 1-Tensor with a binary mask identifying the sparse
          channels represented in inputs
      :param use_local_stats:
      :return:
      """
  
      if mask is None:
          mask = tf.ones([self.n_dense_channels]) > 0
      else:
          mask = mask
  
      input_shape = inputs.shape
      mask_shape = mask.shape
      # operates on all dims except the last dim
      params_shape = mask_shape[-1:]
      assert (
          params_shape[0] == self.n_dense_channels
      ), "Mask size {} must match n_dense_channels {}.".format(
          params_shape[0], self.n_dense_channels
      )
      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,
      )
      beta = tf.boolean_mask(beta, mask)
      gamma = tf.boolean_mask(gamma, mask)
  
      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)
      # only update masked moving averages
      mean_update = tf.dynamic_stitch(
          [
              tf.to_int32(tf.where(mask)[:, 0]),
              tf.to_int32(tf.where(~mask)[:, 0]),
          ],
          [mean, tf.boolean_mask(moving_mean, ~mask)],
      )
      variance_update = tf.dynamic_stitch(
          [
              tf.to_int32(tf.where(mask)[:, 0]),
              tf.to_int32(tf.where(~mask)[:, 0]),
          ],
          [variance, tf.boolean_mask(moving_variance, ~mask)],
      )
      update_moving_mean = moving_averages.assign_moving_average(
          moving_mean, mean_update, self.moving_decay
      ).op
      update_moving_variance = moving_averages.assign_moving_average(
          moving_variance, variance_update, self.moving_decay
      ).op
      tf.add_to_collection(tf.GraphKeys.UPDATE_OPS, update_moving_mean)
      tf.add_to_collection(
          tf.GraphKeys.UPDATE_OPS, update_moving_variance
      )
  
      # call the normalisation function
      if is_training or use_local_stats:
          outputs = tf.nn.batch_normalization(
              inputs,
              mean,
              variance,
              beta,
              gamma,
              self.eps,
              name="batch_norm",
          )
      else:
          outputs = tf.nn.batch_normalization(
              inputs,
              tf.boolean_mask(moving_mean, mask),
              tf.boolean_mask(moving_variance, mask),
              beta,
              gamma,
              self.eps,
              name="batch_norm",
          )
      outputs.set_shape(inputs.get_shape())
      return outputs
  
imports: from __future__ import absolute_import, print_function
  import math
  import numpy
  import tensorflow
  from tensorflow.python.training import moving_averages
  import niftynet.layer.bn
  import niftynet.layer.convolution
  import niftynet.layer.deconvolution
  from niftynet.layer import layer_util
  from niftynet.layer.activation import ActiLayer
  from niftynet.layer.base_layer import TrainableLayer
  from niftynet.layer.deconvolution import infer_output_dims
label_desc: Use image node_id 2 for calling the ChannelSparseBNLayer obj's underlying member method code with example usage: obj.layer_op(inputs, is_training, mask, use_local_stats) and returns: outputs