class_docstr: Dense Feature Stack Block
  
  - Stack is initialized with the input from above layers.
  - Iteratively the output of convolution layers is added to the feature stack.
  - Each sequential convolution is performed over all the previous stacked
    channels.
  
  Diagram example:
  
      feature_stack = [Input]
      feature_stack = [feature_stack, conv(feature_stack)]
      feature_stack = [feature_stack, conv(feature_stack)]
      feature_stack = [feature_stack, conv(feature_stack)]
      ...
      Output = [feature_stack, conv(feature_stack)]
docstr: :param input_tensor: tf tensor, input to the DenseFeatureStackBlock
  :param is_training: boolean, True if network is in training mode
  :param keep_prob: double, percentage of nodes to keep for drop-out
  :return: feature stack
docstr_tok: [":","param","input_tensor",":","tf","tensor",",","input","to","the","DenseFeatureStackBlock",":","param","is_training",":","boolean",",","True","if","network","is","in","training","mode",":","param","keep_prob",":","double",",","percentage","of","nodes","to","keep","for","drop-out",":","return",":","feature","stack"]
code: def layer_op(self, input_tensor, is_training=True, keep_prob=None):
      """
  
      :param input_tensor: tf tensor, input to the DenseFeatureStackBlock
      :param is_training: boolean, True if network is in training mode
      :param keep_prob: double, percentage of nodes to keep for drop-out
      :return: feature stack
      """
      # Create dense feature stack block
      dfs_block = self.create_block()
      # Initialize feature stack for block
      feature_stack = [input_tensor]
  
      # Create initial input mask for batch-wise dropout
      n_channels = input_tensor.shape.as_list()[-1]
      input_mask = tf.ones([n_channels]) > 0
  
      # Stack convolution outputs
      for i, conv in enumerate(dfs_block):
          # No dropout on last layer of the stack
          if i == len(dfs_block) - 1:
              keep_prob = None
  
          # Merge feature stack along channel dimension
          channel_dim = len(input_tensor.shape) - 1
          input_features = tf.concat(feature_stack, channel_dim)
  
          if self.use_bdo:
              output_features, new_input_mask = conv(
                  input_features,
                  input_mask=input_mask,
                  is_training=is_training,
                  keep_prob=keep_prob,
              )
              input_mask = tf.concat([input_mask, new_input_mask], 0)
          else:
              output_features = conv(
                  input_features,
                  is_training=is_training,
                  keep_prob=keep_prob,
              )
  
          feature_stack.append(output_features)
  
      # Unmask the convolution channels
      if self.use_bdo:
          # Modify the returning feature stack by:
          # 1. Removing the input of the DFS from the feature stack
          # 2. Unmasking the feature stack by filling in zeros
          # see: https://github.com/NifTK/NiftyNet/pull/101
  
          # Remove input of DFS from the feature stack
          conv_channels = tf.concat(feature_stack[1:], axis=-1)
  
          # Insert a channel with zeros to be placed
          # where channels were not calculated
          zero_channel = tf.zeros(conv_channels.shape[:-1])
          zero_channel = tf.expand_dims(zero_channel, axis=-1)
          conv_channels = tf.concat(
              [zero_channel, conv_channels], axis=-1
          )
  
          # Indices to keep
          int_mask = tf.cast(input_mask[n_channels:], tf.int32)
          indices = tf.cumsum(int_mask) * int_mask
  
          # Rearrange stack with zeros where channels were not calculated
          conv_channels = tf.gather(conv_channels, indices, axis=-1)
          feature_stack = [conv_channels]
  
      return feature_stack
  
imports: from __future__ import absolute_import, print_function
  import tensorflow
  from niftynet.io.misc_io import image3_axial
  from niftynet.layer import layer_util
  from niftynet.layer.affine_augmentation import AffineAugmentationLayer
  from niftynet.layer.base_layer import TrainableLayer
  from niftynet.layer.bn import BNLayer
  from niftynet.layer.channel_sparse_convolution import ChannelSparseConvolutionalLayer
  from niftynet.layer.convolution import ConvolutionalLayer
  from niftynet.layer.linear_resize import LinearResizeLayer
  from niftynet.layer.downsample import DownSampleLayer
  from niftynet.network.base_net import BaseNet
  from collections import namedtuple
label_desc: Use image node_id 3 for calling the DenseFeatureStackBlock obj's underlying member method code with example usage: obj.layer_op(input_tensor, is_training, keep_prob) and returns: feature_stack