code: """Some special pupropse layers for SSD."""
  
  import keras.backend as K
  from keras.engine.topology import InputSpec
  from keras.engine.topology import Layer
  import numpy as np
  import tensorflow as tf
  
  
  class Normalize(Layer):
      """Normalization layer as described in ParseNet paper.
  
      # Arguments
          scale: Default feature scale.
  
      # Input shape
          4D tensor with shape:
          `(samples, channels, rows, cols)` if dim_ordering='th'
          or 4D tensor with shape:
          `(samples, rows, cols, channels)` if dim_ordering='tf'.
  
      # Output shape
          Same as input
  
      # References
          http://cs.unc.edu/~wliu/papers/parsenet.pdf
  
      #TODO
          Add possibility to have one scale for all features.
      """
      def __init__(self, scale, **kwargs):
          if K.image_dim_ordering() == 'tf':
              self.axis = 3
          else:
              self.axis = 1
          self.scale = scale
          super(Normalize, self).__init__(**kwargs)
  
      def build(self, input_shape):
          self.input_spec = [InputSpec(shape=input_shape)]
          shape = (input_shape[self.axis],)
          init_gamma = self.scale * np.ones(shape)
          self.gamma = K.variable(init_gamma, name='{}_gamma'.format(self.name))
          self.trainable_weights = [self.gamma]
  
      def call(self, x, mask=None):
          output = K.l2_normalize(x, self.axis)
          output *= self.gamma
          return output
  
  
  class PriorBox(Layer):
      """Generate the prior boxes of designated sizes and aspect ratios.
  
      # Arguments
          img_size: Size of the input image as tuple (w, h).
          min_size: Minimum box size in pixels.
          max_size: Maximum box size in pixels.
          aspect_ratios: List of aspect ratios of boxes.
          flip: Whether to consider reverse aspect ratios.
          variances: List of variances for x, y, w, h.
          clip: Whether to clip the prior's coordinates
              such that they are within [0, 1].
  
      # Input shape
          4D tensor with shape:
          `(samples, channels, rows, cols)` if dim_ordering='th'
          or 4D tensor with shape:
          `(samples, rows, cols, channels)` if dim_ordering='tf'.
  
      # Output shape
          3D tensor with shape:
          (samples, num_boxes, 8)
  
      # References
          https://arxiv.org/abs/1512.02325
  
      #TODO
          Add possibility not to have variances.
          Add Theano support
      """
      def __init__(self, img_size, min_size, max_size=None, aspect_ratios=None,
                   flip=True, variances=[0.1], clip=True, **kwargs):
          if K.image_dim_ordering() == 'tf':
              self.waxis = 2
              self.haxis = 1
          else:
              self.waxis = 3
              self.haxis = 2
          self.img_size = img_size
          if min_size <= 0:
              raise Exception('min_size must be positive.')
          self.min_size = min_size
          self.max_size = max_size
          self.aspect_ratios = [1.0]
          if max_size:
              if max_size < min_size:
                  raise Exception('max_size must be greater than min_size.')
              self.aspect_ratios.append(1.0)
          if aspect_ratios:
              for ar in aspect_ratios:
                  if ar in self.aspect_ratios:
                      continue
                  self.aspect_ratios.append(ar)
                  if flip:
                      self.aspect_ratios.append(1.0 / ar)
          self.variances = np.array(variances)
          self.clip = True
          super(PriorBox, self).__init__(**kwargs)
  
      # def get_output_shape_for(self, input_shape):
      def compute_output_shape(self, input_shape):
          num_priors_ = len(self.aspect_ratios)
          layer_width = input_shape[self.waxis]
          layer_height = input_shape[self.haxis]
          num_boxes = num_priors_ * layer_width * layer_height
          return (input_shape[0], num_boxes, 8)
  
      def call(self, x, mask=None):
          if hasattr(x, '_keras_shape'):
              input_shape = x._keras_shape
          elif hasattr(K, 'int_shape'):
              input_shape = K.int_shape(x)
          layer_width = input_shape[self.waxis]
          layer_height = input_shape[self.haxis]
          img_width = self.img_size[0]
          img_height = self.img_size[1]
          # define prior boxes shapes
          box_widths = []
          box_heights = []
          for ar in self.aspect_ratios:
              if ar == 1 and len(box_widths) == 0:
                  box_widths.append(self.min_size)
                  box_heights.append(self.min_size)
              elif ar == 1 and len(box_widths) > 0:
                  box_widths.append(np.sqrt(self.min_size * self.max_size))
                  box_heights.append(np.sqrt(self.min_size * self.max_size))
              elif ar != 1:
                  box_widths.append(self.min_size * np.sqrt(ar))
                  box_heights.append(self.min_size / np.sqrt(ar))
          box_widths = 0.5 * np.array(box_widths)
          box_heights = 0.5 * np.array(box_heights)
          # define centers of prior boxes
          step_x = img_width / layer_width
          step_y = img_height / layer_height
          linx = np.linspace(0.5 * step_x, img_width - 0.5 * step_x,
                             layer_width)
          liny = np.linspace(0.5 * step_y, img_height - 0.5 * step_y,
                             layer_height)
          centers_x, centers_y = np.meshgrid(linx, liny)
          centers_x = centers_x.reshape(-1, 1)
          centers_y = centers_y.reshape(-1, 1)
          # define xmin, ymin, xmax, ymax of prior boxes
          num_priors_ = len(self.aspect_ratios)
          prior_boxes = np.concatenate((centers_x, centers_y), axis=1)
          prior_boxes = np.tile(prior_boxes, (1, 2 * num_priors_))
          prior_boxes[:, ::4] -= box_widths
          prior_boxes[:, 1::4] -= box_heights
          prior_boxes[:, 2::4] += box_widths
          prior_boxes[:, 3::4] += box_heights
          prior_boxes[:, ::2] /= img_width
          prior_boxes[:, 1::2] /= img_height
          prior_boxes = prior_boxes.reshape(-1, 4)
          if self.clip:
              prior_boxes = np.minimum(np.maximum(prior_boxes, 0.0), 1.0)
          # define variances
          num_boxes = len(prior_boxes)
          if len(self.variances) == 1:
              variances = np.ones((num_boxes, 4)) * self.variances[0]
          elif len(self.variances) == 4:
              variances = np.tile(self.variances, (num_boxes, 1))
          else:
              raise Exception('Must provide one or four variances.')
          prior_boxes = np.concatenate((prior_boxes, variances), axis=1)
          prior_boxes_tensor = K.expand_dims(K.variable(prior_boxes), 0)
          if K.backend() == 'tensorflow':
              pattern = [tf.shape(x)[0], 1, 1]
              prior_boxes_tensor = tf.tile(prior_boxes_tensor, pattern)
          elif K.backend() == 'theano':
              #TODO
              pass
          return prior_boxes_tensor
  
