def separable_resBlock(self, x, num_outputs, stride=1, activation_fn=tf.nn.relu, normalizer_fn=layers.batch_norm, scope=None): residual_flag = self.residual and (stride == 1 and num_outputs == x.get_shape().as_list()[self.channel_axis]) with tf.variable_scope(scope, 'resBlock'): # channel_split shortcut, x = self._channel_split(x) if stride != 1: shortcut = layers.separable_conv2d(shortcut, num_outputs, kernel_size=3, stride=stride, scope='separable_conv_shortcut_3x3') shortcut = layers.conv2d(shortcut, num_outputs, kernel_size=1, stride=1, scope='conv_shortcut_1x1') if residual_flag: res_shortcut = x x = layers.conv2d(x, num_outputs, kernel_size=1, stride=1, scope='conv1_1x1',) x = layers.separable_conv2d(x, num_outputs, kernel_size=3, stride=stride, scope='separable_conv2_3x3') x = layers.conv2d(x, num_outputs, kernel_size=1, stride=1, scope='conv3_1x1') if self.se: x = self._squeeze_excitation(x) if residual_flag: x += res_shortcut # concat x = tf.concat([shortcut, x], axis=self.channel_axis) x = self._channel_shuffle(x) return x
def bottleneck(inputs, depth, depth_bottleneck, stride, rate=1, outputs_collections=None, scope=None): """Bottleneck residual unit variant with BN after convolutions. This is the original residual unit proposed in [1]. See Fig. 1(a) of [2] for its definition. Note that we use here the bottleneck variant which has an extra bottleneck layer. When putting together two consecutive ResNet blocks that use this unit, one should use stride = 2 in the last unit of the first block. Args: inputs: A tensor of size [batch, height, width, channels]. depth: The depth of the ResNet unit output. depth_bottleneck: The depth of the bottleneck layers. stride: The ResNet unit's stride. Determines the amount of downsampling of the units output compared to its input. rate: An integer, rate for atrous convolution. outputs_collections: Collection to add the ResNet unit output. scope: Optional variable_scope. use_bounded_activations: Whether or not to use bounded activations. Bounded activations better lend themselves to quantized inference. Returns: The ResNet unit's output. """ with variable_scope.variable_scope(scope, 'bottleneck_v1', [inputs]) as sc: depth_in = utils.last_dimension(inputs.get_shape(), min_rank=4) if depth == depth_in: shortcut = resnet_utils.subsample(inputs, stride, 'shortcut') else: shortcut = layers.conv2d( inputs, depth, [1, 1], stride=stride, activation_fn=None, scope='shortcut') residual = layers.conv2d(inputs, depth_bottleneck, [1, 1], stride=1, scope='conv1') # I don't know use activation_fn? #residual = resnet_utils.conv2d_same(residual, depth_bottleneck, 3, stride, # rate=rate, scope='conv2') if stride == 1: residual = layers.separable_conv2d(residual, depth_bottleneck, [3,3], depth_multiplier=1,stride=1,scope='dws_conv2') else: residual = layers.separable_conv2d(residual, depth_bottleneck, [3,3], depth_multiplier=1,stride=stride,scope='dws_conv2') residual = layers.conv2d(residual, depth, [1, 1], stride=1, activation_fn=None, scope='conv3') output = nn_ops.relu(shortcut + residual) return utils.collect_named_outputs(outputs_collections, sc.name, output)
def conv_dw(self, data, num_filters=None, kernel=(3,3), stride=(1,1), pad='same', act_fn='relu', add_bn=False, name=None): """ """ net_out = separable_conv2d(inputs=data, num_outputs=None, kernel_size=kernel, depth_multiplier=1, stride=stride, padding='SAME', data_format=self.data_format, trainable=self.trainable, activation_fn=None, scope=name+'_dw') if add_bn == True: bn_name = None if name is None else name+'dw_Bn' net_out = self.batch_norm(net_out, act_fn='', name=bn_name) # Activation if act_fn in TF_ACT_FN: act = TF_ACT_FN[act_fn] net_out = act(net_out, name=name+act_fn) # PointWise Convolution if num_filters is not None: net_out = self.convolution(net_out, num_filters, (1,1), (1,1), 'same', act_fn, add_bn, name=name) return net_out
def resBlock_dw(self, x, num_outputs, stride=1, activation_fn=tf.nn.relu, scope=None): assert num_outputs % 4 == 0, "num_outputs must be divided by 4." with tf.variable_scope(scope, 'resBlock_dw'): shortcut = x if stride != 1 or x.get_shape()[self.channel_axis] != num_outputs: shortcut = layers.conv2d(shortcut, num_outputs, kernel_size=1, stride=stride, activation_fn=None, scope='shortcut') x = layers.conv2d(x, num_outputs / 4, kernel_size=1) x = layers.separable_conv2d(x, None, kernel_size=3, depth_multiplier=1, stride=stride) x = layers.conv2d(x, num_outputs, kernel_size=1, activation_fn=None) x += shortcut x = activation_fn(x) return x
def __separable_conv2d(self, input_tensor, num_outputs, kernel_size, stride=1, scope=None): return layers.separable_conv2d(input_tensor, num_outputs, kernel_size, depth_multiplier = 1, stride=stride, \ scope=scope,normalizer_fn=layers.batch_norm, activation_fn=tf.nn.relu6, \ normalizer_params={'is_training': self.is_training, "fused" : True, "decay" : self.normalize_decay})
def testOpAssumptions(self): # Verify that op assumptions are true. For example, verify that specific # inputs are at expected indices. conv_transpose = layers.conv2d_transpose(self.batch_norm_op.outputs[0], num_outputs=8, kernel_size=3, scope='conv_transpose') layers.separable_conv2d(conv_transpose, num_outputs=9, kernel_size=3, scope='dwise_conv') layers.fully_connected(tf.zeros([1, 7]), 10, scope='fc') g = tf.get_default_graph() # Verify that FusedBatchNormV3 has gamma as inputs[1]. self.assertEqual('conv1/BatchNorm/gamma/read:0', self.batch_norm_op.inputs[1].name) # Verify that Conv2D has weights at expected index. index = op_handler_util.WEIGHTS_INDEX_DICT[self.conv_op.type] self.assertEqual('conv1/weights/read:0', self.conv_op.inputs[index].name) # Verify that Conv2DBackpropInput has weights at expected index. conv_transpose_op = g.get_operation_by_name( 'conv_transpose/conv2d_transpose') index = op_handler_util.WEIGHTS_INDEX_DICT[conv_transpose_op.type] self.assertEqual('conv_transpose/weights/read:0', conv_transpose_op.inputs[index].name) # Verify that DepthwiseConv2dNative has weights at expected index. depthwise_conv_op = g.get_operation_by_name( 'dwise_conv/separable_conv2d/depthwise') index = op_handler_util.WEIGHTS_INDEX_DICT[depthwise_conv_op.type] self.assertEqual('dwise_conv/depthwise_weights/read:0', depthwise_conv_op.inputs[index].name) # Verify that MatMul has weights at expected index. matmul_op = g.get_operation_by_name('fc/MatMul') index = op_handler_util.WEIGHTS_INDEX_DICT[matmul_op.type] self.assertEqual('fc/weights/read:0', matmul_op.inputs[index].name)
def pre_bottleneck(self, inputs, state, input_index): with tf.variable_scope('bottleneck_%d' % input_index, reuse=tf.AUTO_REUSE): inputs = contrib_layers.separable_conv2d(tf.concat([inputs, state], 3), self._input_size, self._filter_size, depth_multiplier=1, activation_fn=tf.nn.relu6, normalizer_fn=None) return inputs
def pre_bottleneck(self, inputs, state, input_index): """Apply pre-bottleneck projection to inputs. Pre-bottleneck operation maps features of different channels into the same dimension. The purpose of this op is to share the features from both large and small models in the same LSTM cell. Args: inputs: 4D Tensor with shape [batch_size x width x height x input_size]. state: 4D Tensor with shape [batch_size x width x height x state_size]. input_index: integer index indicating which base features the inputs correspoding to. Returns: inputs: pre-bottlenecked inputs. Raises: ValueError: If pre_bottleneck is not set or inputs is not rank 4. """ # Sometimes state is a tuple, in which case it cannot be modified, e.g. # during training, tf.contrib.training.SequenceQueueingStateSaver # returns the state as a tuple. This should not be an issue since we # only need to modify state[1] during export, when state should be a # list. if len(inputs.shape) != 4: raise ValueError('Expect rank 4 feature tensor.') if not self._flatten_state and len(state.shape) != 4: raise ValueError('Expect rank 4 state tensor.') if self._flatten_state and len(state.shape) != 2: raise ValueError( 'Expect rank 2 state tensor when flatten_state is set.') with tf.name_scope(None): state = tf.identity(state, name='raw_inputs/init_lstm_h') if self._flatten_state: batch_size = inputs.shape[0] height = inputs.shape[1] width = inputs.shape[2] state = tf.reshape(state, [batch_size, height, width, -1]) with tf.variable_scope('conv_lstm_cell', reuse=tf.AUTO_REUSE): scope_name = 'bottleneck_%d' % input_index inputs = contrib_layers.separable_conv2d(tf.concat([inputs, state], 3), self.output_size[-1], self._filter_size, depth_multiplier=1, activation_fn=tf.nn.relu6, normalizer_fn=None, scope=scope_name) # For exporting inference graph, we only mark the first timestep. with tf.name_scope(None): inputs = tf.identity(inputs, name='raw_outputs/base_endpoint_%d' % (input_index + 1)) return inputs
def gconvbn(*args, **kwargs): scope = kwargs.pop('scope', None) with tf.variable_scope(scope): x = separable_conv2d(*args, **kwargs) c = args[-1] f = x.shape[-1].value // c g = f // c x = tf.reshape(x, tf.concat([tf.shape(x)[:-1], tf.constant([g, c, c])], axis=0)) x = tf.reduce_sum(x, axis=-2) x = reshape(x, tf.concat([tf.shape(x)[:-2], tf.constant([f])], axis=0), name='gconv') return batch_norm(x)
def depthwise_conv2d_fixed_padding(inputs, kernel_size, stride, data_format='channels_first', name=None): """Depthwise Strided 2-D convolution with explicit padding. The padding is consistent and is based only on `kernel_size`, not on the dimensions of `inputs` (as opposed to using `tf.layers.conv2d` alone). Args: inputs: Input tensor, float32 or bfloat16 of size [batch, channels, height, width]. kernel_size: Int designating size of kernel to be used in the convolution. stride: Int specifying the stride. If stride >1, the input is downsampled. data_format: String that specifies either "channels_first" for [batch, channels, height,width] or "channels_last" for [batch, height, width, channels]. name: String that specifies name for model layer. Returns: The output activation tensor of size [batch, filters, height_out, width_out] Raises: ValueError: If the data_format provided is not a valid string. """ if stride > 1: inputs = resnet_model.fixed_padding(inputs, kernel_size, data_format=data_format) padding = 'SAME' if stride == 1 else 'VALID' if data_format == 'channels_last': data_format_channels = 'NHWC' elif data_format == 'channels_first': data_format_channels = 'NCHW' else: raise ValueError('Not a valid channel string:', data_format) return contrib_layers.separable_conv2d(inputs=inputs, num_outputs=None, kernel_size=kernel_size, stride=stride, padding=padding, data_format=data_format_channels, activation_fn=None, weights_regularizer=None, biases_initializer=None, biases_regularizer=None, scope=name)
def Conv(data, num_filter=1, kernel=(1, 1), stride=(1, 1), pad=(0, 0), num_group=1, name=None): assert stride[0] == stride[1] stride = stride[0] assert (kernel == (3, 3) and pad == (1, 1)) or (kernel == (1, 1) and pad == (0, 0)) pad = 'SAME' assert num_group == 1 or num_group == data.get_shape().as_list()[-1] with tf.variable_scope(name): if num_group == 1: y = layers.conv2d(data, num_filter, kernel, stride, 'SAME') else: y = layers.separable_conv2d(data, None, kernel, 1, stride, 'SAME') y = layers.batch_norm(y) y = prelu(y) return y
def build_network(input_hold): net = input_hold _layers = {'input': net} # Block 1 : Separable CNN net = layers.separable_conv2d( inputs=net, num_outputs=32, kernel_size=4, stride=2, padding='VALID', depth_multiplier=4, ) _layers['sepCNN1'] = net # Block 2 : Attention (with residual connection) net, att_layers = non_local_nn_2d(net, 16, pool=False, name='non_local', return_layers=True) _layers['attention'] = att_layers['attention'] _layers['NLNN'] = net # Block 3 : Convolution net = layers.convolution(inputs=net, num_outputs=64, kernel_size=3, stride=2, padding='VALID') _layers['CNN1'] = net net = layers.convolution(inputs=net, num_outputs=64, kernel_size=2, stride=2, padding='VALID') _layers['CNN2'] = net # Block 4 : Feature Vector net = layers.flatten(net) _layers['flat'] = net net = layers.fully_connected( net, 128, activation_fn=None, ) _layers['dense1'] = net return net, _layers
def depthwise_separable_conv2d(self, net, num_outputs, kernel_size, stride=1, scope=None): with tf.variable_scope(scope, 'depthwise_separable_conv2d'): net = layers.separable_conv2d(net, None, kernel_size, depth_multiplier=1, stride=stride) net = layers.conv2d(net, num_outputs, kernel_size=1) return net
def gconvbn(*args, **kwargs): scope = kwargs.pop('scope', None) with tf.variable_scope(scope): x = separable_conv2d(*args, **kwargs) c = args[-1] f = x.shape[-1].value // c g = f // c kernel = np.zeros((1, 1, f * c, f), np.float32) for i in range(f): start = (i // c) * c * c + i % c end = start + c * c kernel[:, :, start:end:c, i] = 1. x = conv2d_primitive(x, tf.constant(kernel), strides=[1, 1, 1, 1], padding='VALID', name='gconv') return batch_norm(x)
def _depthwise_separable_conv(self, x, num_outputs, kernel_size=3, stride=1, scope=None): with tf.variable_scope(scope, "dw_blk"): dw_conv = tcl.separable_conv2d(x, num_outputs=None, kernel_size=kernel_size, stride=stride, depth_multiplier=1) conv_1x1 = tcl.conv2d(dw_conv, num_outputs=num_outputs, kernel_size=1, stride=1) return conv_1x1
def resBlock_dw_grouped(self, x, num_outputs, num_groups, stride=1, activation_fn=tf.nn.relu, scope=None): assert num_outputs % 4 == 0, "num_outputs must be divided by 4." assert num_outputs % num_groups == 0, "num_outputs must be divided by num_groups %d." % num_groups with tf.variable_scope(scope, 'resBlock_dw_grouped'): shortcut = x if stride != 1: shortcut = layers.avg_pool2d(shortcut, kernel_size=3, stride=stride, padding='SAME', data_format=self.data_format) x = self.grouped_conv2d(x, num_outputs / 4, kernel_size=1, num_groups=self.num_groups) x = self.channel_shuffle(x, self.num_groups) x = layers.separable_conv2d(x, None, kernel_size=3, depth_multiplier=1, stride=stride) x = self.grouped_conv2d(x, num_outputs, kernel_size=1, num_groups=self.num_groups, activation_fn=None) if stride != 1: x = tf.concat([x, shortcut], axis=self.channel_axis) else: x += shortcut x = activation_fn(x) return x
def testDepthwiseChannelMapping(self): """Verify depth multiplier maps input to output as expected.""" tf.reset_default_graph() # Construct input tensor with shape [1, 4, 4, 5]. There are 5 channels # where each channel has values corresponding to the channel index. channel0 = tf.ones([1, 4, 4, 1]) * 0 channel1 = tf.ones([1, 4, 4, 1]) * 1 channel2 = tf.ones([1, 4, 4, 1]) * 2 channel3 = tf.ones([1, 4, 4, 1]) * 3 channel4 = tf.ones([1, 4, 4, 1]) * 4 inputs = tf.concat([channel0, channel1, channel2, channel3, channel4], axis=3) # Sanity check that input tensor is the right shape. self.assertAllEqual([1, 4, 4, 5], inputs.shape.as_list()) conv = layers.separable_conv2d( inputs, num_outputs=None, kernel_size=3, depth_multiplier=2, weights_initializer=identity_initializer, scope='depthwise_conv') with self.cached_session(): with tf.variable_scope('', reuse=tf.AUTO_REUSE): weights = tf.get_variable('depthwise_conv/depthwise_weights') biases = tf.get_variable('depthwise_conv/biases', [10], initializer=tf.zeros_initializer) init = tf.variables_initializer([weights, biases]) init.run() # The depth_multiplier replicates channels with [a, a, b, b, c, c, ...] # pattern. Expected output has shape [1, 4, 4, 10]. expected_output = tf.concat([ channel0, channel0, channel1, channel1, channel2, channel2, channel3, channel3, channel4, channel4 ], axis=3) # Sanity check that output tensor is the right shape. self.assertAllEqual([1, 4, 4, 10], expected_output.shape.as_list()) self.assertAllEqual(expected_output.eval(), conv.eval())
class CostCalculatorTest(parameterized.TestCase, tf.test.TestCase): def _batch_norm_scope(self): params = { 'trainable': True, 'normalizer_fn': layers.batch_norm, 'normalizer_params': { 'scale': True } } with arg_scope([layers.conv2d], **params) as sc: return sc def testImageIsNotZerothOutputOfOp(self): # Throughout the framework, we assume that the 0th output of each op is the # only one of interest. One exception that often happens is when the input # image comes from a queue or from a staging op. Then the image is one of # the outputs of the dequeue (or staging) op, not necessarily the 0th one. # Here we test that the BilinearNetworkRegularizer deals correctly with this # case. # Create an input op where the image is output number 1, not 0. # TODO(g1) Move this mechanism to add_concat_model_stub, possibly using # tf.split to produce an op where the image is not the 0th output image # (instead of FIFOQueue). image = add_concat_model_stub.image_stub() non_image_tensor = tf.zeros(shape=(41, )) queue = tf.FIFOQueue(capacity=1, dtypes=(tf.float32, ) * 2, shapes=(non_image_tensor.shape, image.shape)) # Pass the image (output[1]) to the network. with arg_scope(self._batch_norm_scope()): output_op = add_concat_model_stub.build_model(queue.dequeue()[1]) # Create OpHandler dict for test. op_handler_dict = collections.defaultdict( grouping_op_handler.GroupingOpHandler) op_handler_dict.update({ 'FusedBatchNormV3': batch_norm_source_op_handler.BatchNormSourceOpHandler(0.1), 'Conv2D': output_non_passthrough_op_handler.OutputNonPassthroughOpHandler(), 'ConcatV2': concat_op_handler.ConcatOpHandler(), }) # Create OpRegularizerManager and NetworkRegularizer for test. manager = orm.OpRegularizerManager([output_op], op_handler_dict) calculator = cc.CostCalculator(manager, resource_function.flop_function) # Calculate expected FLOP cost. expected_alive_conv1 = sum( add_concat_model_stub.expected_alive()['conv1']) conv1_op = tf.get_default_graph().get_operation_by_name('conv1/Conv2D') conv1_coeff = resource_function.flop_coeff(conv1_op) num_channels = 3 expected_cost = conv1_coeff * num_channels * expected_alive_conv1 with self.session(): tf.global_variables_initializer().run() # Set gamma values to replicate aliveness in add_concat_model_stub. name_to_var = {v.op.name: v for v in tf.global_variables()} gamma1 = name_to_var['conv1/BatchNorm/gamma'] gamma1.assign([0, 1, 1, 0, 1, 0, 1]).eval() gamma4 = name_to_var['conv4/BatchNorm/gamma'] gamma4.assign([0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0]).eval() queue.enqueue((non_image_tensor, image)).run() self.assertEqual(expected_cost, calculator.get_cost([conv1_op]).eval()) # for 0/1 assigments cost and reg_term are equal: self.assertEqual( expected_cost, calculator.get_regularization_term([conv1_op]).eval()) @parameterized.named_parameters( ('_conv2d', 4, lambda x: layers.conv2d(x, 16, 3), 'Conv2D'), ('_convt', 4, lambda x: layers.conv2d_transpose(x, 16, 3), 'conv2d_transpose'), ('_conv2s', 4, lambda x: layers.separable_conv2d(x, None, 3), 'depthwise'), ('_conv3d', 5, lambda x: layers.conv3d(x, 16, 3), 'Conv3D')) def test_get_input_activation2(self, rank, fn, op_name): g = tf.get_default_graph() inputs = tf.zeros([6] * rank) with arg_scope([ layers.conv2d, layers.conv2d_transpose, layers.separable_conv2d, layers.conv3d ], scope='test_layer'): _ = fn(inputs) for op in g.get_operations(): print(op.name) self.assertEqual( inputs, cc.get_input_activation( g.get_operation_by_name('test_layer/' + op_name)))
def apply_convolution(self, x, layer, layer_idx): """Adds convolution and batch norm layers if hparam.batch_norm is True.""" if 'filters' not in layer: return x filter_shape = layer['filters'] # Instantiate or retrieve filter weights. fanin = tf.to_float(tf.reduce_prod(filter_shape[:-1])) stddev = tf.sqrt(tf.div(2.0, fanin)) initializer = tf.random_normal_initializer(0.0, stddev) regular_convs = ( not self.hparams.use_sep_conv or layer_idx < self.hparams.num_initial_regular_conv_layers) if regular_convs: dilation_rates = layer.get('dilation_rate', 1) if isinstance(dilation_rates, int): dilation_rates = [dilation_rates] * 2 weights = tf.get_variable( 'weights', filter_shape, initializer=initializer if self.is_training else None) stride = layer.get('conv_stride', 1) conv = tf.nn.conv2d(x, weights, strides=[1, stride, stride, 1], padding=layer.get('conv_pad', 'SAME'), dilations=[1] + dilation_rates + [1]) else: num_outputs = filter_shape[-1] num_splits = layer.get('num_pointwise_splits', 1) tf.logging.info('num_splits %d', num_splits) if num_splits > 1: num_outputs = None conv = contrib_layers.separable_conv2d( x, num_outputs, filter_shape[:2], depth_multiplier=self.hparams.sep_conv_depth_multiplier, stride=layer.get('conv_stride', 1), padding=layer.get('conv_pad', 'SAME'), rate=layer.get('dilation_rate', 1), activation_fn=None, weights_initializer=initializer if self.is_training else None) if num_splits > 1: splits = tf.split(conv, num_splits, -1) print(len(splits), splits[0].shape) # TODO(annahuang): support non equal splits. pointwise_splits = [ tf.layers.dense(splits[i], filter_shape[3] / num_splits, name='split_%d_%d' % (layer_idx, i)) for i in range(num_splits) ] conv = tf.concat((pointwise_splits), axis=-1) # Compute batch normalization or add biases. if self.hparams.batch_norm: y = self.apply_batchnorm(conv) else: biases = tf.get_variable('bias', [conv.get_shape()[-1]], initializer=tf.constant_initializer(0.0)) y = tf.nn.bias_add(conv, biases) return y
def setUp(self): super(DepthwiseConvolutionOpHandlerTest, self).setUp() tf.reset_default_graph() # This tests a Conv2D -> SeparableConv2D -> Conv2D chain of ops. with framework.arg_scope(self._batch_norm_scope()): inputs = tf.zeros([2, 4, 4, 3]) c1 = layers.conv2d(inputs, num_outputs=5, kernel_size=3, scope='conv1') c2 = layers.separable_conv2d(c1, num_outputs=8, kernel_size=3, depth_multiplier=2, scope='conv2') layers.conv2d(c2, num_outputs=6, kernel_size=3, scope='conv3') g = tf.get_default_graph() # Declare OpSlice and OpGroup for ops of interest. self.dwise_conv2_op = g.get_operation_by_name( 'conv2/separable_conv2d/depthwise') self.dwise_conv2_op_slice = orm.OpSlice(self.dwise_conv2_op, orm.Slice(0, 10)) self.dwise_conv2_op_slice_0_1 = orm.OpSlice(self.dwise_conv2_op, orm.Slice(0, 1)) self.dwise_conv2_op_slice_1_2 = orm.OpSlice(self.dwise_conv2_op, orm.Slice(1, 1)) self.dwise_conv2_op_slice_2_3 = orm.OpSlice(self.dwise_conv2_op, orm.Slice(2, 1)) self.dwise_conv2_op_slice_3_4 = orm.OpSlice(self.dwise_conv2_op, orm.Slice(3, 1)) self.dwise_conv2_op_slice_4_5 = orm.OpSlice(self.dwise_conv2_op, orm.Slice(4, 1)) self.dwise_conv2_op_slice_5_6 = orm.OpSlice(self.dwise_conv2_op, orm.Slice(5, 1)) self.dwise_conv2_op_slice_6_7 = orm.OpSlice(self.dwise_conv2_op, orm.Slice(6, 1)) self.dwise_conv2_op_slice_7_8 = orm.OpSlice(self.dwise_conv2_op, orm.Slice(7, 1)) self.dwise_conv2_op_slice_8_9 = orm.OpSlice(self.dwise_conv2_op, orm.Slice(8, 1)) self.dwise_conv2_op_slice_9_10 = orm.OpSlice(self.dwise_conv2_op, orm.Slice(9, 1)) self.conv2_op = g.get_operation_by_name('conv2/separable_conv2d') self.conv2_op_slice = orm.OpSlice(self.conv2_op, orm.Slice(0, 8)) self.relu1_op = g.get_operation_by_name('conv1/Relu') self.relu1_op_slice = orm.OpSlice(self.relu1_op, orm.Slice(0, 5)) self.relu1_op_slice_0_1 = orm.OpSlice(self.relu1_op, orm.Slice(0, 1)) self.relu1_op_slice_1_2 = orm.OpSlice(self.relu1_op, orm.Slice(1, 1)) self.relu1_op_slice_2_3 = orm.OpSlice(self.relu1_op, orm.Slice(2, 1)) self.relu1_op_slice_3_4 = orm.OpSlice(self.relu1_op, orm.Slice(3, 1)) self.relu1_op_slice_4_5 = orm.OpSlice(self.relu1_op, orm.Slice(4, 1)) self.relu1_op_group = orm.OpGroup(self.relu1_op_slice) self.conv3_op = g.get_operation_by_name('conv3/Conv2D') self.conv3_op_slice = orm.OpSlice(self.conv3_op, orm.Slice(0, 6)) # Create mock OpRegularizerManager with custom mapping of OpSlice and # OpGroup. self.mock_op_reg_manager = mock.create_autospec( orm.OpRegularizerManager) self.op_slice_dict = { self.dwise_conv2_op: [self.dwise_conv2_op_slice], self.conv2_op: [self.conv2_op_slice], self.relu1_op: [self.relu1_op_slice], self.conv3_op: [self.conv3_op_slice], } def get_op_slices(op): return self.op_slice_dict.get(op) def get_op_group(op_slice): return self.op_group_dict.get(op_slice) # Update op_slice_dict when an op is sliced. def slice_op(op, _): if op == self.dwise_conv2_op: self.op_slice_dict[self.dwise_conv2_op] = [ self.dwise_conv2_op_slice_0_1, self.dwise_conv2_op_slice_1_2, self.dwise_conv2_op_slice_2_3, self.dwise_conv2_op_slice_3_4, self.dwise_conv2_op_slice_4_5, self.dwise_conv2_op_slice_5_6, self.dwise_conv2_op_slice_6_7, self.dwise_conv2_op_slice_7_8, self.dwise_conv2_op_slice_8_9, self.dwise_conv2_op_slice_9_10 ] if op == self.relu1_op: self.op_slice_dict[self.relu1_op] = [ self.relu1_op_slice_0_1, self.relu1_op_slice_1_2, self.relu1_op_slice_2_3, self.relu1_op_slice_3_4, self.relu1_op_slice_4_5 ] self.mock_op_reg_manager.get_op_slices.side_effect = get_op_slices self.mock_op_reg_manager.get_op_group.side_effect = get_op_group self.mock_op_reg_manager.is_source_op.return_value = False self.mock_op_reg_manager.slice_op.side_effect = slice_op self.mock_op_reg_manager.ops = [ self.relu1_op, self.dwise_conv2_op, self.conv2_op, self.conv3_op ]
def inception_v2_base(inputs, final_endpoint='Mixed_5c', min_depth=16, depth_multiplier=1.0, scope=None): """Inception v2 (6a2). Constructs an Inception v2 network from inputs to the given final endpoint. This method can construct the network up to the layer inception(5b) as described in http://arxiv.org/abs/1502.03167. Args: inputs: a tensor of shape [batch_size, height, width, channels]. final_endpoint: specifies the endpoint to construct the network up to. It can be one of ['Conv2d_1a_7x7', 'MaxPool_2a_3x3', 'Conv2d_2b_1x1', 'Conv2d_2c_3x3', 'MaxPool_3a_3x3', 'Mixed_3b', 'Mixed_3c', 'Mixed_4a', 'Mixed_4b', 'Mixed_4c', 'Mixed_4d', 'Mixed_4e', 'Mixed_5a', 'Mixed_5b', 'Mixed_5c']. min_depth: Minimum depth value (number of channels) for all convolution ops. Enforced when depth_multiplier < 1, and not an active constraint when depth_multiplier >= 1. depth_multiplier: Float multiplier for the depth (number of channels) for all convolution ops. The value must be greater than zero. Typical usage will be to set this value in (0, 1) to reduce the number of parameters or computation cost of the model. scope: Optional variable_scope. Returns: tensor_out: output tensor corresponding to the final_endpoint. end_points: a set of activations for external use, for example summaries or losses. Raises: ValueError: if final_endpoint is not set to one of the predefined values, or depth_multiplier <= 0 """ # end_points will collect relevant activations for external use, for example # summaries or losses. end_points = {} # Used to find thinned depths for each layer. if depth_multiplier <= 0: raise ValueError('depth_multiplier is not greater than zero.') depth = lambda d: max(int(d * depth_multiplier), min_depth) with variable_scope.variable_scope(scope, 'InceptionV2', [inputs]): with arg_scope( [ layers.conv2d, layers_lib.max_pool2d, layers_lib.avg_pool2d, layers.separable_conv2d ], stride=1, padding='SAME'): # Note that sizes in the comments below assume an input spatial size of # 224x224, however, the inputs can be of any size greater 32x32. # 224 x 224 x 3 end_point = 'Conv2d_1a_7x7' # depthwise_multiplier here is different from depth_multiplier. # depthwise_multiplier determines the output channels of the initial # depthwise conv (see docs for tf.nn.separable_conv2d), while # depth_multiplier controls the # channels of the subsequent 1x1 # convolution. Must have # in_channels * depthwise_multipler <= out_channels # so that the separable convolution is not overparameterized. depthwise_multiplier = min(int(depth(64) / 3), 8) net = layers.separable_conv2d( inputs, depth(64), [7, 7], depth_multiplier=depthwise_multiplier, stride=2, weights_initializer=trunc_normal(1.0), scope=end_point) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 112 x 112 x 64 end_point = 'MaxPool_2a_3x3' net = layers_lib.max_pool2d(net, [3, 3], scope=end_point, stride=2) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 56 x 56 x 64 end_point = 'Conv2d_2b_1x1' net = layers.conv2d( net, depth(64), [1, 1], scope=end_point, weights_initializer=trunc_normal(0.1)) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 56 x 56 x 64 end_point = 'Conv2d_2c_3x3' net = layers.conv2d(net, depth(192), [3, 3], scope=end_point) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 56 x 56 x 192 end_point = 'MaxPool_3a_3x3' net = layers_lib.max_pool2d(net, [3, 3], scope=end_point, stride=2) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 28 x 28 x 192 # Inception module. end_point = 'Mixed_3b' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(64), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(64), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(64), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(64), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(96), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(96), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(32), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat(3, [branch_0, branch_1, branch_2, branch_3] ) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 28 x 28 x 256 end_point = 'Mixed_3c' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(64), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(64), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(96), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(64), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(96), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(96), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(64), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat(3, [branch_0, branch_1, branch_2, branch_3]) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 28 x 28 x 320 end_point = 'Mixed_4a' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(128), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_0 = layers.conv2d( branch_0, depth(160), [3, 3], stride=2, scope='Conv2d_1a_3x3') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(64), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(96), [3, 3], scope='Conv2d_0b_3x3') branch_1 = layers.conv2d( branch_1, depth(96), [3, 3], stride=2, scope='Conv2d_1a_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers_lib.max_pool2d( net, [3, 3], stride=2, scope='MaxPool_1a_3x3') net = array_ops.concat(3, [branch_0, branch_1, branch_2]) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 14 x 14 x 576 end_point = 'Mixed_4b' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(224), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(64), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(96), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(96), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(128), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(128), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(128), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat(3, [branch_0, branch_1, branch_2, branch_3]) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 14 x 14 x 576 end_point = 'Mixed_4c' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(192), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(96), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(128), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(96), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(128), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(128), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(128), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat(3, [branch_0, branch_1, branch_2, branch_3]) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 14 x 14 x 576 end_point = 'Mixed_4d' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(160), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(128), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(160), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(128), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(160), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(160), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(96), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat(3, [branch_0, branch_1, branch_2, branch_3]) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 14 x 14 x 576 end_point = 'Mixed_4e' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(96), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(128), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(192), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(160), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(192), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(192), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(96), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat(3, [branch_0, branch_1, branch_2, branch_3]) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 14 x 14 x 576 end_point = 'Mixed_5a' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(128), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_0 = layers.conv2d( branch_0, depth(192), [3, 3], stride=2, scope='Conv2d_1a_3x3') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(192), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(256), [3, 3], scope='Conv2d_0b_3x3') branch_1 = layers.conv2d( branch_1, depth(256), [3, 3], stride=2, scope='Conv2d_1a_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers_lib.max_pool2d( net, [3, 3], stride=2, scope='MaxPool_1a_3x3') net = array_ops.concat(3, [branch_0, branch_1, branch_2]) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 7 x 7 x 1024 end_point = 'Mixed_5b' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(352), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(192), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(320), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(160), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(224), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(224), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(128), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat(3, [branch_0, branch_1, branch_2, branch_3]) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 7 x 7 x 1024 end_point = 'Mixed_5c' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(352), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(192), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(320), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(192), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(224), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(224), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(128), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat(3, [branch_0, branch_1, branch_2, branch_3]) end_points[end_point] = net if end_point == final_endpoint: return net, end_points raise ValueError('Unknown final endpoint %s' % final_endpoint)
def __call__(self, inputs, state, scope=None): """Long short-term memory cell (LSTM) with bottlenecking. Args: inputs: Input tensor at the current timestep. state: Tuple of tensors, the state and output at the previous timestep. scope: Optional scope. Returns: A tuple where the first element is the LSTM output and the second is a LSTMStateTuple of the state at the current timestep. """ scope = scope or 'conv_lstm_cell' with tf.variable_scope(scope, reuse=tf.AUTO_REUSE): c, h = state # unflatten state if necessary if self._flatten_state: c = tf.reshape(c, [-1] + self.output_size) h = tf.reshape(h, [-1] + self.output_size) # summary of input passed into cell if self._viz_gates: slim.summaries.add_histogram_summary(inputs, 'cell_input') if self._pre_bottleneck: bottleneck = inputs else: bottleneck = contrib_layers.separable_conv2d( tf.concat([inputs, h], 3), self._num_units, self._filter_size, depth_multiplier=1, activation_fn=self._activation, normalizer_fn=None, scope='bottleneck') if self._viz_gates: slim.summaries.add_histogram_summary( bottleneck, 'bottleneck') concat = contrib_layers.separable_conv2d(bottleneck, 4 * self._num_units, self._filter_size, depth_multiplier=1, activation_fn=None, normalizer_fn=None, scope='gates') i, j, f, o = tf.split(concat, 4, 3) new_c = (c * tf.sigmoid(f + self._forget_bias) + tf.sigmoid(i) * self._activation(j)) if self._clip_state: new_c = tf.clip_by_value(new_c, -6, 6) new_h = self._activation(new_c) * tf.sigmoid(o) # summary of cell output and new state if self._viz_gates: slim.summaries.add_histogram_summary(new_h, 'cell_output') slim.summaries.add_histogram_summary(new_c, 'cell_state') output = new_h if self._output_bottleneck: output = tf.concat([new_h, bottleneck], axis=3) # reflatten state to store it if self._flatten_state: new_c = tf.reshape(new_c, [-1, self._param_count]) new_h = tf.reshape(new_h, [-1, self._param_count]) return output, contrib_rnn.LSTMStateTuple(new_c, new_h)
def separable_conv2d_same(inputs, num_outputs, kernel_size, stride, rate=1, scope=None): """Strided 2-D convolution with 'SAME' padding. When stride > 1, then we do explicit zero-padding, followed by conv2d with 'VALID' padding. Note that net = conv2d_same(inputs, num_outputs, 3, stride=stride) is equivalent to net = tf.contrib.layers.conv2d(inputs, num_outputs, 3, stride=1, padding='SAME') net = subsample(net, factor=stride) whereas net = tf.contrib.layers.conv2d(inputs, num_outputs, 3, stride=stride, padding='SAME') is different when the input's height or width is even, which is why we add the current function. For more details, see ResnetUtilsTest.testConv2DSameEven(). Args: inputs: A 4-D tensor of size [batch, height_in, width_in, channels]. num_outputs: An integer, the number of output filters. kernel_size: An int with the kernel_size of the filters. stride: An integer, the output stride. rate: An integer, rate for atrous convolution. scope: Scope. biases_initializer: Biases initializer Returns: output: A 4-D tensor of size [batch, height_out, width_out, channels] with the convolution output. """ if stride == 1: return layers_lib.separable_conv2d(inputs, num_outputs, kernel_size, stride=1, rate=rate, padding='SAME', scope=scope, biases_initializer=None) else: kernel_size_effective = kernel_size + (kernel_size - 1) * (rate - 1) pad_total = kernel_size_effective - 1 pad_beg = pad_total // 2 pad_end = pad_total - pad_beg inputs = array_ops.pad( inputs, [[0, 0], [pad_beg, pad_end], [pad_beg, pad_end], [0, 0]]) return layers_lib.separable_conv2d(inputs, num_outputs, kernel_size, stride=stride, rate=rate, padding='VALID', scope=scope, biases_initializer=None)
def quantizable_separable_conv2d(inputs, num_outputs, kernel_size, is_quantized=True, depth_multiplier=1, stride=1, activation_fn=tf.nn.relu6, normalizer_fn=None, scope=None): """Quantization friendly backward compatible separable conv2d. This op has the same API is separable_conv2d. The main difference is that an additional BiasAdd is manually inserted after the depthwise conv, such that the depthwise bias will not have name conflict with pointwise bias. The motivation of this op is that quantization script need BiasAdd in order to recognize the op, in which a native call to separable_conv2d do not create for the depthwise conv. Args: inputs: A tensor of size [batch_size, height, width, channels]. num_outputs: The number of pointwise convolution output filters. If is None, then we skip the pointwise convolution stage. kernel_size: A list of length 2: [kernel_height, kernel_width] of the filters. Can be an int if both values are the same. is_quantized: flag to enable/disable quantization. depth_multiplier: The number of depthwise convolution output channels for each input channel. The total number of depthwise convolution output channels will be equal to num_filters_in * depth_multiplier. stride: A list of length 2: [stride_height, stride_width], specifying the depthwise convolution stride. Can be an int if both strides are the same. activation_fn: Activation function. The default value is a ReLU function. Explicitly set it to None to skip it and maintain a linear activation. normalizer_fn: Normalization function to use instead of biases. scope: Optional scope for variable_scope. Returns: Tensor resulting from concatenation of input tensors """ if is_quantized: outputs = contrib_layers.separable_conv2d( inputs, None, kernel_size, depth_multiplier=depth_multiplier, stride=1, activation_fn=None, normalizer_fn=None, biases_initializer=None, scope=scope) outputs = contrib_layers.bias_add(outputs, trainable=True, scope='%s_bias' % scope) outputs = contrib_layers.conv2d(outputs, num_outputs, [1, 1], activation_fn=activation_fn, stride=stride, normalizer_fn=normalizer_fn, scope=scope) else: outputs = contrib_layers.separable_conv2d( inputs, num_outputs, kernel_size, depth_multiplier=depth_multiplier, stride=stride, activation_fn=activation_fn, normalizer_fn=normalizer_fn, scope=scope) return outputs
def sconvbnrelu6(*args, **kwargs): scope = kwargs.pop('scope', None) with tf.variable_scope(scope): return relu6(batch_norm(separable_conv2d(*args, **kwargs)))
def testAssignGrouping_NoDepthMultiplier(self): # Repeat setUp, but with depth_multiplier=1. Unfortunately, this involves # rebuilding the graph from scratch. tf.reset_default_graph() # This tests a Conv2D -> SeparableConv2D -> Conv2D chain of ops. with framework.arg_scope(self._batch_norm_scope()): inputs = tf.zeros([2, 4, 4, 3]) c1 = layers.conv2d(inputs, num_outputs=5, kernel_size=3, scope='conv1') c2 = layers.separable_conv2d(c1, num_outputs=8, kernel_size=3, depth_multiplier=1, scope='conv2') layers.conv2d(c2, num_outputs=6, kernel_size=3, scope='conv3') g = tf.get_default_graph() # Declare OpSlice and OpGroup for ops of interest. self.dwise_conv2_op = g.get_operation_by_name( 'conv2/separable_conv2d/depthwise') self.dwise_conv2_op_slice = orm.OpSlice(self.dwise_conv2_op, orm.Slice(0, 5)) self.conv2_op = g.get_operation_by_name('conv2/separable_conv2d') self.conv2_op_slice = orm.OpSlice(self.conv2_op, orm.Slice(0, 8)) self.relu1_op = g.get_operation_by_name('conv1/Relu') self.relu1_op_slice = orm.OpSlice(self.relu1_op, orm.Slice(0, 5)) self.relu1_op_group = orm.OpGroup(self.relu1_op_slice) self.conv3_op = g.get_operation_by_name('conv3/Conv2D') self.conv3_op_slice = orm.OpSlice(self.conv3_op, orm.Slice(0, 6)) # Create mock OpRegularizerManager with custom mapping of OpSlice and # OpGroup. self.mock_op_reg_manager = mock.create_autospec( orm.OpRegularizerManager) self.op_slice_dict = { self.dwise_conv2_op: [self.dwise_conv2_op_slice], self.conv2_op: [self.conv2_op_slice], self.relu1_op: [self.relu1_op_slice], self.conv3_op: [self.conv3_op_slice], } def get_op_slices(op): return self.op_slice_dict.get(op) def get_op_group(op_slice): return self.op_group_dict.get(op_slice) self.mock_op_reg_manager.get_op_slices.side_effect = get_op_slices self.mock_op_reg_manager.get_op_group.side_effect = get_op_group self.mock_op_reg_manager.is_source_op.return_value = False self.mock_op_reg_manager.ops = [ self.relu1_op, self.dwise_conv2_op, self.conv2_op, self.conv3_op ] # All neighbor ops have groups. self.op_group_dict = { self.relu1_op_slice: self.relu1_op_group, } # Call handler to assign grouping. handler = depthwise_convolution_op_handler.DepthwiseConvolutionOpHandler( ) handler.assign_grouping(self.dwise_conv2_op, self.mock_op_reg_manager) # Verify manager looks up OpSlice for ops of interest. self.mock_op_reg_manager.get_op_slices.assert_has_calls( # Checking for ops to process. [ mock.call(self.relu1_op), mock.call(self.conv2_op), # Initial slice data. mock.call(self.dwise_conv2_op), mock.call(self.relu1_op), # Reslicing. mock.call(self.relu1_op), mock.call(self.dwise_conv2_op), # Refreshing slice data. mock.call(self.relu1_op), # Group depthwise convolution. mock.call(self.dwise_conv2_op) ]) # Verify manager groups batch norm with inputs and outputs. self.mock_op_reg_manager.group_op_slices.assert_called_once_with( [self.dwise_conv2_op_slice, self.relu1_op_slice]) # Verify manager does not process any additional ops. self.mock_op_reg_manager.process_ops.assert_called_once_with( [self.conv2_op]) self.mock_op_reg_manager.process_ops_last.assert_not_called()
def build(self): endpoints = self.endpoints y = self.inputs['images'] with arg_scope([layers.conv2d, layers.separable_conv2d], padding='SAME', activation_fn=tf.nn.relu6, weights_initializer=layers.xavier_initializer(), weights_regularizer=layers.l2_regularizer(self.weight_decay), normalizer_fn=layers.batch_norm, normalizer_params={'is_training': self.is_training}): y = layers.conv2d(y, 32, (3, 3), 2, scope='Conv2d_0') endpoints['Conv2d_0'] = y # set num_outputs to None to skipe point-wise convolution y = layers.separable_conv2d(y, None, (3, 3), 1, stride=1, scope='Depthwise_Conv2d_1') y = layers.conv2d(y, 64, (1, 1), scope='Pointwise_Conv2d_1') endpoints['Pointwise_Conv2d_1'] = y y = layers.separable_conv2d(y, None, (3, 3), 1, stride=2, scope='Depthwise_Conv2d_2') y = layers.conv2d(y, 128, (1, 1), scope='Pointwise_Conv2d_2') endpoints['Pointwise_Conv2d_2'] = y y = layers.separable_conv2d(y, None, (3, 3), 1, stride=1, scope='Depthwise_Conv2d_3') y = layers.conv2d(y, 128, (1, 1), scope='Pointwise_Conv2d_3') endpoints['Pointwise_Conv2d_3'] = y y = layers.separable_conv2d(y, None, (3, 3), 1, stride=2, scope='Depthwise_Conv2d_4') y = layers.conv2d(y, 256, (1, 1), scope='Pointwise_Conv2d_4') endpoints['Pointwise_Conv2d_4'] = y y = layers.separable_conv2d(y, None, (3, 3), 1, stride=1, scope='Depthwise_Conv2d_5') y = layers.conv2d(y, 256, (1, 1), scope='Pointwise_Conv2d_5') endpoints['Pointwise_Conv2d_5'] = y y = layers.separable_conv2d(y, None, (3, 3), 1, stride=2, scope='Depthwise_Conv2d_6') # y = layers.separable_conv2d(y, None, (3, 3), 1, stride=1, scope='Depthwise_Conv2d_6') y = layers.conv2d(y, 512, (1, 1), scope='Pointwise_Conv2d_6') endpoints['Pointwise_Conv2d_6'] = y # repeat 5 times y = layers.separable_conv2d(y, None, (3, 3), 1, stride=1, scope='Depthwise_Conv2d_7') y = layers.conv2d(y, 512, (1, 1), scope='Pointwise_Conv2d_7') # y = dropblock(y, 0.9, 7, self.is_training) endpoints['Pointwise_Conv2d_7'] = y y = layers.separable_conv2d(y, None, (3, 3), 1, stride=1, scope='Depthwise_Conv2d_8') y = layers.conv2d(y, 512, (1, 1), scope='Pointwise_Conv2d_8') # y = dropblock(y, 0.9, 7, self.is_training) endpoints['Pointwise_Conv2d_8'] = y y = layers.separable_conv2d(y, None, (3, 3), 1, stride=1, scope='Depthwise_Conv2d_9') y = layers.conv2d(y, 512, (1, 1), scope='Pointwise_Conv2d_9') # y = dropblock(y, 0.9, 7, self.is_training) endpoints['Pointwise_Conv2d_9'] = y y = layers.separable_conv2d(y, None, (3, 3), 1, stride=2, scope='Depthwise_Conv2d_10') y = layers.conv2d(y, 512, (1, 1), scope='Pointwise_Conv2d_10') # y = dropblock(y, 0.9, 7, self.is_training) endpoints['Pointwise_Conv2d_10'] = y y = layers.separable_conv2d(y, None, (3, 3), 1, stride=1, scope='Depthwise_Conv2d_11') y = layers.conv2d(y, 512, (1, 1), scope='Pointwise_Conv2d_11') # y = dropblock(y, 0.9, 7, self.is_training) endpoints['Pointwise_Conv2d_11'] = y y = layers.separable_conv2d(y, None, (3, 3), 1, stride=2, scope='Depthwise_Conv2d_12') y = layers.conv2d(y, 1024, (1, 1), scope='Pointwise_Conv2d_12') # y = dropblock(y, 0.9, 7, self.is_training) endpoints['Pointwise_Conv2d_12'] = y # 此层stride存疑,原文为2。 y = layers.separable_conv2d(y, None, (3, 3), 1, stride=1, scope='Depthwise_Conv2d_13') y = layers.conv2d(y, 1024, (1, 1), scope='Pointwise_Conv2d_13') # y = dropblock(y, 0.9, 7, self.is_training) endpoints['Pointwise_Conv2d_13'] = y y = tf.reduce_mean(y, keepdims=True, axis=[1, 2]) endpoints['global_pooling'] = y y = layers.flatten(y) y = layers.fully_connected(y, 1000, scope='fc1') endpoints['fc1'] = y self.outputs['logits'] = y return y
def inception_v2_base(inputs, final_endpoint='Mixed_5c', min_depth=16, depth_multiplier=1.0, scope=None): """Inception v2 (6a2). Constructs an Inception v2 network from inputs to the given final endpoint. This method can construct the network up to the layer inception(5b) as described in http://arxiv.org/abs/1502.03167. Args: inputs: a tensor of shape [batch_size, height, width, channels]. final_endpoint: specifies the endpoint to construct the network up to. It can be one of ['Conv2d_1a_7x7', 'MaxPool_2a_3x3', 'Conv2d_2b_1x1', 'Conv2d_2c_3x3', 'MaxPool_3a_3x3', 'Mixed_3b', 'Mixed_3c', 'Mixed_4a', 'Mixed_4b', 'Mixed_4c', 'Mixed_4d', 'Mixed_4e', 'Mixed_5a', 'Mixed_5b', 'Mixed_5c']. min_depth: Minimum depth value (number of channels) for all convolution ops. Enforced when depth_multiplier < 1, and not an active constraint when depth_multiplier >= 1. depth_multiplier: Float multiplier for the depth (number of channels) for all convolution ops. The value must be greater than zero. Typical usage will be to set this value in (0, 1) to reduce the number of parameters or computation cost of the model. scope: Optional variable_scope. Returns: tensor_out: output tensor corresponding to the final_endpoint. end_points: a set of activations for external use, for example summaries or losses. Raises: ValueError: if final_endpoint is not set to one of the predefined values, or depth_multiplier <= 0 """ # end_points will collect relevant activations for external use, for example # summaries or losses. end_points = {} # Used to find thinned depths for each layer. if depth_multiplier <= 0: raise ValueError('depth_multiplier is not greater than zero.') depth = lambda d: max(int(d * depth_multiplier), min_depth) with variable_scope.variable_scope(scope, 'InceptionV2', [inputs]): with arg_scope( [ layers.conv2d, layers_lib.max_pool2d, layers_lib.avg_pool2d, layers.separable_conv2d ], stride=1, padding='SAME'): # Note that sizes in the comments below assume an input spatial size of # 224x224, however, the inputs can be of any size greater 32x32. # 224 x 224 x 3 end_point = 'Conv2d_1a_7x7' # depthwise_multiplier here is different from depth_multiplier. # depthwise_multiplier determines the output channels of the initial # depthwise conv (see docs for tf.nn.separable_conv2d), while # depth_multiplier controls the # channels of the subsequent 1x1 # convolution. Must have # in_channels * depthwise_multipler <= out_channels # so that the separable convolution is not overparameterized. depthwise_multiplier = min(int(depth(64) / 3), 8) net = layers.separable_conv2d( inputs, depth(64), [7, 7], depth_multiplier=depthwise_multiplier, stride=2, weights_initializer=trunc_normal(1.0), scope=end_point) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 112 x 112 x 64 end_point = 'MaxPool_2a_3x3' net = layers_lib.max_pool2d(net, [3, 3], scope=end_point, stride=2) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 56 x 56 x 64 end_point = 'Conv2d_2b_1x1' net = layers.conv2d( net, depth(64), [1, 1], scope=end_point, weights_initializer=trunc_normal(0.1)) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 56 x 56 x 64 end_point = 'Conv2d_2c_3x3' net = layers.conv2d(net, depth(192), [3, 3], scope=end_point) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 56 x 56 x 192 end_point = 'MaxPool_3a_3x3' net = layers_lib.max_pool2d(net, [3, 3], scope=end_point, stride=2) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 28 x 28 x 192 # Inception module. end_point = 'Mixed_3b' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(64), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(64), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(64), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(64), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(96), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(96), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(32), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat([branch_0, branch_1, branch_2, branch_3], 3) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 28 x 28 x 256 end_point = 'Mixed_3c' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(64), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(64), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(96), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(64), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(96), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(96), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(64), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat([branch_0, branch_1, branch_2, branch_3], 3) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 28 x 28 x 320 end_point = 'Mixed_4a' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(128), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_0 = layers.conv2d( branch_0, depth(160), [3, 3], stride=2, scope='Conv2d_1a_3x3') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(64), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(96), [3, 3], scope='Conv2d_0b_3x3') branch_1 = layers.conv2d( branch_1, depth(96), [3, 3], stride=2, scope='Conv2d_1a_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers_lib.max_pool2d( net, [3, 3], stride=2, scope='MaxPool_1a_3x3') net = array_ops.concat([branch_0, branch_1, branch_2], 3) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 14 x 14 x 576 end_point = 'Mixed_4b' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(224), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(64), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(96), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(96), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(128), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(128), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(128), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat([branch_0, branch_1, branch_2, branch_3], 3) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 14 x 14 x 576 end_point = 'Mixed_4c' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(192), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(96), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(128), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(96), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(128), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(128), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(128), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat([branch_0, branch_1, branch_2, branch_3], 3) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 14 x 14 x 576 end_point = 'Mixed_4d' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(160), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(128), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(160), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(128), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(160), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(160), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(96), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat([branch_0, branch_1, branch_2, branch_3], 3) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 14 x 14 x 576 end_point = 'Mixed_4e' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(96), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(128), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(192), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(160), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(192), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(192), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(96), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat([branch_0, branch_1, branch_2, branch_3], 3) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 14 x 14 x 576 end_point = 'Mixed_5a' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(128), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_0 = layers.conv2d( branch_0, depth(192), [3, 3], stride=2, scope='Conv2d_1a_3x3') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(192), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(256), [3, 3], scope='Conv2d_0b_3x3') branch_1 = layers.conv2d( branch_1, depth(256), [3, 3], stride=2, scope='Conv2d_1a_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers_lib.max_pool2d( net, [3, 3], stride=2, scope='MaxPool_1a_3x3') net = array_ops.concat([branch_0, branch_1, branch_2], 3) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 7 x 7 x 1024 end_point = 'Mixed_5b' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(352), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(192), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(320), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(160), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(224), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(224), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(128), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat([branch_0, branch_1, branch_2, branch_3], 3) end_points[end_point] = net if end_point == final_endpoint: return net, end_points # 7 x 7 x 1024 end_point = 'Mixed_5c' with variable_scope.variable_scope(end_point): with variable_scope.variable_scope('Branch_0'): branch_0 = layers.conv2d( net, depth(352), [1, 1], scope='Conv2d_0a_1x1') with variable_scope.variable_scope('Branch_1'): branch_1 = layers.conv2d( net, depth(192), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_1 = layers.conv2d( branch_1, depth(320), [3, 3], scope='Conv2d_0b_3x3') with variable_scope.variable_scope('Branch_2'): branch_2 = layers.conv2d( net, depth(192), [1, 1], weights_initializer=trunc_normal(0.09), scope='Conv2d_0a_1x1') branch_2 = layers.conv2d( branch_2, depth(224), [3, 3], scope='Conv2d_0b_3x3') branch_2 = layers.conv2d( branch_2, depth(224), [3, 3], scope='Conv2d_0c_3x3') with variable_scope.variable_scope('Branch_3'): branch_3 = layers_lib.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3') branch_3 = layers.conv2d( branch_3, depth(128), [1, 1], weights_initializer=trunc_normal(0.1), scope='Conv2d_0b_1x1') net = array_ops.concat([branch_0, branch_1, branch_2, branch_3], 3) end_points[end_point] = net if end_point == final_endpoint: return net, end_points raise ValueError('Unknown final endpoint %s' % final_endpoint)