class_docstr: ### Description
      A reimplementation of 2D UNet:
          Ronneberger et al., U-Net: Convolutional Networks for Biomedical
          Image Segmentation, MICCAI '15
  
  ### Building blocks
  [dBLOCK]        - Downsampling Block (conv 3x3, Relu + conv 3x3, Relu +  Max pooling)
  [BLOCK]         - Two layer Block (conv 3x3, Relu + conv 3x3, Relu)
  [uBLOCK]        - Upsampling Block (deconv 2x2 + crop and concat + conv 3x3, Relu + conv 3x3, Relu)
  [CONV]          - Classification block (conv 1x1)
  
  ### Diagram
  
  INPUT  -->  [dBLOCK] - - - - - - - - - - - - - - - -  [BLOCK] --> [CONV] --> OUTPUT
                  |                                       |
                  [dBLOCK] - - - - - - - - - - - - [uBLOCK]
                      |                              |
                      [dBLOCK]  - - - - - - - [uBLOCK]
                          |                      |
                          [dBLOCK]  - - - [uBLOCK]
                              |               |
                              ----[BLOCk] ----
  
  ### Constraints
docstr: :param images: tensor, input to the network
  :param is_training: boolean, True if network is in training mode
  :param unused_kwargs: other conditional arguments, not in use
  :return: tensor, output of the network
docstr_tok: [":","param","images",":","tensor",",","input","to","the","network",":","param","is_training",":","boolean",",","True","if","network","is","in","training","mode",":","param","unused_kwargs",":","other","conditional","arguments",",","not","in","use",":","return",":","tensor",",","output","of","the","network"]
code: def layer_op(self, images, is_training=True, **unused_kwargs):
      """
  
      :param images: tensor, input to the network
      :param is_training: boolean, True if network is in training mode
      :param unused_kwargs: other conditional arguments, not in use
      :return: tensor, output of the network
      """
      # contracting path
      output_1 = TwoLayerConv(self.n_fea[0], self.conv_params)(
          images, is_training=is_training
      )
      down_1 = Pooling(func="MAX", **self.pooling_params)(output_1)
  
      output_2 = TwoLayerConv(self.n_fea[1], self.conv_params)(
          down_1, is_training=is_training
      )
      down_2 = Pooling(func="MAX", **self.pooling_params)(output_2)
  
      output_3 = TwoLayerConv(self.n_fea[2], self.conv_params)(
          down_2, is_training=is_training
      )
      down_3 = Pooling(func="MAX", **self.pooling_params)(output_3)
  
      output_4 = TwoLayerConv(self.n_fea[3], self.conv_params)(
          down_3, is_training=is_training
      )
      down_4 = Pooling(func="MAX", **self.pooling_params)(output_4)
  
      output_5 = TwoLayerConv(self.n_fea[4], self.conv_params)(
          down_4, is_training=is_training
      )
  
      # expansive path
      up_4 = DeConv(self.n_fea[3], **self.deconv_params)(
          output_5, is_training=is_training
      )
      output_4 = CropConcat()(output_4, up_4)
      output_4 = TwoLayerConv(self.n_fea[3], self.conv_params)(
          output_4, is_training=is_training
      )
  
      up_3 = DeConv(self.n_fea[2], **self.deconv_params)(
          output_4, is_training=is_training
      )
      output_3 = CropConcat()(output_3, up_3)
      output_3 = TwoLayerConv(self.n_fea[2], self.conv_params)(
          output_3, is_training=is_training
      )
  
      up_2 = DeConv(self.n_fea[1], **self.deconv_params)(
          output_3, is_training=is_training
      )
      output_2 = CropConcat()(output_2, up_2)
      output_2 = TwoLayerConv(self.n_fea[1], self.conv_params)(
          output_2, is_training=is_training
      )
  
      up_1 = DeConv(self.n_fea[0], **self.deconv_params)(
          output_2, is_training=is_training
      )
      output_1 = CropConcat()(output_1, up_1)
      output_1 = TwoLayerConv(self.n_fea[0], self.conv_params)(
          output_1, is_training=is_training
      )
  
      # classification layer
      classifier = Conv(
          n_output_chns=self.num_classes,
          kernel_size=1,
          with_bias=True,
          feature_normalization=None,
      )
      output_tensor = classifier(output_1)
      tf.logging.info("output shape %s", output_tensor.shape)
      return output_tensor
  
imports: from __future__ import absolute_import, print_function
  import tensorflow
  from niftynet.layer.base_layer import TrainableLayer, Layer
  from niftynet.layer.convolution import ConvolutionalLayer
  from niftynet.layer.crop import CropLayer
  from niftynet.layer.deconvolution import DeconvolutionalLayer
  from niftynet.layer.downsample import DownSampleLayer
  from niftynet.layer.elementwise import ElementwiseLayer
  from niftynet.layer.linear_resize import LinearResizeLayer
  from niftynet.network.base_net import BaseNet
label_desc: Use image node_id 2 for calling the UNet2D obj's underlying member method code with example usage: obj.layer_op(images, is_training) and returns: output_tensor