Esempio n. 1
0
  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
Esempio n. 2
0
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)
Esempio n. 3
0
    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
Esempio n. 4
0
    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
Esempio n. 5
0
 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})
Esempio n. 6
0
    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
Esempio n. 8
0
    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)
Esempio n. 10
0
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
Esempio n. 12
0
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
Esempio n. 13
0
    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
Esempio n. 14
0
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)
Esempio n. 15
0
 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
Esempio n. 16
0
    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())
Esempio n. 18
0
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)))
Esempio n. 19
0
    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
        ]
Esempio n. 21
0
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)
Esempio n. 22
0
    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)
Esempio n. 24
0
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
Esempio n. 25
0
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()
Esempio n. 27
0
    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
Esempio n. 28
0
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)