def get_version():
    version = {}
    with open("bqueryd/version.py") as fp:
        exec (fp.read(), version)
    return version
def __call__(self, inputs, training):
    """Add operations to classify a batch of input images.

    Args:
      inputs: A Tensor representing a batch of input images.
      training: A boolean. Set to True to add operations required only when
        training the classifier.

    Returns:
      A logits Tensor with shape [<batch_size>, self.num_classes].
    """

    with self._model_variable_scope():
      if self.data_format == 'channels_first':
        # Convert the inputs from channels_last (NHWC) to channels_first (NCHW).
        # This provides a large performance boost on GPU. See
        # https://www.tensorflow.org/performance/performance_guide#data_formats
        inputs = tf.transpose(a=inputs, perm=[0, 3, 1, 2])

      inputs = conv2d_fixed_padding(
          inputs=inputs,
          filters=self.num_filters,
          kernel_size=self.kernel_size,
          strides=self.conv_stride,
          data_format=self.data_format,
          name='initial_input')
      inputs = tf.identity(inputs, 'initial_conv')

      # We do not include batch normalization or activation functions in V2
      # for the initial conv1 because the first ResNet unit will perform these
      # for both the shortcut and non-shortcut paths as part of the first
      # block's projection. Cf. Appendix of [2].
      if self.resnet_version == 1:
        inputs = batch_norm(inputs, training, self.data_format)
        inputs = tf.nn.relu(inputs)

      if self.first_pool_size:
        inputs = tf.compat.v1.layers.max_pooling2d(
            inputs=inputs,
            pool_size=self.first_pool_size,
            strides=self.first_pool_stride,
            padding='SAME',
            data_format=self.data_format)
        inputs = tf.identity(inputs, 'initial_max_pool')

      for i, num_blocks in enumerate(self.block_sizes):
        # We now have 4 block layers, but the last does not
        # double the number of filters.
        # We also skip the projection shortcut in the first block layer.
        num_filters = self.num_filters * min((2**i), 4)
        shortcut = i != 0
        inputs = block_layer(
            inputs=inputs,
            filters=num_filters,
            bottleneck=self.bottleneck,
            block_fn=self.block_fn,
            blocks=num_blocks,
            strides=self.block_strides[i],
            training=training,
            name='block_layer{}'.format(i + 1),
            data_format=self.data_format,
            shortcut=shortcut)

      # Skip the last BN+relu.
      # Only apply the BN and ReLU for model that does pre_activation in each
      # building/bottleneck block, eg resnet V2.
      # if self.pre_activation:
      #   inputs = batch_norm(inputs, training, self.data_format,
      #     name='pre_act'+'batch_norm')
      #   inputs = tf.nn.relu(inputs,name='pre_act'+'relu')

      # The current top layer has shape
      # `batch_size x pool_size x pool_size x final_size`.
      # ResNet does an Average Pooling layer over pool_size,
      # but that is the same as doing a reduce_mean. We do a reduce_mean
      # here because it performs better than AveragePooling2D.
      # Also perform max-pooling, and concat results.
      axes = [2, 3] if self.data_format == 'channels_first' else [1, 2]
      avg_pooled = tf.reduce_mean(input_tensor=inputs, axis=axes, keepdims=True)
      avg_pooled = tf.squeeze(avg_pooled, axes)
      max_pooled = tf.reduce_max(input_tensor=inputs, axis=axes, keepdims=True)
      max_pooled = tf.squeeze(max_pooled, axes)
      inputs = tf.concat([avg_pooled, max_pooled], axis=1)
      inputs = tf.identity(inputs, 'final_pooling')

      inputs = tf.compat.v1.layers.dense(
          inputs=inputs, units=self.num_classes, reuse=tf.AUTO_REUSE)
      inputs = tf.identity(inputs, 'final_dense')
      return inputs