apis: numpy.maximum numpy.sqrt numpy.linspace numpy.meshgrid tensorflow.shape numpy.tile numpy.ones numpy.concatenate numpy.array tensorflow.tile
api_extract: [(47, 'keras.backend.l2_normalize', 'K.l2_normalize', (['x', 'self.axis'], {}), True, 'import keras.backend as K\n'), (107, 'numpy.array', 'np.array', (['variances'], {}), True, 'import numpy as np\n'), (146, 'numpy.linspace', 'np.linspace', (['(0.5 * step_x)', '(img_width - 0.5 * step_x)', 'layer_width'], {}), True, 'import numpy as np\n'), (148, 'numpy.linspace', 'np.linspace', (['(0.5 * step_y)', '(img_height - 0.5 * step_y)', 'layer_height'], {}), True, 'import numpy as np\n'), (150, 'numpy.meshgrid', 'np.meshgrid', (['linx', 'liny'], {}), True, 'import numpy as np\n'), (155, 'numpy.concatenate', 'np.concatenate', (['(centers_x, centers_y)'], {'axis': '(1)'}), True, 'import numpy as np\n'), (156, 'numpy.tile', 'np.tile', (['prior_boxes', '(1, 2 * num_priors_)'], {}), True, 'import numpy as np\n'), (174, 'numpy.concatenate', 'np.concatenate', (['(prior_boxes, variances)'], {'axis': '(1)'}), True, 'import numpy as np\n'), (32, 'keras.backend.image_dim_ordering', 'K.image_dim_ordering', ([], {}), True, 'import keras.backend as K\n'), (40, 'keras.engine.topology.InputSpec', 'InputSpec', ([], {'shape': 'input_shape'}), False, 'from keras.engine.topology import InputSpec\n'), (42, 'numpy.ones', 'np.ones', (['shape'], {}), True, 'import numpy as np\n'), (84, 'keras.backend.image_dim_ordering', 'K.image_dim_ordering', ([], {}), True, 'import keras.backend as K\n'), (141, 'numpy.array', 'np.array', (['box_widths'], {}), True, 'import numpy as np\n'), (142, 'numpy.array', 'np.array', (['box_heights'], {}), True, 'import numpy as np\n'), (175, 'keras.backend.variable', 'K.variable', (['prior_boxes'], {}), True, 'import keras.backend as K\n'), (176, 'keras.backend.backend', 'K.backend', ([], {}), True, 'import keras.backend as K\n'), (178, 'tensorflow.tile', 'tf.tile', (['prior_boxes_tensor', 'pattern'], {}), True, 'import tensorflow as tf\n'), (123, 'keras.backend.int_shape', 'K.int_shape', (['x'], {}), True, 'import keras.backend as K\n'), (165, 'numpy.maximum', 'np.maximum', (['prior_boxes', '(0.0)'], {}), True, 'import numpy as np\n'), (169, 'numpy.ones', 'np.ones', (['(num_boxes, 4)'], {}), True, 'import numpy as np\n'), (171, 'numpy.tile', 'np.tile', (['self.variances', '(num_boxes, 1)'], {}), True, 'import numpy as np\n'), (179, 'keras.backend.backend', 'K.backend', ([], {}), True, 'import keras.backend as K\n'), (177, 'tensorflow.shape', 'tf.shape', (['x'], {}), True, 'import tensorflow as tf\n'), (136, 'numpy.sqrt', 'np.sqrt', (['(self.min_size * self.max_size)'], {}), True, 'import numpy as np\n'), (137, 'numpy.sqrt', 'np.sqrt', (['(self.min_size * self.max_size)'], {}), True, 'import numpy as np\n'), (139, 'numpy.sqrt', 'np.sqrt', (['ar'], {}), True, 'import numpy as np\n'), (140, 'numpy.sqrt', 'np.sqrt', (['ar'], {}), True, 'import numpy as np\n')]