class_docstr: This class defines a composite layer with optional components::
  
      convolution -> feature_normalization (default batch norm) -> activation -> dropout
  
  The b_initializer and b_regularizer are applied to the ConvLayer
  The w_initializer and w_regularizer are applied to the ConvLayer,
  the feature normalization layer, and the activation layer (for 'prelu')
code: def layer_op(self, input_tensor, is_training=None, keep_prob=None):
      conv_layer = ConvLayer(
          n_output_chns=self.n_output_chns,
          kernel_size=self.kernel_size,
          stride=self.stride,
          dilation=self.dilation,
          padding=self.padding,
          with_bias=self.with_bias,
          w_initializer=self.initializers["w"],
          w_regularizer=self.regularizers["w"],
          b_initializer=self.initializers["b"],
          b_regularizer=self.regularizers["b"],
          padding_constant=self.padding_constant,
          name="conv_",
      )
  
      if self.feature_normalization == "batch":
          if is_training is None:
              raise ValueError(
                  "is_training argument should be "
                  "True or False unless feature_normalization is False"
              )
          bn_layer = BNLayer(
              regularizer=self.regularizers["w"],
              moving_decay=self.moving_decay,
              eps=self.eps,
              name="bn_",
          )
      elif self.feature_normalization == "instance":
          in_layer = InstanceNormLayer(eps=self.eps, name="in_")
      elif self.feature_normalization == "group":
          gn_layer = GNLayer(
              regularizer=self.regularizers["w"],
              group_size=self.group_size,
              eps=self.eps,
              name="gn_",
          )
      if self.acti_func is not None:
          acti_layer = ActiLayer(
              func=self.acti_func,
              regularizer=self.regularizers["w"],
              name="acti_",
          )
  
      if keep_prob is not None:
          dropout_layer = ActiLayer(func="dropout", name="dropout_")
  
      def activation(output_tensor):
          if self.feature_normalization == "batch":
              output_tensor = bn_layer(output_tensor, is_training)
          elif self.feature_normalization == "instance":
              output_tensor = in_layer(output_tensor)
          elif self.feature_normalization == "group":
              output_tensor = gn_layer(output_tensor)
          if self.acti_func is not None:
              output_tensor = acti_layer(output_tensor)
          if keep_prob is not None:
              output_tensor = dropout_layer(
                  output_tensor, keep_prob=keep_prob
              )
          return output_tensor
  
      if self.preactivation:
          output_tensor = conv_layer(activation(input_tensor))
      else:
          output_tensor = activation(conv_layer(input_tensor))
  
      return output_tensor
  
imports: from __future__ import absolute_import, print_function
  import math
  import numpy
  import tensorflow
  from niftynet.layer import layer_util
  from niftynet.layer.activation import ActiLayer
  from niftynet.layer.base_layer import TrainableLayer
  from niftynet.layer.bn import BNLayer, InstanceNormLayer
  from niftynet.layer.gn import GNLayer
  from niftynet.utilities.util_common import look_up_operations
label_desc: Use image node_id 2 for calling the ConvolutionalLayer obj's underlying member method code with example usage: obj.layer_op(input_tensor, is_training, keep_prob) and returns: output_tensor, output_tensor