'Extracts RPN features.
This function extracts two feature maps: a feature map to be directly
fed to a box predictor (to predict location and objectness scores for
proposals) and a feature map from which to crop regions which will then
be sent to the second stage box classifier.
Args:
preprocessed_inputs: a [batch, height, width, channels] image tensor.
Returns:
rpn_box_predictor_features: A 4-D float32 tensor with shape
[batch, height, width, depth] to be used for predicting proposal boxes
and corresponding objectness scores.
rpn_features_to_crop: A 4-D float32 tensor with shape
[batch, height, width, depth] representing image features to crop using
the proposals boxes.
anchors: A BoxList representing anchors (for the RPN) in
absolute coordinates.
image_shape: A 1-D tensor representing the input image shape.'

def _extract_rpn_feature_maps(self, preprocessed_inputs):

    image_shape = tf.shape(preprocessed_inputs)
    rpn_features_to_crop = self._feature_extractor.extract_proposal_features(preprocessed_inputs, scope=self.first_stage_feature_extractor_scope)
    feature_map_shape = tf.shape(rpn_features_to_crop)
    anchors = self._first_stage_anchor_generator.generate([(feature_map_shape[1], feature_map_shape[2])])
    with slim.arg_scope(self._first_stage_box_predictor_arg_scope):
        kernel_size = self._first_stage_box_predictor_kernel_size
        rpn_box_predictor_features = slim.conv2d(rpn_features_to_crop, self._first_stage_box_predictor_depth, kernel_size=[kernel_size, kernel_size], rate=self._first_stage_atrous_rate, activation_fn=tf.nn.relu6)
    return (rpn_box_predictor_features, rpn_features_to_crop, anchors, image_shape)
