Exemplo n.º 1
0
def _CloneWithNewOperands(layer_op, input_tensor, weight_tensor):
  """Clones layer_op with input_tensor and weight_tensor as new inputs."""
  new_layer_name = layer_op.name.split('/')[-1] + '_Fold'
  if layer_op.type == 'Conv2D':
    return nn_ops.conv2d(
        input_tensor,
        weight_tensor,
        strides=layer_op.get_attr('strides'),
        padding=layer_op.get_attr('padding'),
        use_cudnn_on_gpu=layer_op.get_attr('use_cudnn_on_gpu'),
        data_format=layer_op.get_attr('data_format'),
        name=new_layer_name)
  elif layer_op.type == 'MatMul':
    return math_ops.matmul(
        input_tensor,
        weight_tensor,
        transpose_a=layer_op.get_attr('transpose_a'),
        transpose_b=layer_op.get_attr('transpose_b'),
        name=new_layer_name)
  elif layer_op.type == 'DepthwiseConv2dNative':
    return nn.depthwise_conv2d(
        input_tensor,
        weight_tensor,
        strides=layer_op.get_attr('strides'),
        padding=layer_op.get_attr('padding'),
        name=new_layer_name)
  else:
    raise ValueError('Cannot handle operation of type: %s' % layer_op.type)
