def resnet_v2_26(inputs, num_classes=None, is_training=True, global_pool=True, output_stride=None, reuse=None, scope='resnet_v2_26'): """ResNet-26 model of [1]. See resnet_v2() for arg and return description.""" blocks = [ resnet_utils.Block('block1', bottleneck, [(128, 64, 1)] * 2), resnet_utils.Block('block2', bottleneck, [(128, 64, 1)] * 2), resnet_utils.Block('block3', bottleneck, [(128, 64, 1)] * 2), resnet_utils.Block('block4', bottleneck, [(128, 64, 1)] + [(128, 64, 2)]) ] return resnet_v2(inputs, blocks, num_classes, is_training=is_training, global_pool=global_pool, output_stride=output_stride, include_root_block=False, reuse=reuse, scope=scope, conv1_num_outputs=128)
def resnet_v1_20(inputs, num_classes=None, is_training=True, global_pool=True, output_stride=None, reuse=None, scope='resnet_v1_20', **kwargs): """ResNet-20 model. See resnet_v1() for arg and return description.""" blocks = [ resnet_utils.Block('block1', bottleneck, [(64, 16, 1)] * 1 + [(64, 16, 2)]), resnet_utils.Block('block2', bottleneck, [(128, 32, 1)] * 1 + [(128, 32, 2)]), resnet_utils.Block('block3', bottleneck, [(256, 64, 1)] * 1 + [(256, 64, 2)]) ] root_block = [16, 3, 1] # num filters, filter size, stride return resnet_v1(inputs, blocks, num_classes, is_training, global_pool=global_pool, output_stride=output_stride, include_root_block=True, root_block=root_block, reuse=reuse, scope=scope, **kwargs)
def testEndPointsV1(self): """Test the end points of a tiny v1 bottleneck network.""" bottleneck = resnet_v1.bottleneck blocks = [ resnet_utils.Block('block1', bottleneck, [(4, 1, 1), (4, 1, 2)]), resnet_utils.Block('block2', bottleneck, [(8, 2, 1), (8, 2, 1)]) ] inputs = create_test_input(2, 32, 16, 3) with slim.arg_scope(resnet_utils.resnet_arg_scope()): _, end_points = self._resnet_plain(inputs, blocks, scope='tiny') expected = [ 'tiny/block1/unit_1/bottleneck_v1/shortcut', 'tiny/block1/unit_1/bottleneck_v1/conv1', 'tiny/block1/unit_1/bottleneck_v1/conv2', 'tiny/block1/unit_1/bottleneck_v1/conv3', 'tiny/block1/unit_2/bottleneck_v1/conv1', 'tiny/block1/unit_2/bottleneck_v1/conv2', 'tiny/block1/unit_2/bottleneck_v1/conv3', 'tiny/block2/unit_1/bottleneck_v1/shortcut', 'tiny/block2/unit_1/bottleneck_v1/conv1', 'tiny/block2/unit_1/bottleneck_v1/conv2', 'tiny/block2/unit_1/bottleneck_v1/conv3', 'tiny/block2/unit_2/bottleneck_v1/conv1', 'tiny/block2/unit_2/bottleneck_v1/conv2', 'tiny/block2/unit_2/bottleneck_v1/conv3' ] self.assertItemsEqual(expected, end_points)
def _resnet_small(self, inputs, num_classes=None, is_training=True, global_pool=True, output_stride=None, include_root_block=True, reuse=None, scope='resnet_v1_small'): """A shallow and thin ResNet v1 for faster tests.""" bottleneck = resnet_v1.bottleneck blocks = [ resnet_utils.Block('block1', bottleneck, [(4, 1, 1)] * 2 + [(4, 1, 2)]), resnet_utils.Block('block2', bottleneck, [(8, 2, 1)] * 2 + [(8, 2, 2)]), resnet_utils.Block('block3', bottleneck, [(16, 4, 1)] * 2 + [(16, 4, 2)]), resnet_utils.Block('block4', bottleneck, [(32, 8, 1)] * 2) ] return resnet_v1.resnet_v1(inputs, blocks, num_classes, is_training=is_training, global_pool=global_pool, output_stride=output_stride, include_root_block=include_root_block, reuse=reuse, scope=scope)
def resnet_v1_200(inputs, num_classes=None, is_training=True, global_pool=True, output_stride=None, reuse=None, scope='resnet_v1_200'): """ResNet-200 model of [2]. See resnet_v1() for arg and return description.""" blocks = [ resnet_utils.Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]), resnet_utils.Block('block2', bottleneck, [(512, 128, 1)] * 23 + [(512, 128, 2)]), resnet_utils.Block('block3', bottleneck, [(1024, 256, 1)] * 35 + [(1024, 256, 2)]), resnet_utils.Block('block4', bottleneck, [(2048, 512, 1)] * 3) ] return resnet_v1(inputs, blocks, num_classes, is_training, global_pool=global_pool, output_stride=output_stride, include_root_block=True, reuse=reuse, scope=scope)
def resnet_v1_101(inputs, num_classes=None, is_training=True, global_pool=True, output_stride=None, reuse=None, train_top_bn=None, dropout_keep_prob=1.0, scope='resnet_v1_101'): """ResNet-101 model of [1]. See resnet_v1() for arg and return description.""" blocks = [ resnet_utils.Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]), resnet_utils.Block('block2', bottleneck, [(512, 128, 1)] * 3 + [(512, 128, 2)]), resnet_utils.Block('block3', bottleneck, [(1024, 256, 1)] * 22 + [(1024, 256, 2)]), resnet_utils.Block('block4', bottleneck, [(2048, 512, 1)] * 3) ] return resnet_v1(inputs, blocks, num_classes, is_training, global_pool=global_pool, output_stride=output_stride, include_root_block=True, train_top_bn=train_top_bn, dropout_keep_prob=dropout_keep_prob, reuse=reuse, scope=scope)
def resnet_v2_152(inputs, num_classes=None, is_training=True, data_format='NCHW', global_pool=True, output_stride=None, reuse=None, scope='resnet_v2_152'): """ResNet-152 model of [1]. See resnet_v2() for arg and return description.""" blocks = [ resnet_utils.Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]), resnet_utils.Block('block2', bottleneck, [(512, 128, 1)] * 7 + [(512, 128, 2)]), resnet_utils.Block('block3', bottleneck, [(1024, 256, 1)] * 35 + [(1024, 256, 2)]), resnet_utils.Block('block4', bottleneck, [(2048, 512, 1)] * 3) ] return resnet_v2(inputs, blocks, num_classes, is_training=is_training, data_format=data_format, global_pool=global_pool, output_stride=output_stride, include_root_block=True, reuse=reuse, scope=scope)
def resnet_v1_distributions_baseline_50(inputs, num_classes=None, is_training=True, global_pool=True, output_stride=None, reuse=None, sample_number=1, scope='resnet_v1_50'): """ResNet-50 model of [1]. See resnet_v1() for arg and return description.""" blocks = [ resnet_utils.Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]), resnet_utils.Block('block2', bottleneck, [(512, 128, 1)] * 3 + [(512, 128, 2)]), resnet_utils.Block('block3', bottleneck, [(1024, 256, 1)] * 5 + [(1024, 256, 2)]), resnet_utils.Block('block4', bottleneck, [(2048, 512, 1)] * 3) ] return resnet_distributions_baseline_v1(inputs, blocks, num_classes, is_training, output_stride=output_stride, include_root_block=True, reuse=reuse, scope=scope, sample_number=sample_number)
def _atrousValues(self, bottleneck): """Verify the values of dense feature extraction by atrous convolution. Make sure that dense feature extraction by stack_blocks_dense() followed by subsampling gives identical results to feature extraction at the nominal network output stride using the simple self._stack_blocks_nondense() above. Args: bottleneck: The bottleneck function. """ blocks = [ resnet_utils.Block('block1', bottleneck, [(4, 1, 1), (4, 1, 2)]), resnet_utils.Block('block2', bottleneck, [(8, 2, 1), (8, 2, 2)]), resnet_utils.Block('block3', bottleneck, [(16, 4, 1), (16, 4, 2)]), resnet_utils.Block('block4', bottleneck, [(32, 8, 1), (32, 8, 1)]) ] nominal_stride = 8 # Test both odd and even input dimensions. height = 30 width = 31 with slim.arg_scope(resnet_utils.resnet_arg_scope()): with slim.arg_scope([slim.batch_norm], is_training=False): for output_stride in [1, 2, 4, 8, None]: with tf.Graph().as_default(): with self.test_session() as sess: tf.set_random_seed(0) inputs = create_test_input(1, height, width, 3) # Dense feature extraction followed by subsampling. output = resnet_utils.stack_blocks_dense( inputs, blocks, output_stride) if output_stride is None: factor = 1 else: factor = nominal_stride // output_stride output = resnet_utils.subsample(output, factor) # Make the two networks use the same weights. tf.get_variable_scope().reuse_variables() # Feature extraction at the nominal network rate. expected = self._stack_blocks_nondense( inputs, blocks) try: sess.run(tf.global_variables_initializer()) except AttributeError: sess.run(tf.initialize_all_variables()) output, expected = sess.run([output, expected]) self.assertAllClose(output, expected, atol=1e-4, rtol=1e-4)
def resnet_v2_block(scope, base_depth, num_units, stride, EPSILON=2.0, middle_pos=None, num_classes=1001): """Helper function for creating a resnet_v2 bottleneck block. Args: scope: The scope of the block. base_depth: The depth of the bottleneck layer for each unit. num_units: The number of units in the block. stride: The stride of the block, implemented as a stride in the last unit. All other units have stride=1. Returns: A resnet_v2 bottleneck block. """ if middle_pos is not None: return resnet_utils.Block(scope, bottleneck, [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': 1, 'EPSILON':EPSILON, }] * (middle_pos - 1) + [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': 1, 'EPSILON': EPSILON, 'middle':True, 'num_classes':num_classes }] + [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': 1, 'EPSILON':EPSILON, }] * (num_units - middle_pos - 1) + [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': stride, 'EPSILON': EPSILON, }]) else: return resnet_utils.Block(scope, bottleneck, [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': 1, 'EPSILON':EPSILON, }] * (num_units - 1) + [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': stride, 'EPSILON': EPSILON, }])
def resnet_v1_block(scope, base_depth, num_units, stride, inj_type=None, quant_min_max=None, inj_layer=None, inj_pos=None): """Helper function for creating a resnet_v1 bottleneck block. Args: scope: The scope of the block. base_depth: The depth of the bottleneck layer for each unit. num_units: The number of units in the block. stride: The stride of the block, implemented as a stride in the last unit. All other units have stride=1. Returns: A resnet_v1 bottleneck block. """ return resnet_utils.Block(scope, bottleneck, [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': 1, 'inj_type': inj_type, 'quant_min_max': quant_min_max, 'inj_layer': inj_layer, 'inj_pos': inj_pos }] * (num_units - 1) + [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': stride, 'inj_type': inj_type, 'quant_min_max': quant_min_max, 'inj_layer': inj_layer, 'inj_pos': inj_pos }])
def resnext_block(scope, base_depth, cardinality, bottleneck_type, num_units, stride): """Helper function for creating a resnext bottleneck block. Args: scope: The scope of the block. base_depth: The depth of the bottleneck layer for each group. cardinality: The number of the groups in the bottleneck bottleneck_type: The type of the bottleneck (b or c). num_units: The number of units in the block. stride: The stride of the block, implemented as a stride in the last unit. All other units have stride=1. Returns: A resnext bottleneck block. """ if bottleneck_type == 'b': bottleneck = bottleneck_b elif bottleneck_type == 'c': bottleneck = bottleneck_c else: raise ValueError('Unknown type of the bottleneck. Should be type b or c.') return resnet_utils.Block(scope, bottleneck, [{ 'unit_depth': base_depth, 'cardinality': cardinality, 'stride': 1 }] * (num_units - 1) + [{ 'unit_depth': base_depth, 'cardinality': cardinality, 'stride': stride }])
def resnet_v1_block(scope, base_depth, num_units, stride): """Helper function for creating a resnet_v1 bottleneck block. Args: scope: The scope of the block. base_depth: The depth of the bottleneck layer for each unit. num_units: The number of units in the block.bottleneck stride: The stride of the block, implemented as a stride in the last unit. All other units have stride=1. Returns: A resnet_v1 bottleneck block. bottleneck block residual block consists of 3 layers in this order: 1x1 convolution - 3x3 convolution - 1x1 convolution. The first and the last convolution is the bottleneck. It mostly just for practical consideration, as the first 1x1 convolution is being used to reduce the dimensionality, and the last 1x1 convolution is to restore it Above thinh is something to understand """ return resnet_utils.Block(scope, bottleneck, [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': 1 }] * (num_units - 1) + [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': stride }])
def _extract_box_classifier_features(self, proposal_feature_maps, scope): """Extracts second stage box classifier features. Args: proposal_feature_maps: A 4-D float tensor with shape [batch_size * self.max_num_proposals, crop_height, crop_width, depth] representing the feature map cropped to each proposal. scope: A scope name (unused). Returns: proposal_classifier_features: A 4-D float tensor with shape [batch_size * self.max_num_proposals, height, width, depth] representing box classifier features for each proposal. """ with tf.variable_scope(self._architecture, reuse=self._reuse_weights): with slim.arg_scope( resnet_utils.resnet_arg_scope( batch_norm_epsilon=1e-5, batch_norm_scale=True, weight_decay=self._weight_decay)): with slim.arg_scope([slim.batch_norm], is_training=False): blocks = [ resnet_utils.Block('block4', resnet_v1.bottleneck, [{ 'depth': 2048, 'depth_bottleneck': 512, 'stride': 1 }] * 3) ] proposal_classifier_features = resnet_utils.stack_blocks_dense( proposal_feature_maps, blocks) return proposal_classifier_features
def resnet_v2_block(scope, base_depth, num_units, stride, attention_module): """Helper function for creating a resnet_v2 bottleneck block. Args: scope: The scope of the block. base_depth: The depth of the bottleneck layer for each unit. num_units: The number of units in the block. stride: The stride of the block, implemented as a stride in the last unit. All other units have stride=1. Returns: A resnet_v2 bottleneck block. """ return resnet_utils.Block( scope, bottleneck, [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': 1, 'attention_module': attention_module }] * (num_units - 1) + [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': stride, 'attention_module': attention_module }])
def _extract_second_stage_features(self, proposal_feature_maps): """Extracts second stage features for final box encoding and class prediction. Args: proposal_feature_maps: float tensor of shape [batch_size * num_proposals, height_in, width_in, depth_in] Returns: proposal_classifier_features: float tensor of shape [batch_size * num_proposals, height_out, width_out, depth_out] """ with tf.variable_scope(self._resnet_name, reuse=self._reuse_weights): with slim.arg_scope( resnet_utils.resnet_arg_scope( batch_norm_epsilon=1e-5, batch_norm_scale=True, weight_decay=self._weight_decay)): blocks = [ resnet_utils.Block('block4', resnet_v1.bottleneck, [{ 'depth': 2048, 'depth_bottleneck': 512, 'stride': 1 }] * 3) ] proposal_classifier_features = resnet_utils.stack_blocks_dense( proposal_feature_maps, blocks) return proposal_classifier_features
def shufflenet_block(scope, base_depth, ngroups, num_units, stride): """Helper function for creating a resnext bottleneck block. Args: scope: The scope of the block. base_depth: The depth of the bottleneck layer for each group. cardinality: The number of the groups in the bottleneck bottleneck_type: The type of the bottleneck (b or c). num_units: The number of units in the block. stride: The stride of the block, implemented as a stride in the last unit. All other units have stride=1. Returns: A resnext bottleneck block. """ return resnet_utils.Block(scope, bottleneck, [{ 'depth': base_depth, 'ngroups': ngroups, 'stride': stride }] + [{ 'depth': base_depth, 'ngroups': ngroups, 'stride': 1 }] * (num_units - 1))
def resnet_v1_block(scope, base_depth, num_units, stride, initializers=None, split_model=False, insert_shift=False): """Helper function for creating a resnet_v1 bottleneck block. Args: scope: The scope of the block. base_depth: The depth of the bottleneck layer for each unit. num_units: The number of units in the block. stride: The stride of the block, implemented as a stride in the last unit. All other units have stride=1. initializers: Initializers for conv and batchnorm layers. key "bottleneckX", for 0-indexed bottleck id X, returns list of conv initializer kwargs for that bottleneck. split_model: Forwarded to block. Determines if model should be split at shift operations insert_shift: If true, inserts shift operation in front of every first conv1x1 within a block. Returns: A resnet_v1 bottleneck block. """ args = [] for i in range(num_units): s = stride if i == num_units - 1 else 1 args.append({ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': s, 'initializers': initializers[f"bottleneck{i}"], 'split_model': split_model, 'insert_shift': insert_shift }) return resnet_utils.Block(scope, bottleneck, args)
def _extract_box_classifier_features(self, proposal_feature_maps, scope): """Extracts second stage box classifier features. Args: proposal_feature_maps: A 4-D float tensor with shape [batch_size * self.max_num_proposals, crop_height, crop_width, depth] representing the feature map cropped to each proposal. scope: A scope name (unused). Returns: proposal_classifier_features: A 4-D float tensor with shape [batch_size * self.max_num_proposals, height, width, depth] representing box classifier features for each proposal. """ if self._second_stage_head_sel == 'res_block4' and self._first_stage_features_outblock == 4: raise ValueError('first_stage_features outs from res-block4, should use other head!') if self._second_stage_head_sel == 'res_block4': with tf.variable_scope(self._architecture, reuse=self._reuse_weights): with slim.arg_scope( resnet_utils.resnet_arg_scope( batch_norm_epsilon=1e-5, batch_norm_scale=True, weight_decay=self._weight_decay)): with slim.arg_scope([slim.batch_norm], is_training=self._train_batch_norm): blocks = [ resnet_utils.Block('block4', resnet_v1.bottleneck, [{ 'depth': self._second_stage_features_depth, 'depth_bottleneck': 512, 'stride': 1 }] * 3) ] proposal_classifier_features = resnet_utils.stack_blocks_dense( proposal_feature_maps, blocks) return proposal_classifier_features if self._second_stage_head_sel == 'light_head': # pass return proposal_classifier_features if self._second_stage_head_sel == 'direct_fc': # proposal_feature_maps = tf.reduce_mean(proposal_feature_maps, [1, 2], keep_dims=True, name='AvgPool') with tf.variable_scope(self._architecture, reuse=self._reuse_weights): if self._use_avgpool: proposal_feature_maps = tf.reduce_mean(proposal_feature_maps, [1, 2], keep_dims=True, name='RoIPool_AvgPool') with slim.arg_scope([slim.fully_connected], weights_regularizer=slim.l2_regularizer(self._weight_decay), normalizer_fn=slim.batch_norm): with slim.arg_scope([slim.batch_norm], is_training=self._train_batch_norm): proposal_classifier_features = slim.fully_connected( proposal_feature_maps, num_outputs=self._second_stage_features_depth, trainable=self._train_batch_norm) return proposal_classifier_features
def resnet_v1_block(scope, base_depth, num_units, stride, unit_fun): return resnet_utils.Block(scope, unit_fun, [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': 1 }] * (num_units - 1) + [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': stride }])
def attention_block(scope, hidden_size, num_layers, num_heads, attention_dropout, stride): return resnet_utils.Block(scope, self_attention, [{ 'hidden_size': hidden_size, 'num_heads': num_heads, 'attention_dropout': attention_dropout, 'stride': 1 }] * (num_layers - 1) + [{ 'hidden_size': hidden_size, 'num_heads': num_heads, 'attention_dropout': attention_dropout, 'stride': stride }])
def bulat_resnet_v2_152(inputs, num_classes=None, is_training=True, global_pool=True, output_stride=None, reuse=None, scope='resnet_v2_152'): """ResNet-152 model of [1]. See resnet_v2() for arg and return description.""" blocks = [ # 1x1 64 # 3x3 64 x 3 # 1x1 256 resnet_utils.Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]), # 1x1 128 # 3x3 128 x 8 # 1x1 512 resnet_utils.Block('block2', bottleneck, [(512, 128, 1)] * 7 + [(512, 128, 2)]), # 1x1 256 # 3x3 256 x 36 # 1x1 1024 resnet_utils.Block('block3', bottleneck, [(1024, 256, 1)] * 37 + [(1024, 256, 2)]), # 1x1 512 # 3x3 512 x 3 # 1x1 2048 resnet_utils.Block('block4', bottleneck, [(2048, 512, 1)] * 3) ] return bulat_resnet_v2(inputs, blocks, num_classes, is_training=is_training, global_pool=global_pool, output_stride=output_stride, include_root_block=True, reuse=reuse, scope=scope)
def resnet_v1_block_pruned(scope, convDictList, num_units): """Helper function for creating a resnet_v1 bottleneck block. Args: scope: The scope of the block. base_depth: The depth of the bottleneck layer for each unit. num_units: The number of units in the block. stride: The stride of the block, implemented as a stride in the last unit. All other units have stride=1. Returns: A resnet_v1 bottleneck block. """ assert (len(convDictList) == num_units) return resnet_utils.Block(scope, bottleneck_pruned, convDictList)
def resnet_v1_base_block(scope, base_depth, num_units, stride): """Helper function for creating a resnet_v1 base block. Args: scope: The scope of the block. base_depth: The depth of the bottleneck layer for each unit. num_units: The number of units in the block. stride: The stride of the block, implemented as a stride in the last unit. All other units have stride=1. Returns: A resnet_v1 base block. """ return resnet_utils.Block(scope, building_block, [{ 'depth': base_depth, 'stride': 1 }] * (num_units - 1) + [{ 'depth': base_depth, 'stride': stride }])
def resnet_v1_block(scope, base_depth, num_units, stride): """Helper function for creating a resnet_v1 bottleneck block. Args: scope: The scope of the block. base_depth: The depth of the bottleneck layer for each unit. num_units: The number of units in the block. stride: The stride of the block, implemented as a stride in the first unit. All other units have stride=1. Note that the default slim implementation places the stride in the last unit, which is less memory efficient and a deviation from the resnet paper. Returns: A resnet_v1 bottleneck block. """ return resnet_utils.Block(scope, resnet_v1.bottleneck, [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': stride }] + [{ 'depth': base_depth * 4, 'depth_bottleneck': base_depth, 'stride': 1 }] * (num_units - 1))
Returns: proposal_classifier_features: A 4-D float tensor with shape [batch_size * self.max_num_proposals, height, width, depth] representing box classifier features for each proposal. """ with tf.variable_scope(self._architecture, reuse=self._reuse_weights): with slim.arg_scope( resnet_utils.resnet_arg_scope( batch_norm_epsilon=1e-5, batch_norm_scale=True, weight_decay=self._weight_decay)): with slim.arg_scope([slim.batch_norm], is_training=False): blocks = [ resnet_utils.Block('block4', resnet_v1.bottleneck, [{ 'depth': 2048, 'depth_bottleneck': 512, 'stride': 1 }] * 3) ] proposal_classifier_features = resnet_utils.stack_blocks_dense( proposal_feature_maps, blocks) return proposal_classifier_features class FasterRCNNResnet50FeatureExtractor(FasterRCNNResnetV1FeatureExtractor): //基础上述基类,RCNN 50 特征提取器 """Faster R-CNN Resnet 50 feature extractor implementation.""" def __init__(self, is_training, first_stage_features_stride, reuse_weights=None,