class_docstr: Implementation of:
  
  SubPixel Convolution initialised with ICNR initialisation
  and followed by an AveragePooling
  
  Limitations:
  
  If ICNR initialization is used then the upsample factor
  MUST be an integer
  
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Shi, W., Caballero, J., Huszár, F., Totz, J., Aitken, A.P.,
  Bishop, R., Rueckert, D. and Wang, Z., 2016.
  
  Real-time single image and video super-resolution using an
  efficient sub-pixel convolutional neural network.
  
  In Proceedings of the IEEE conference on computer vision
  and pattern recognition (pp. 1874-1883).
  
  https://www.cv-foundation.org/openaccess/content_cvpr_2016/
  papers/Shi_Real-Time_Single_Image_CVPR_2016_paper.pdf
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Aitken, A., Ledig, C., Theis, L., Caballero, J., Wang, Z.
  and Shi, W., 2017.
  
  Checkerboard artifact free sub-pixel convolution: A note on
  sub-pixel convolution, resize convolution and convolution
  resize.
  
  arXiv preprint arXiv:1707.02937.
  
  https://arxiv.org/pdf/1707.02937.pdf
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Sugawara, Y., Shiota, S. and Kiya, H., 2018, October.
  
  Super-resolution using convolutional neural networks without
  any checkerboard artifacts.
  
  In 2018 25th IEEE International Conference on Image Processing
  (ICIP) (pp. 66-70). IEEE.
  
  https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=8451141
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
code: def layer_op(self, lr_image, is_training=True, keep_prob=1.0):
      input_shape = lr_image.get_shape().as_list()
      batch_size = input_shape.pop(0)
  
      if batch_size is None:
          raise ValueError("The batch size must be known and fixed.")
      if any(i is None or i <= 0 for i in input_shape):
          raise ValueError("The image shape must be known in advance.")
  
      # Making sure there are enough features channels for the
      # periodic shuffling
      features = ConvolutionalLayer(
          n_output_chns=(
              self.n_output_chns
              * self.upsample_factor ** (len(input_shape) - 1)
          ),
          kernel_size=self.kernel_size,
          acti_func=None,
          name="subpixel_conv",
          **self.conv_layer_params,
      )(
          input_tensor=lr_image,
          is_training=is_training,
          keep_prob=keep_prob,
      )
  
      # Setting the number of output features to the known value
      # obtained from the input shape results in a ValueError as
      # of TF 1.12
      sr_image = tf.contrib.periodic_resample.periodic_resample(
          values=features,
          shape=(
              [batch_size]
              + [self.upsample_factor * i for i in input_shape[:-1]]
              + [None]
          ),
          name="periodic_shuffle",
      )
  
      # Averaging out the values without downsampling to counteract
      # the periodicity of periodic shuffling as per Sugawara et al.
      if self.use_avg:
          sr_image = DownSampleLayer(
              func="AVG",
              kernel_size=self.upsample_factor,
              stride=1,
              padding="SAME",
              name="averaging",
          )(input_tensor=sr_image)
  
      return sr_image
  
file_path: NiftyNet/niftynet/layer/subpixel.py
imports: from __future__ import absolute_import, print_function
  import tensorflow
  from niftynet.layer.base_layer import TrainableLayer
  from niftynet.layer.convolution import ConvolutionalLayer
  from niftynet.layer.downsample import DownSampleLayer
label_desc: Use image node_id 2 for calling the SubPixelLayer obj's underlying member method code with example usage: obj.layer_op(lr_image, is_training, keep_prob) and returns: sr_image