class_docstr: ### Description
      reimplementation of 3D U-net
        Çiçek et al., "3D U-Net: Learning dense Volumetric segmentation from
        sparse annotation", MICCAI '16
  
  ### Building blocks
  [dBLOCK]        - Downsampling UNet Block
  [uBLOCK]        - Upsampling UNet Block
  [nBLOCK]        - UNet Block with no final operation
  [CROP]          - Cropping layer
  
  ### Diagram
  
  INPUT  -->  [dBLOCK] - - - - - - - - - - - - - - - -  [nBLOCK] --> [CROP] --> OUTPUT
                  |                                       |
                  [dBLOCK] - - - - - - - - - - - - [uBLOCK]
                      |                              |
                      [dBLOCK]  - - - - - - - [uBLOCK]
                          |                      |
                          --------[uBLOCk] ------
  
  ### Constraints
   - Image size - 4 should be divisible by 8
   - Label size should be more than 88
   - border is 44
class_docstr_tok: ["#","#","#","Description","reimplementation","of","3D","U-net","\u00c7i\u00e7ek","et","al.",",","``","3D","U-Net",":","Learning","dense","Volumetric","segmentation","from","sparse","annotation","''",",","MICCAI","'16","#","#","#","Building","blocks","[","dBLOCK","]","-","Downsampling","UNet","Block","[","uBLOCK","]","-","Upsampling","UNet","Block","[","nBLOCK","]","-","UNet","Block","with","no","final","operation","[","CROP","]","-","Cropping","layer","#","#","#","Diagram","INPUT","--",">","[","dBLOCK","]","-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","[","nBLOCK","]","--",">","[","CROP","]","--",">","OUTPUT","|","|","[","dBLOCK","]","-","-","-","-","-","-","-","-","-","-","-","-","[","uBLOCK","]","|","|","[","dBLOCK","]","-","-","-","-","-","-","-","[","uBLOCK","]","|","|","--","--","--","--","[","uBLOCk","]","--","--","--","#","#","#","Constraints","-","Image","size","-","4","should","be","divisible","by","8","-","Label","size","should","be","more","than","88","-","border","is","44"]
docstr: :param images: tensor, input to the network
  :param is_training: boolean, True if network is in training mode
  :param layer_id: int, not in use
  :param unused_kwargs: other 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","layer_id",":","int",",","not","in","use",":","param","unused_kwargs",":","other","arguments",",","not","in","use",":","return",":","tensor",",","output","of","the","network"]
code: def layer_op(
      self, images, is_training=True, layer_id=-1, **unused_kwargs
  ):
      """
  
      :param images: tensor, input to the network
      :param is_training: boolean, True if network is in training mode
      :param layer_id: int, not in use
      :param unused_kwargs: other arguments, not in use
      :return: tensor, output of the network
      """
      # image_size  should be divisible by 8
      assert layer_util.check_spatial_dims(images, lambda x: x % 8 == 0)
      assert layer_util.check_spatial_dims(images, lambda x: x >= 89)
      block_layer = UNetBlock(
          "DOWNSAMPLE",
          (self.n_features[0], self.n_features[1]),
          (3, 3),
          with_downsample_branch=True,
          w_initializer=self.initializers["w"],
          w_regularizer=self.regularizers["w"],
          acti_func=self.acti_func,
          name="L1",
      )
      pool_1, conv_1 = block_layer(images, is_training)
      print(block_layer)
  
      block_layer = UNetBlock(
          "DOWNSAMPLE",
          (self.n_features[1], self.n_features[2]),
          (3, 3),
          with_downsample_branch=True,
          w_initializer=self.initializers["w"],
          w_regularizer=self.regularizers["w"],
          acti_func=self.acti_func,
          name="L2",
      )
      pool_2, conv_2 = block_layer(pool_1, is_training)
      print(block_layer)
  
      block_layer = UNetBlock(
          "DOWNSAMPLE",
          (self.n_features[2], self.n_features[3]),
          (3, 3),
          with_downsample_branch=True,
          w_initializer=self.initializers["w"],
          w_regularizer=self.regularizers["w"],
          acti_func=self.acti_func,
          name="L3",
      )
      pool_3, conv_3 = block_layer(pool_2, is_training)
      print(block_layer)
  
      block_layer = UNetBlock(
          "UPSAMPLE",
          (self.n_features[3], self.n_features[4]),
          (3, 3),
          with_downsample_branch=False,
          w_initializer=self.initializers["w"],
          w_regularizer=self.regularizers["w"],
          acti_func=self.acti_func,
          name="L4",
      )
      up_3, _ = block_layer(pool_3, is_training)
      print(block_layer)
  
      block_layer = UNetBlock(
          "UPSAMPLE",
          (self.n_features[3], self.n_features[3]),
          (3, 3),
          with_downsample_branch=False,
          w_initializer=self.initializers["w"],
          w_regularizer=self.regularizers["w"],
          acti_func=self.acti_func,
          name="R3",
      )
      concat_3 = ElementwiseLayer("CONCAT")(conv_3, up_3)
      up_2, _ = block_layer(concat_3, is_training)
      print(block_layer)
  
      block_layer = UNetBlock(
          "UPSAMPLE",
          (self.n_features[2], self.n_features[2]),
          (3, 3),
          with_downsample_branch=False,
          w_initializer=self.initializers["w"],
          w_regularizer=self.regularizers["w"],
          acti_func=self.acti_func,
          name="R2",
      )
      concat_2 = ElementwiseLayer("CONCAT")(conv_2, up_2)
      up_1, _ = block_layer(concat_2, is_training)
      print(block_layer)
  
      block_layer = UNetBlock(
          "NONE",
          (self.n_features[1], self.n_features[1], self.num_classes),
          (3, 3, 1),
          with_downsample_branch=True,
          w_initializer=self.initializers["w"],
          w_regularizer=self.regularizers["w"],
          acti_func=self.acti_func,
          name="R1_FC",
      )
      concat_1 = ElementwiseLayer("CONCAT")(conv_1, up_1)
  
      # for the last layer, upsampling path is not used
      _, output_tensor = block_layer(concat_1, is_training)
  
      crop_layer = CropLayer(border=44, name="crop-88")
      output_tensor = crop_layer(output_tensor)
      print(block_layer)
      return output_tensor
  
file_path: NiftyNet/niftynet/network/unet.py
imports: from __future__ import absolute_import, print_function
  from niftynet.layer import layer_util
  from niftynet.layer.base_layer import TrainableLayer
  from niftynet.layer.convolution import ConvolutionalLayer
  from niftynet.layer.deconvolution import DeconvolutionalLayer
  from niftynet.layer.downsample import DownSampleLayer
  from niftynet.layer.elementwise import ElementwiseLayer
  from niftynet.layer.crop import CropLayer
  from niftynet.utilities.util_common import look_up_operations
label_desc: Use image node_id 2 for calling the UNet3D obj's underlying member method code with example usage: obj.layer_op(images, is_training, layer_id) and returns: output_tensor