Exemplo n.º 2
0
    def testDepthwiseConv3x1(self):
        with self.session() as sess:
            with ops.device("/device:IPU:0"):
                pa = array_ops.placeholder(np.float32, [1, 2, 2, 3], name="a")
                pb = array_ops.placeholder(np.float32, [1, 1, 3, 1], name="b")
                pc = array_ops.placeholder(np.float32, [3], name="c")
                c = nn.depthwise_conv2d(pa,
                                        pb,
                                        strides=[1, 1, 1, 1],
                                        padding="SAME")
                output = c + pc

            report = tu.ReportJSON(self, sess)
            report.reset()

            fd = {
                pa: [[[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]],
                pb: [[[[6], [4], [2]]]],
                pc: [1, 1, 1]
            }
            result = sess.run(output, fd)
            self.assertAllClose(
                result,
                [[[[7, 9, 7], [25, 21, 13]], [[43, 33, 19], [61, 45, 25]]]])

            report.parse_log()

            # pylint: disable=line-too-long
            ok = [
                '__seed*', 'host-exchange-local-copy-', 'Copy_',
                'depthwise/convolution.*/Conv_1x1', 'add/fusion*/Add'
            ]
            # pylint: enable=line-too-long
            report.assert_all_compute_sets_and_list(ok)
Exemplo n.º 3
0
def _CloneWithNewOperands(layer_op, input_tensor, weight_tensor):
  """Clones layer_op with input_tensor and weight_tensor as new inputs."""
  new_layer_name = layer_op.name.split('/')[-1] + '_Fold'
  if layer_op.type == 'Conv2D':
    return nn_ops.conv2d(
        input_tensor,
        weight_tensor,
        strides=layer_op.get_attr('strides'),
        padding=layer_op.get_attr('padding'),
        use_cudnn_on_gpu=layer_op.get_attr('use_cudnn_on_gpu'),
        data_format=layer_op.get_attr('data_format'),
        name=new_layer_name)
  elif layer_op.type == 'MatMul':
    return math_ops.matmul(
        input_tensor,
        weight_tensor,
        transpose_a=layer_op.get_attr('transpose_a'),
        transpose_b=layer_op.get_attr('transpose_b'),
        name=new_layer_name)
  elif layer_op.type == 'DepthwiseConv2dNative':
    return nn.depthwise_conv2d(
        input_tensor,
        weight_tensor,
        strides=layer_op.get_attr('strides'),
        padding=layer_op.get_attr('padding'),
        name=new_layer_name)
  else:
    raise ValueError('Cannot handle operation of type: %s' % layer_op.type)
Exemplo n.º 4
0
 def _CloneDepthwiseConv2d(self, op, inputs, new_name):
     input_tensor = inputs[0]
     weights = inputs[1]
     self._AssertConvShapes(op.name, input_tensor, weights)
     return nn.depthwise_conv2d(input_tensor,
                                weights,
                                strides=op.get_attr('strides'),
                                padding=op.get_attr('padding'),
                                name=new_name).op
Exemplo n.º 5
0
 def reducer(x):
     shape = array_ops.shape(x)
     x = array_ops.reshape(x, shape=array_ops.concat([[-1], shape[-3:]], 0))
     y = nn.depthwise_conv2d(x,
                             kernel,
                             strides=[1, 1, 1, 1],
                             padding='VALID')
     return array_ops.reshape(
         y,
         array_ops.concat([shape[:-3], array_ops.shape(y)[1:]], 0))
Exemplo n.º 6
0
 def _CloneDepthwiseConv2d(self, op, inputs, new_name):
   input_tensor = inputs[0]
   weights = inputs[1]
   self._AssertConvShapes(op.name, input_tensor, weights)
   return nn.depthwise_conv2d(
       input_tensor,
       weights,
       strides=op.get_attr('strides'),
       padding=op.get_attr('padding'),
       name=new_name).op
Exemplo n.º 7
0
    def testSeparableConvWithResourceVar(self):
        graph = ops.Graph()
        with graph.as_default():
            with variable_scope.variable_scope('', use_resource=True):
                batch_size, height, width, depth = 5, 128, 128, 3
                input1 = array_ops.zeros((batch_size, height, width, depth))
                kernel_size, depth_multiplier = 3, 1
                depthwise_shape = [
                    kernel_size, kernel_size, depth, depth_multiplier
                ]
                depthwise_weights = variables.model_variable(
                    'depthwise_weights', shape=depthwise_shape)
                strides = [1, 1, 1, 1]
                with variable_scope.variable_scope('depthwise_conv_1'):
                    conv1 = nn.depthwise_conv2d(input1,
                                                depthwise_weights,
                                                strides,
                                                padding='SAME')
                with variable_scope.variable_scope('depthwise_conv_2'):
                    conv2 = nn.depthwise_conv2d(conv1,
                                                depthwise_weights,
                                                strides,
                                                padding='SAME')
                    math_ops.add(conv2, input1, name='add')

        quantize.Quantize(graph, True)

        # Test that the weights and activations of all convs have been quantized.
        quant_node_name = 'FakeQuantWithMinMaxVars'
        weights_quant = graph.get_operation_by_name(
            'depthwise_conv_1/weights_quant/' + quant_node_name)
        self.assertEqual(weights_quant.type, quant_node_name)
        act_quant = graph.get_operation_by_name('depthwise_conv_1/act_quant/' +
                                                quant_node_name)
        self.assertEqual(act_quant.type, quant_node_name)

        weights_quant = graph.get_operation_by_name(
            'depthwise_conv_2/weights_quant/' + quant_node_name)
        self.assertEqual(weights_quant.type, quant_node_name)
        act_quant = graph.get_operation_by_name('depthwise_conv_2/act_quant/' +
                                                quant_node_name)
        self.assertEqual(act_quant.type, quant_node_name)
Exemplo n.º 8
0
def _CloneWithNewOperands(layer_op, input_tensor, weight_tensor,
                          batch_to_space_op):
    """Clones layer_op with input_tensor and weight_tensor as new inputs."""
    new_layer_name = layer_op.name.split('/')[-1] + '_Fold'
    if layer_op.type == 'Conv2D':
        conv = nn_ops.conv2d(
            input_tensor,
            weight_tensor,
            strides=layer_op.get_attr('strides'),
            padding=layer_op.get_attr('padding'),
            use_cudnn_on_gpu=layer_op.get_attr('use_cudnn_on_gpu'),
            data_format=layer_op.get_attr('data_format'),
            name=new_layer_name)
        if batch_to_space_op:
            batch_to_space_op = layer_op.outputs[0].consumers()[0]
            # TODO(suharshs): It's hard to make this name match with the unfused name.
            # Restructure this code to not rely on scope at all.
            new_batch_to_space_name = batch_to_space_op.name.split(
                '/')[-1] + '_Fold'
            conv = array_ops.batch_to_space_nd(conv,
                                               batch_to_space_op.inputs[1],
                                               batch_to_space_op.inputs[2],
                                               name=new_batch_to_space_name)
        return conv
    elif layer_op.type == 'MatMul':
        return math_ops.matmul(input_tensor,
                               weight_tensor,
                               transpose_a=layer_op.get_attr('transpose_a'),
                               transpose_b=layer_op.get_attr('transpose_b'),
                               name=new_layer_name)
    elif layer_op.type == 'DepthwiseConv2dNative':
        # We don't copy dilation rate because we reuse the input SpaceToBatch
        # and create our own BatchToSpace operation below.
        conv = nn.depthwise_conv2d(input_tensor,
                                   weight_tensor,
                                   strides=layer_op.get_attr('strides'),
                                   padding=layer_op.get_attr('padding'),
                                   name=new_layer_name)
        # Copy the batch to space operation if we have a atrous convolution.
        if batch_to_space_op:
            batch_to_space_op = layer_op.outputs[0].consumers()[0]
            # TODO(suharshs): It's hard to make this name match with the unfused name.
            # Restructure this code to not rely on scope at all.
            new_batch_to_space_name = batch_to_space_op.name.split(
                '/')[-1] + '_Fold'
            conv = array_ops.batch_to_space_nd(conv,
                                               batch_to_space_op.inputs[1],
                                               batch_to_space_op.inputs[2],
                                               name=new_batch_to_space_name)
        return conv
    else:
        raise ValueError('Cannot handle operation of type: %s' % layer_op.type)
Exemplo n.º 9
0
  def test_group_conv_depthwise(self):
    if test.is_gpu_available(cuda_only=True):
      with testing_utils.use_gpu():
        inputs = random_ops.random_uniform(shape=(3, 27, 27, 32))

        layer = keras.layers.Conv2D(32, 3, groups=32, use_bias=False)
        layer.build((3, 27, 27, 32))

        weights_dw = array_ops.reshape(layer.kernel, [3, 3, 32, 1])
        expected_outputs = nn.depthwise_conv2d(
            inputs, weights_dw, strides=[1, 1, 1, 1], padding='VALID')

        self.assertAllClose(layer(inputs), expected_outputs, rtol=1e-5)
Exemplo n.º 10
0
  def testSeparableConvWithResourceVar(self):
    graph = ops.Graph()
    with graph.as_default():
      with variable_scope.variable_scope('', use_resource=True):
        batch_size, height, width, depth = 5, 128, 128, 3
        input1 = array_ops.zeros((batch_size, height, width, depth))
        kernel_size, depth_multiplier = 3, 1
        depthwise_shape = [kernel_size, kernel_size, depth, depth_multiplier]
        depthwise_weights = variables.model_variable(
            'depthwise_weights', shape=depthwise_shape)
        strides = [1, 1, 1, 1]
        with variable_scope.variable_scope('depthwise_conv_1'):
          conv1 = nn.depthwise_conv2d(
              input1, depthwise_weights, strides, padding='SAME')
        with variable_scope.variable_scope('depthwise_conv_2'):
          conv2 = nn.depthwise_conv2d(
              conv1, depthwise_weights, strides, padding='SAME')
          math_ops.add(conv2, input1, name='add')

    quantize.Quantize(graph, True)

    # Test that the weights and activations of all convs have been quantized.
    quant_node_name = 'FakeQuantWithMinMaxVars'
    weights_quant = graph.get_operation_by_name(
        'depthwise_conv_1/weights_quant/' + quant_node_name)
    self.assertEqual(weights_quant.type, quant_node_name)
    act_quant = graph.get_operation_by_name('depthwise_conv_1/act_quant/' +
                                            quant_node_name)
    self.assertEqual(act_quant.type, quant_node_name)

    weights_quant = graph.get_operation_by_name(
        'depthwise_conv_2/weights_quant/' + quant_node_name)
    self.assertEqual(weights_quant.type, quant_node_name)
    act_quant = graph.get_operation_by_name('depthwise_conv_2/act_quant/' +
                                            quant_node_name)
    self.assertEqual(act_quant.type, quant_node_name)
Exemplo n.º 11
0
 def call(self, inputs):
     filter = np.array(self.filter, np.float32)
     if filter.ndim == 1:
         filter = filter[:, np.newaxis] * filter[np.newaxis, :]
     if self.normalize:
         filter /= np.sum(filter)
     filter = filter[:, :, np.newaxis, np.newaxis]
     filter = K.constant(filter, dtype=inputs.dtype, name='filter')
     filter = K.tile(filter, [1, 1, K.shape(inputs)[-1], 1])
     outputs = nn.depthwise_conv2d(
         inputs,
         filter,
         strides=(1, self.stride, self.stride, 1),
         padding='SAME')
     return outputs
Exemplo n.º 12
0
 def forward(self, inputs):
     strides = (1,) + self.strides + (1,)\
         if self.data_format[-1] == 'C' else (1, 1) + self.strides
     outputs = nn.depthwise_conv2d(input=inputs,
                                   filter=self.kernel,
                                   strides=strides,
                                   padding=self.padding,
                                   data_format=self.data_format,
                                   rate=self.dilation_rate)
     if self.use_bias:
         outputs = F.bias_add(outputs,
                              self.bias,
                              data_format=self.data_format)
     if self.activation is not None:
         outputs = self.activation(outputs)
     return outputs
Exemplo n.º 13
0
    def call(self, inputs):
        if self.padding == 'causal':
            inputs = array_ops.pad(inputs, self._compute_causal_padding())
        if self.data_format == 'channels_last':
            strides = (1, ) + self.strides * 2 + (1, )
            spatial_start_dim = 1
        else:
            strides = (1, 1) + self.strides * 2
            spatial_start_dim = 2

        # Explicitly broadcast inputs and kernels to 4D.
        inputs = array_ops.expand_dims(inputs, spatial_start_dim)

        if self.common_kernel == True:
            #Need to replicate kernel {channels} times over axis 1
            dw_kernel = tf.tile(self.depthwise_kernel, (1, self.channels, 1))
            bias_kernel = tf.tile(self.bias, (self.channels, ))
        else:
            dw_kernel = self.depthwise_kernel
            bias_kernel = self.bias

        dw_kernel = array_ops.expand_dims(dw_kernel, 0)

        if self.padding == 'causal':
            op_padding = 'valid'
        else:
            op_padding = self.padding
        outputs = nn.depthwise_conv2d(
            inputs,
            dw_kernel,
            strides=strides,
            padding=op_padding.upper(),
            data_format=conv_utils.convert_data_format(self.data_format,
                                                       ndim=4))

        outputs = array_ops.squeeze(outputs, [spatial_start_dim])

        if self.use_bias:
            outputs = backend.bias_add(outputs,
                                       bias_kernel,
                                       data_format=self.data_format)

        if self.activation is not None:
            return self.activation(outputs)

        return outputs
Exemplo n.º 14
0
def _CloneWithNewOperands(layer_op, input_tensor, weight_tensor,
                          batch_to_space_op):
  """Clones layer_op with input_tensor and weight_tensor as new inputs."""
  new_layer_name = layer_op.name.split('/')[-1] + '_Fold'
  if layer_op.type == 'Conv2D':
    return nn_ops.conv2d(
        input_tensor,
        weight_tensor,
        strides=layer_op.get_attr('strides'),
        padding=layer_op.get_attr('padding'),
        use_cudnn_on_gpu=layer_op.get_attr('use_cudnn_on_gpu'),
        data_format=layer_op.get_attr('data_format'),
        name=new_layer_name)
  elif layer_op.type == 'MatMul':
    return math_ops.matmul(
        input_tensor,
        weight_tensor,
        transpose_a=layer_op.get_attr('transpose_a'),
        transpose_b=layer_op.get_attr('transpose_b'),
        name=new_layer_name)
  elif layer_op.type == 'DepthwiseConv2dNative':
    # We don't copy dilation rate because we reuse the input SpaceToBatch
    # and create our own BatchToSpace operation below.
    conv = nn.depthwise_conv2d(
        input_tensor,
        weight_tensor,
        strides=layer_op.get_attr('strides'),
        padding=layer_op.get_attr('padding'),
        name=new_layer_name)
    # Copy the batch to space operation if we have a atrous convolution.
    if batch_to_space_op:
      batch_to_space_op = layer_op.outputs[0].consumers()[0]
      # TODO(suharshs): It's hard to make this name match with the unfused name.
      # Restructure this code to not rely on scope at all.
      new_batch_to_space_name = batch_to_space_op.name.split('/')[-1] + '_Fold'
      conv = array_ops.batch_to_space_nd(
          conv,
          batch_to_space_op.inputs[1],
          batch_to_space_op.inputs[2],
          name=new_batch_to_space_name)
    return conv
  else:
    raise ValueError('Cannot handle operation of type: %s' % layer_op.type)
Exemplo n.º 15
0
def sobel_edges_tfpad(image):
    """Returns a tensor holding Sobel edge maps.
     Note: image is CONSTANT(0) padded instead of REFLECT padded.
  Arguments:
    image: Image tensor with shape [batch_size, h, w, d] and type float32 or
      float64.  The image(s) must be 2x2 or larger.
  Returns:
    Tensor holding edge maps for each channel. Returns a tensor with shape
    [batch_size, h, w, d, 2] where the last two dimensions hold [[dy[0], dx[0]],
    [dy[1], dx[1]], ..., [dy[d-1], dx[d-1]]] calculated using the Sobel filter.
  """
    # Define vertical and horizontal Sobel filters.
    static_image_shape = image.get_shape()
    image_shape = array_ops.shape(image)

    num_kernels = 2
    sobel_kn = tf.constant([[[-1, -2, -1], [0, 0, 0], [1, 2, 1]],
                            [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]],
                           dtype=tf.float32)
    kernels_tf = tf.expand_dims(tf.transpose(sobel_kn, perm=(1, 2, 0)),
                                axis=-2)

    kernels_tf = array_ops.tile(kernels_tf, [1, 1, image_shape[-1], 1],
                                name='sobel_filters')

    # Use depth-wise convolution to calculate edge maps per channel.
    #pad_sizes = [[0, 0], [1, 1], [1, 1], [0, 0]]
    pad_sizes = tf.constant([[0, 0], [1, 1], [1, 1], [0, 0]], dtype=tf.int32)
    #padded = array_ops.pad(image, pad_sizes, mode='REFLECT')
    #padded = tf.pad(tensor=image, paddings=pad_sizes, mode='REFLECT')
    padded = tf.pad(tensor=image, paddings=pad_sizes, mode='CONSTANT')

    # Output tensor has shape [batch_size, h, w, d * num_kernels].
    strides = [1, 1, 1, 1]
    output = nn.depthwise_conv2d(padded, kernels_tf, strides, 'VALID')

    # Reshape to [batch_size, h, w, d, num_kernels].
    shape = array_ops.concat([image_shape, [num_kernels]], 0)
    output = array_ops.reshape(output, shape=shape)
    output.set_shape(static_image_shape.concatenate([num_kernels]))
    return output
Exemplo n.º 16
0
def depthwise_conv2d(x,
                     depthwise_kernel,
                     strides=(1, 1),
                     padding='valid',
                     data_format=None,
                     dilation_rate=(1, 1)):
    """2D convolution with separable filters.
    Arguments:
        x: input tensor
        depthwise_kernel: convolution kernel for the depthwise convolution.
        strides: strides tuple (length 2).
        padding: padding mode, "valid" or "same".
        data_format: data format, "channels_first" or "channels_last".
        dilation_rate: tuple of integers,
            dilation rates for the depthwise convolution.
  
    Returns:
        Output tensor.
  
    Raises:
        ValueError: if `data_format` is neither `channels_last` or
        `channels_first`.
    """
    if data_format is None:
        data_format = K.image_data_format()
    if data_format not in {'channels_first', 'channels_last'}:
        raise ValueError('Unknown data_format ' + str(data_format))

    x = K._preprocess_conv2d_input(x, data_format)
    padding = K._preprocess_padding(padding)
    strides = (1, ) + strides + (1, )

    x = nn.depthwise_conv2d(x,
                            depthwise_kernel,
                            strides=strides,
                            padding=padding,
                            rate=dilation_rate)
    return K._postprocess_conv2d_output(x, data_format)
Exemplo n.º 17
0
  def testDepthwiseConv3x1(self):
    with ops.device("/device:IPU:0"):
      pa = array_ops.placeholder(np.float32, [1, 2, 2, 3], name="a")
      pb = array_ops.placeholder(np.float32, [1, 1, 3, 1], name="b")
      pc = array_ops.placeholder(np.float32, [3], name="c")
      c = nn.depthwise_conv2d(pa, pb, strides=[1, 1, 1, 1], padding="SAME")
      output = c + pc

    with ops.device('cpu'):
      report = gen_ipu_ops.ipu_event_trace()

    tu.configure_ipu_system()

    with tu.ipu_session() as sess:
      sess.run(report)

      fd = {
          pa: [[[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]],
          pb: [[[[6], [4], [2]]]],
          pc: [1, 1, 1]
      }
      result = sess.run(output, fd)
      self.assertAllClose(
          result, [[[[7, 9, 7], [25, 21, 13]], [[43, 33, 19], [61, 45, 25]]]])

      result = sess.run(report)

      s = tu.extract_all_strings_from_event_trace(result)
      cs_list = tu.get_compute_sets_from_report(s)

      ok = [
          '__seed*', 'host-exchange-local-copy-', 'Copy_',
          'depthwise/convolution.*/Conv_1x1',
          'Copy_depthwise/convolution.*/Conv_1x1/partials_to_depthwise/convolution.*/Conv_1x1/partials[[]cloned[]]',
          'add/fusion*/addToChannel'
      ]
      self.assertTrue(tu.check_all_compute_sets_and_list(cs_list, ok))
Exemplo n.º 18
0
def depthwise_leaders_convolution2d(
        inputs,
        kernel_size,
        stride=1,
        padding='SAME',
        rates=[1, 2],
        pooling_sizes=[3, 1],
        pooling_type='MAX',
        activation_fn=nn.relu,
        normalizer_fn=None,
        normalizer_params=None,
        weights_initializer=initializers.xavier_initializer(),
        weights_regularizer=None,
        biases_initializer=init_ops.zeros_initializer(),
        biases_regularizer=None,
        reuse=None,
        variables_collections=None,
        outputs_collections=None,
        trainable=True,
        data_format='NHWC',
        scope=None):
    """Adds a depthwise 2D convolution with optional batch_norm layer.
    This op performs a depthwise convolution that acts separately on
    channels, creating a variable called `depthwise_weights`. Then,
    if `normalizer_fn` is None,
    it adds bias to the result, creating a variable called 'biases', otherwise,
    the `normalizer_fn` is applied. It finally applies an activation function
    to produce the end result.
    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
          of the filters. Can be an int if both values are the same.
        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.
        padding: One of 'VALID' or 'SAME'.
        rate: A list of length 2: [rate_height, rate_width], specifying the dilation
          rates for atrous convolution. Can be an int if both rates are the same.
          If any value is larger than one, then both stride values need to be one.
        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`. If
          `normalizer_fn` is provided then `biases_initializer` and
          `biases_regularizer` are ignored and `biases` are not created nor added.
          default set to None for no normalizer function
        normalizer_params: Normalization function parameters.
        weights_initializer: An initializer for the weights.
        weights_regularizer: Optional regularizer for the weights.
        biases_initializer: An initializer for the biases. If None skip biases.
        biases_regularizer: Optional regularizer for the biases.
        reuse: Whether or not the layer and its variables should be reused. To be
          able to reuse the layer scope must be given.
        variables_collections: Optional list of collections for all the variables or
          a dictionary containing a different list of collection per variable.
        outputs_collections: Collection to add the outputs.
        trainable: Whether or not the variables should be trainable or not.
        scope: Optional scope for variable_scope.
    Returns:
        A `Tensor` representing the output of the operation.
    """
    with variable_scope.variable_scope(scope,
                                       'DepthwiseLeadersConv2d', [inputs],
                                       reuse=reuse) as sc:
        inputs = ops.convert_to_tensor(inputs)
        dtype = inputs.dtype.base_dtype
        kernel_h, kernel_w = utils.two_element_tuple(kernel_size)
        stride_h, stride_w = utils.two_element_tuple(stride)
        if data_format == 'NHWC':
            num_filters_in = utils.last_dimension(inputs.get_shape(),
                                                  min_rank=4)
            strides = [1, stride_h, stride_w, 1]
        else:
            num_filters_in = inputs.get_shape().as_list()[1]
            strides = [1, 1, stride_h, stride_w]
        # Depthwise weights + biases variables.
        depth_multiplier = 1
        num_outputs = depth_multiplier * num_filters_in

        weights_collections = utils.get_variable_collections(
            variables_collections, 'weights')
        depthwise_shape = [
            kernel_h, kernel_w, num_filters_in, depth_multiplier
        ]
        depthwise_weights = variables.model_variable(
            'depthwise_weights',
            shape=depthwise_shape,
            dtype=dtype,
            initializer=weights_initializer,
            regularizer=weights_regularizer,
            trainable=trainable,
            collections=weights_collections)
        biases_collections = utils.get_variable_collections(
            variables_collections, 'biases')
        biases = variables.model_variable('biases',
                                          shape=[
                                              num_outputs,
                                          ],
                                          dtype=dtype,
                                          initializer=biases_initializer,
                                          regularizer=biases_regularizer,
                                          trainable=trainable,
                                          collections=biases_collections)

        # Perform the convolution at different rates.
        outputs = []
        for i, rate in enumerate(rates):
            # Depthwise conv.
            net = nn.depthwise_conv2d(inputs,
                                      depthwise_weights,
                                      strides=[1, 1, 1, 1],
                                      padding='SAME',
                                      rate=utils.two_element_tuple(rate),
                                      data_format=data_format)
            # Add bias + abs. val.
            net = tf.abs(nn.bias_add(net, biases, data_format=data_format))
            # Pooling...
            if pooling_sizes[i] > 1:
                net = tf.nn.pool(net, [pooling_sizes[i], pooling_sizes[i]],
                                 pooling_type,
                                 padding='SAME',
                                 data_format=data_format)
            outputs.append(net)
        # Fuse different rates/scales.
        net = None
        for i, o in enumerate(outputs):
            if net is None:
                # First in the list...
                net = o
            else:
                # MAX or AVG pooling...
                if pooling_type == 'MAX':
                    net = tf.maximum(net, o)
                else:
                    net += o * pooling_sizes[i]**2
        # Pooling => for stride > 1
        if stride_h > 1 or stride_w > 1:
            # net = tf.nn.pool(net,
            #                  [1, 1],
            #                  pooling_type,
            #                  padding='SAME',
            #                  strides=[stride_h, stride_w],
            #                  data_format=data_format)
            net = tf.nn.max_pool(net, [1, 1, 1, 1],
                                 padding='SAME',
                                 strides=strides,
                                 data_format=data_format)
        # (Batch normalization)...
        normalizer_params = normalizer_params or {}
        net = normalizer_fn(net, **normalizer_params)

        # Split into two parts: positive and negative extreme.
        net_p = slim.bias_add(net,
                              data_format=data_format,
                              scope='bias_positive')
        net_p = activation_fn(net_p)
        # net_p = slim.dropout(net_p, 0.5, is_training=True, scope='dropout_p')

        net_m = slim.bias_add(-net,
                              data_format=data_format,
                              scope='bias_negative')
        net_m = activation_fn(net_m)
        # net_m = slim.dropout(net_m, 0.5, is_training=True, scope='dropout_m')

        # Concat the final result...
        outputs = concat_channels([net_p, net_m], data_format=data_format)
        return utils.collect_named_outputs(outputs_collections,
                                           sc.original_name_scope, outputs)
Exemplo n.º 19
0
def depthwise_convolution2d(
        inputs,
        kernel_size,
        depth_multiplier=1,
        stride=1,
        padding='SAME',
        rate=1,
        activation_fn=nn.relu,
        normalizer_fn=None,
        normalizer_params=None,
        weights_initializer=initializers.xavier_initializer(),
        weights_regularizer=None,
        biases_initializer=init_ops.zeros_initializer(),
        biases_regularizer=None,
        reuse=None,
        variables_collections=None,
        outputs_collections=None,
        trainable=True,
        data_format='NHWC',
        scope=None):
    """Adds a depthwise 2D convolution with optional batch_norm layer.
    This op performs a depthwise convolution that acts separately on
    channels, creating a variable called `depthwise_weights`. Then,
    if `normalizer_fn` is None,
    it adds bias to the result, creating a variable called 'biases', otherwise,
    the `normalizer_fn` is applied. It finally applies an activation function
    to produce the end result.
    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
          of the filters. Can be an int if both values are the same.
        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.
        padding: One of 'VALID' or 'SAME'.
        rate: A list of length 2: [rate_height, rate_width], specifying the dilation
          rates for atrous convolution. Can be an int if both rates are the same.
          If any value is larger than one, then both stride values need to be one.
        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`. If
          `normalizer_fn` is provided then `biases_initializer` and
          `biases_regularizer` are ignored and `biases` are not created nor added.
          default set to None for no normalizer function
        normalizer_params: Normalization function parameters.
        weights_initializer: An initializer for the weights.
        weights_regularizer: Optional regularizer for the weights.
        biases_initializer: An initializer for the biases. If None skip biases.
        biases_regularizer: Optional regularizer for the biases.
        reuse: Whether or not the layer and its variables should be reused. To be
          able to reuse the layer scope must be given.
        variables_collections: Optional list of collections for all the variables or
          a dictionary containing a different list of collection per variable.
        outputs_collections: Collection to add the outputs.
        trainable: Whether or not the variables should be trainable or not.
        scope: Optional scope for variable_scope.
    Returns:
        A `Tensor` representing the output of the operation.
    """
    with variable_scope.variable_scope(scope, 'DepthwiseConv2d', [inputs],
                                       reuse=reuse) as sc:
        inputs = ops.convert_to_tensor(inputs)
        # Actually apply depthwise conv instead of separable conv.
        dtype = inputs.dtype.base_dtype
        kernel_h, kernel_w = utils.two_element_tuple(kernel_size)
        stride_h, stride_w = utils.two_element_tuple(stride)
        if data_format == 'NHWC':
            num_filters_in = utils.last_dimension(inputs.get_shape(), min_rank=4)
            strides = [1, stride_h, stride_w, 1]
        else:
            num_filters_in = inputs.get_shape().as_list()[1]
            strides = [1, 1, stride_h, stride_w]

        weights_collections = utils.get_variable_collections(
            variables_collections, 'weights')

        # Depthwise weights variable.
        depthwise_shape = [kernel_h, kernel_w,
                           num_filters_in, depth_multiplier]
        depthwise_weights = variables.model_variable(
            'depthwise_weights',
            shape=depthwise_shape,
            dtype=dtype,
            initializer=weights_initializer,
            regularizer=weights_regularizer,
            trainable=trainable,
            collections=weights_collections)

        outputs = nn.depthwise_conv2d(inputs, depthwise_weights,
                                      strides, padding,
                                      rate=utils.two_element_tuple(rate),
                                      data_format=data_format)
        num_outputs = depth_multiplier * num_filters_in

        if normalizer_fn is not None:
            normalizer_params = normalizer_params or {}
            outputs = normalizer_fn(outputs, **normalizer_params)
        else:
            if biases_initializer is not None:
                biases_collections = utils.get_variable_collections(
                    variables_collections, 'biases')
                biases = variables.model_variable('biases',
                                                  shape=[num_outputs,],
                                                  dtype=dtype,
                                                  initializer=biases_initializer,
                                                  regularizer=biases_regularizer,
                                                  trainable=trainable,
                                                  collections=biases_collections)
                outputs = nn.bias_add(outputs, biases, data_format=data_format)
        if activation_fn is not None:
            outputs = activation_fn(outputs)
        return utils.collect_named_outputs(outputs_collections,
                                           sc.original_name_scope, outputs)
def _depthwise_conv(inputs, weights_shape, strides, padding='SAME'):
    weights = tf.Variable(
        tf.random_normal(shape=weights_shape, dtype=tf.float32))
    return nn.depthwise_conv2d(inputs, weights, strides, padding=padding)
Exemplo n.º 21
0
def _depthwise_conv2d(x, w):
    """Returns a 2d depthwise convolution layer with full stride."""
    return nn.depthwise_conv2d(x, w, strides=[1, 1, 1, 1], padding='SAME')
Exemplo n.º 22
0
def depthwise_convolution2d(
        inputs,
        kernel_size,
        depth_multiplier=1,
        stride=1,
        padding='SAME',
        rate=1,
        activation_fn=nn.relu,
        normalizer_fn=None,
        normalizer_params=None,
        weights_initializer=initializers.xavier_initializer(),
        weights_regularizer=None,
        biases_initializer=init_ops.zeros_initializer(),
        biases_regularizer=None,
        reuse=None,
        variables_collections=None,
        outputs_collections=None,
        trainable=True,
        data_format='NHWC',
        scope=None):
    """Adds a depthwise 2D convolution with optional batch_norm layer.
    This op performs a depthwise convolution that acts separately on
    channels, creating a variable called `depthwise_weights`. Then,
    if `normalizer_fn` is None,
    it adds bias to the result, creating a variable called 'biases', otherwise,
    the `normalizer_fn` is applied. It finally applies an activation function
    to produce the end result.
    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
          of the filters. Can be an int if both values are the same.
        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.
        padding: One of 'VALID' or 'SAME'.
        rate: A list of length 2: [rate_height, rate_width], specifying the dilation
          rates for atrous convolution. Can be an int if both rates are the same.
          If any value is larger than one, then both stride values need to be one.
        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`. If
          `normalizer_fn` is provided then `biases_initializer` and
          `biases_regularizer` are ignored and `biases` are not created nor added.
          default set to None for no normalizer function
        normalizer_params: Normalization function parameters.
        weights_initializer: An initializer for the weights.
        weights_regularizer: Optional regularizer for the weights.
        biases_initializer: An initializer for the biases. If None skip biases.
        biases_regularizer: Optional regularizer for the biases.
        reuse: Whether or not the layer and its variables should be reused. To be
          able to reuse the layer scope must be given.
        variables_collections: Optional list of collections for all the variables or
          a dictionary containing a different list of collection per variable.
        outputs_collections: Collection to add the outputs.
        trainable: Whether or not the variables should be trainable or not.
        scope: Optional scope for variable_scope.
    Returns:
        A `Tensor` representing the output of the operation.
    """
    with variable_scope.variable_scope(scope,
                                       'DepthwiseConv2d', [inputs],
                                       reuse=reuse) as sc:
        inputs = ops.convert_to_tensor(inputs)
        # Actually apply depthwise conv instead of separable conv.
        dtype = inputs.dtype.base_dtype
        kernel_h, kernel_w = utils.two_element_tuple(kernel_size)
        stride_h, stride_w = utils.two_element_tuple(stride)
        if data_format == 'NHWC':
            num_filters_in = utils.last_dimension(inputs.get_shape(),
                                                  min_rank=4)
            strides = [1, stride_h, stride_w, 1]
        else:
            num_filters_in = inputs.get_shape().as_list()[1]
            strides = [1, 1, stride_h, stride_w]

        weights_collections = utils.get_variable_collections(
            variables_collections, 'weights')

        # Depthwise weights variable.
        depthwise_shape = [
            kernel_h, kernel_w, num_filters_in, depth_multiplier
        ]
        depthwise_weights = variables.model_variable(
            'depthwise_weights',
            shape=depthwise_shape,
            dtype=dtype,
            initializer=weights_initializer,
            regularizer=weights_regularizer,
            trainable=trainable,
            collections=weights_collections)

        outputs = nn.depthwise_conv2d(inputs,
                                      depthwise_weights,
                                      strides,
                                      padding,
                                      rate=utils.two_element_tuple(rate),
                                      data_format=data_format)
        num_outputs = depth_multiplier * num_filters_in

        if normalizer_fn is not None:
            normalizer_params = normalizer_params or {}
            outputs = normalizer_fn(outputs, **normalizer_params)
        else:
            if biases_initializer is not None:
                biases_collections = utils.get_variable_collections(
                    variables_collections, 'biases')
                biases = variables.model_variable(
                    'biases',
                    shape=[
                        num_outputs,
                    ],
                    dtype=dtype,
                    initializer=biases_initializer,
                    regularizer=biases_regularizer,
                    trainable=trainable,
                    collections=biases_collections)
                outputs = nn.bias_add(outputs, biases, data_format=data_format)
        if activation_fn is not None:
            outputs = activation_fn(outputs)
        return utils.collect_named_outputs(outputs_collections,
                                           sc.original_name_scope, outputs)
Exemplo n.º 23
0
def separable_convolution2d_diffpad(
        inputs,
        num_outputs,
        kernel_size,
        depth_multiplier,
        stride=1,
        padding='SAME',
        activation_fn=nn.relu,
        normalizer_fn=None,
        normalizer_params=None,
        weights_initializer=initializers.xavier_initializer(),
        weights_regularizer=None,
        biases_initializer=init_ops.zeros_initializer,
        biases_regularizer=None,
        reuse=None,
        variables_collections=None,
        outputs_collections=None,
        trainable=True,
        scope=None):
    """Adds a depth-separable 2D convolution with optional batch_norm layer.
    This op first performs a depthwise convolution that acts separately on
    channels, creating a variable called `depthwise_weights`. If `num_outputs`
    is not None, it adds a pointwise convolution that mixes channels, creating a
    variable called `pointwise_weights`. Then, if `batch_norm_params` is None,
    it adds bias to the result, creating a variable called 'biases', otherwise
    it adds a batch normalization layer. It finally applies an activation function
    to produce the end result.
    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
            of the filters. Can be an int if both values are the same.
        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.
        padding: one of 'VALID' or 'SAME'.
        activation_fn: activation function, set to None to skip it and maintain
            a linear activation.
        normalizer_fn: normalization function to use instead of `biases`. If
            `normalizer_fn` is provided then `biases_initializer` and
            `biases_regularizer` are ignored and `biases` are not created nor added.
            default set to None for no normalizer function
        normalizer_params: normalization function parameters.
        weights_initializer: An initializer for the weights.
        weights_regularizer: Optional regularizer for the weights.
        biases_initializer: An initializer for the biases. If None skip biases.
        biases_regularizer: Optional regularizer for the biases.
        reuse: whether or not the layer and its variables should be reused. To be
            able to reuse the layer scope must be given.
        variables_collections: optional list of collections for all the variables or
            a dictionay containing a different list of collection per variable.
        outputs_collections: collection to add the outputs.
        trainable: whether or not the variables should be trainable or not.
        scope: Optional scope for variable_scope.
    Returns:
        A `Tensor` representing the output of the operation.
    """
    with variable_scope.variable_scope(
            scope, 'SeparableConv2dPad', [inputs], reuse=reuse) as sc:
        # TOFIX: Hard set padding and multiplier...
        padding = 'SAME'
        depth_multiplier = 1

        dtype = inputs.dtype.base_dtype
        kernel_h, kernel_w = utils.two_element_tuple(kernel_size)
        stride_h, stride_w = utils.two_element_tuple(stride)
        num_filters_in = utils.last_dimension(inputs.get_shape(), min_rank=4)
        weights_collections = utils.get_variable_collections(
                variables_collections, 'weights')

        depthwise_shape = [kernel_h, kernel_w,
                           num_filters_in, depth_multiplier]
        depthwise_weights = variables.model_variable(
                'depthwise_weights',
                shape=depthwise_shape,
                dtype=dtype,
                initializer=weights_initializer,
                regularizer=weights_regularizer,
                trainable=trainable,
                collections=weights_collections)
        strides = [1, stride_h, stride_w, 1]

        # Classic depthwise_conv2d with SAME padding (i.e. zero padding).
        outputs = nn.depthwise_conv2d(inputs, depthwise_weights, strides, padding)

        # Fix padding according too the difference rule. Dirty shit!
        # diff_padding = variables.local_variable(outputs)
        diff_padding = variables.variable(
            'diff_padding',
            shape=outputs.get_shape(),
            dtype=dtype,
            initializer=tf.constant_initializer(0.0),
            regularizer=None,
            trainable=False,
            collections=[ops.GraphKeys.LOCAL_VARIABLES])

        # Bottom and top fixing...
        # print(diff_padding[:, 0, :, :].get_shape())
        # print(depthwise_weights[0, 0, :, 0].get_shape())
        op1 = diff_padding[:, 0, :, :].assign(
            outputs[:, 0, :, :] * (depthwise_weights[0, 0, :, 0] +
                                   depthwise_weights[0, 1, :, 0] +
                                   depthwise_weights[0, 2, :, 0]))
        op2 = diff_padding[:, -1, :, :].assign(
            outputs[:, -1, :, :] * (depthwise_weights[-1, 0, :, 0] +
                                    depthwise_weights[-1, 1, :, 0] +
                                    depthwise_weights[-1, 2, :, 0]))
        # Bottom and top fixing...
        op3 = diff_padding[:, :, 0, :].assign(
            outputs[:, :, 0, :] * (depthwise_weights[0, 0, :, 0] +
                                   depthwise_weights[1, 0, :, 0] +
                                   depthwise_weights[2, 0, :, 0]))
        op4 = diff_padding[:, :, -1, :].assign(
            outputs[:, :, -1, :] * (depthwise_weights[0, -1, :, 0] +
                                    depthwise_weights[1, -1, :, 0] +
                                    depthwise_weights[2, -1, :, 0]))
        diff_padding1 = control_flow_ops.with_dependencies([op1, op2, op3, op4],
                                                           diff_padding)

        # Fix double addition in corners.
        op5 = diff_padding[:, 0, 0, :].assign(
            diff_padding1[:, 0, 0, :] - outputs[:, 0, 0, :] * depthwise_weights[0, 0, :, 0])
        op6 = diff_padding[:, -1, 0, :].assign(
            diff_padding1[:, -1, 0, :] - outputs[:, -1, 0, :] * depthwise_weights[-1, 0, :, 0])
        op7 = diff_padding[:, 0, -1, :].assign(
            diff_padding1[:, 0, -1, :] - outputs[:, 0, -1, :] * depthwise_weights[0, -1, :, 0])
        op8 = diff_padding[:, -1, -1, :].assign(
            diff_padding1[:, -1, -1, :] - outputs[:, -1, -1, :] * depthwise_weights[-1, -1, :, 0])
        diff_padding2 = control_flow_ops.with_dependencies([op5, op6, op7, op8],
                                                           diff_padding)

        # # Update padding!
        outputs = outputs + diff_padding2

        # Adding pointwise convolution.
        if num_outputs is not None:
            # Full separable convolution: Depthwise followed by pointwise convolution.
            pointwise_shape = [1, 1, depth_multiplier * num_filters_in, num_outputs]
            pointwise_weights = variables.model_variable(
                    'pointwise_weights',
                    shape=pointwise_shape,
                    dtype=dtype,
                    initializer=weights_initializer,
                    regularizer=weights_regularizer,
                    trainable=trainable,
                    collections=weights_collections)

            outputs = nn.conv2d(outputs, pointwise_weights,
                                strides=(1, 1, 1, 1), padding='SAME')

        else:
            # Depthwise convolution only.
            num_outputs = depth_multiplier * num_filters_in

        if normalizer_fn is not None:
            normalizer_params = normalizer_params or {}
            outputs = normalizer_fn(outputs, **normalizer_params)
        else:
            if biases_initializer is not None:
                biases_collections = utils.get_variable_collections(
                        variables_collections, 'biases')
                biases = variables.model_variable('biases',
                                                  shape=[num_outputs,],
                                                  dtype=dtype,
                                                  initializer=biases_initializer,
                                                  regularizer=biases_regularizer,
                                                  collections=biases_collections)
                outputs = nn.bias_add(outputs, biases)

        if activation_fn is not None:
            outputs = activation_fn(outputs)
        return utils.collect_named_outputs(outputs_collections,
                                           sc.original_name_scope, outputs)
Exemplo n.º 24
0
def depth_conv2d(inputs,
                 kernel_size,
                 stride=1,
                 channel_multiplier=1,
                 padding='SAME',
                 data_format=DATA_FORMAT_NHWC,
                 rate=1,
                 activation_fn=nn.relu,
                 normalizer_fn=None,
                 normalizer_params=None,
                 weights_initializer=initializers.xavier_initializer(),
                 weights_regularizer=None,
                 biases_initializer=init_ops.zeros_initializer(),
                 biases_regularizer=None,
                 reuse=None,
                 variables_collections=None,
                 outputs_collections=None,
                 trainable=True,
                 scope=None):

    if data_format not in (DATA_FORMAT_NCHW, DATA_FORMAT_NHWC):
        raise ValueError('data_format has to be either NCHW or NHWC.')
    layer_variable_getter = _build_variable_getter({
        'bias':
        'biases',
        'depthwise_kernel':
        'depthwise_weights'
    })

    with variable_scope.variable_scope(
            scope,
            'SeparableConv2d', [inputs],
            reuse=reuse,
            custom_getter=layer_variable_getter) as sc:
        inputs = ops.convert_to_tensor(inputs)

        df = ('channels_first' if data_format and data_format.startswith('NC')
              else 'channels_last')

        # Actually apply depthwise conv instead of separable conv.
        dtype = inputs.dtype.base_dtype
        kernel_h, kernel_w = utils.two_element_tuple(kernel_size)
        stride_h, stride_w = utils.two_element_tuple(stride)
        num_filters_in = utils.channel_dimension(inputs.get_shape(),
                                                 df,
                                                 min_rank=4)
        weights_collections = utils.get_variable_collections(
            variables_collections, 'weights')

        depthwise_shape = [
            kernel_h, kernel_w, num_filters_in, channel_multiplier
        ]
        depthwise_weights = variables.model_variable(
            'depthwise_weights',
            shape=depthwise_shape,
            dtype=dtype,
            initializer=weights_initializer,
            regularizer=weights_regularizer,
            trainable=trainable,
            collections=weights_collections)
        strides = [
            1, 1, stride_h, stride_w
        ] if data_format.startswith('NC') else [1, stride_h, stride_w, 1]

        outputs = nn.depthwise_conv2d(inputs,
                                      depthwise_weights,
                                      strides,
                                      padding,
                                      rate=utils.two_element_tuple(rate),
                                      data_format=data_format)
        num_outputs = num_filters_in

        if normalizer_fn is not None:
            normalizer_params = normalizer_params or {}
            outputs = normalizer_fn(outputs, **normalizer_params)
        else:
            if biases_initializer is not None:
                biases_collections = utils.get_variable_collections(
                    variables_collections, 'biases')
                biases = variables.model_variable(
                    'biases',
                    shape=[
                        num_outputs,
                    ],
                    dtype=dtype,
                    initializer=biases_initializer,
                    regularizer=biases_regularizer,
                    trainable=trainable,
                    collections=biases_collections)
                outputs = nn.bias_add(outputs, biases, data_format=data_format)

        if activation_fn is not None:
            outputs = activation_fn(outputs)
        return utils.collect_named_outputs(outputs_collections, sc.name,
                                           outputs)
Exemplo n.º 25
0
def separable_convolution2d(
        inputs,
        num_outputs,
        kernel_size,
        depth_multiplier,
        stride=1,
        padding='SAME',
        data_format=DATA_FORMAT_NHWC,
        rate=1,
        activation_fn=nn.relu,
        normalizer_fn=None,
        normalizer_params=None,
        weights_initializer=initializers.xavier_initializer(),
        weights_regularizer=None,
        biases_initializer=init_ops.zeros_initializer(),
        biases_regularizer=None,
        reuse=None,
        variables_collections=None,
        outputs_collections=None,
        trainable=True,
        scope=None,
        mask_type=None,
        mask_init_value=None,
        mask_bern_sample=None):
    """Adds a depth-separable 2D convolution with optional batch_norm layer.
  
    This op first performs a depthwise convolution that acts separately on
    channels, creating a variable called `depthwise_weights`. If `num_outputs`
    is not None, it adds a pointwise convolution that mixes channels, creating a
    variable called `pointwise_weights`. Then, if `normalizer_fn` is None,
    it adds bias to the result, creating a variable called 'biases', otherwise,
    the `normalizer_fn` is applied. It finally applies an activation function
    to produce the end result.
  
    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
        of the filters. Can be an int if both values are the same.
      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.
      padding: One of 'VALID' or 'SAME'.
      data_format: A string. `NHWC` (default) and `NCHW` are supported.
      rate: A list of length 2: [rate_height, rate_width], specifying the dilation
        rates for atrous convolution. Can be an int if both rates are the same.
        If any value is larger than one, then both stride values need to be one.
      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`. If
        `normalizer_fn` is provided then `biases_initializer` and
        `biases_regularizer` are ignored and `biases` are not created nor added.
        default set to None for no normalizer function
      normalizer_params: Normalization function parameters.
      weights_initializer: An initializer for the weights.
      weights_regularizer: Optional regularizer for the weights.
      biases_initializer: An initializer for the biases. If None skip biases.
      biases_regularizer: Optional regularizer for the biases.
      reuse: Whether or not the layer and its variables should be reused. To be
        able to reuse the layer scope must be given.
      variables_collections: Optional list of collections for all the variables or
        a dictionary containing a different list of collection per variable.
      outputs_collections: Collection to add the outputs.
      trainable: Whether or not the variables should be trainable or not.
      scope: Optional scope for variable_scope.
  
    Returns:
      A `Tensor` representing the output of the operation.
    Raises:
      ValueError: If `data_format` is invalid.
    """
    if data_format not in (DATA_FORMAT_NCHW, DATA_FORMAT_NHWC):
        raise ValueError('data_format has to be either NCHW or NHWC.')
    layer_variable_getter = _build_variable_getter({
        'bias':
        'biases',
        'depthwise_kernel':
        'depthwise_weights',
        'pointwise_kernel':
        'pointwise_weights'
    })

    gen_mask_kwargs = dict(mask_bern_sample=mask_bern_sample,
                           mask_type=mask_type,
                           mask_shape=None,
                           mask_init_value=mask_init_value,
                           dtype=inputs.dtype.base_dtype,
                           get_var_fn=None)

    with variable_scope.variable_scope(
            scope,
            'SeparableConv2d', [inputs],
            reuse=reuse,
            custom_getter=layer_variable_getter) as sc:
        inputs = ops.convert_to_tensor(inputs)

        df = ('channels_first' if data_format and data_format.startswith('NC')
              else 'channels_last')
        if num_outputs is not None:
            # Apply separable conv using the SeparableConvolution2D layer.
            layer = convolutional_layers.SeparableConvolution2D(
                filters=num_outputs,
                kernel_size=kernel_size,
                strides=stride,
                padding=padding,
                data_format=df,
                dilation_rate=utils.two_element_tuple(rate),
                activation=None,
                depth_multiplier=depth_multiplier,
                use_bias=not normalizer_fn and biases_initializer,
                depthwise_initializer=weights_initializer,
                pointwise_initializer=weights_initializer,
                bias_initializer=biases_initializer,
                depthwise_regularizer=weights_regularizer,
                pointwise_regularizer=weights_regularizer,
                bias_regularizer=biases_regularizer,
                activity_regularizer=None,
                trainable=trainable,
                name=sc.name,
                dtype=inputs.dtype.base_dtype,
                _scope=sc,
                _reuse=reuse)
            # Insert masks for pruning
            layer.build(inputs.get_shape())
            masked_depthwise_kernel, masked_bias = generate_masks(
                kernel=layer.depthwise_kernel,
                bias=layer.bias,
                **gen_mask_kwargs)
            masked_pointwise_kernel, _ = generate_masks(
                kernel=layer.pointwise_kernel, bias=None, **gen_mask_kwargs)
            layer.depthwise_kernel_copy = layer.depthwise_kernel
            layer.pointwise_kernel_copy = layer.pointwise_kernel
            layer.bias_copy = layer.bias
            layer.depthwise_kernel = masked_depthwise_kernel
            layer.pointwise_kernel = masked_pointwise_kernel
            layer.bias = masked_bias
            outputs = layer.apply(inputs)  # Compute
            layer.depthwise_kernel = layer.depthwise_kernel_copy
            layer.pointwise_kernel = layer.pointwise_kernel_copy
            layer.bias = layer.bias_copy

            # Add variables to collections.
            _add_variable_to_collections(layer.depthwise_kernel,
                                         variables_collections, 'weights')
            _add_variable_to_collections(layer.pointwise_kernel,
                                         variables_collections, 'weights')
            if layer.bias is not None:
                _add_variable_to_collections(layer.bias, variables_collections,
                                             'biases')

            if normalizer_fn is not None:
                normalizer_params = normalizer_params or {}
                outputs = normalizer_fn(outputs, **normalizer_params)
        else:
            # Actually apply depthwise conv instead of separable conv.
            dtype = inputs.dtype.base_dtype
            kernel_h, kernel_w = utils.two_element_tuple(kernel_size)
            stride_h, stride_w = utils.two_element_tuple(stride)
            num_filters_in = utils.channel_dimension(inputs.get_shape(),
                                                     df,
                                                     min_rank=4)
            weights_collections = utils.get_variable_collections(
                variables_collections, 'weights')

            depthwise_shape = [
                kernel_h, kernel_w, num_filters_in, depth_multiplier
            ]
            depthwise_weights = variables.model_variable(
                'depthwise_weights',
                shape=depthwise_shape,
                dtype=dtype,
                initializer=weights_initializer,
                regularizer=weights_regularizer,
                trainable=trainable,
                collections=weights_collections)
            masked_depthwise_weights, _ = generate_masks(
                kernel=depthwise_weights, bias=None, **gen_mask_kwargs)

            strides = [
                1, 1, stride_h, stride_w
            ] if data_format.startswith('NC') else [1, stride_h, stride_w, 1]

            outputs = nn.depthwise_conv2d(inputs,
                                          masked_depthwise_weights,
                                          strides,
                                          padding,
                                          rate=utils.two_element_tuple(rate),
                                          data_format=data_format)
            num_outputs = depth_multiplier * num_filters_in

            if normalizer_fn is not None:
                normalizer_params = normalizer_params or {}
                outputs = normalizer_fn(outputs, **normalizer_params)
            else:
                if biases_initializer is not None:
                    biases_collections = utils.get_variable_collections(
                        variables_collections, 'biases')
                    biases = variables.model_variable(
                        'biases',
                        shape=[
                            num_outputs,
                        ],
                        dtype=dtype,
                        initializer=biases_initializer,
                        regularizer=biases_regularizer,
                        trainable=trainable,
                        collections=biases_collections)
                    # TODO: bias is not masked currently
                    outputs = nn.bias_add(outputs,
                                          biases,
                                          data_format=data_format)

        if activation_fn is not None:
            outputs = activation_fn(outputs)
        return utils.collect_named_outputs(outputs_collections, sc.name,
                                           outputs)