Пример #1
0
    def replacement(self, match_layer):
        relu_layer_node = match_layer
        add_layer_node = relu_layer_node.input_layers[0]

        add_layer_node.metadata['quantize_config'] = (
            default_8bit_quantize_configs.NoOpQuantizeConfig())

        return match_layer
Пример #2
0
  def _replace(self, relu_layer_node, bn_layer_node, conv_layer_node):
    if _has_custom_quantize_config(
        relu_layer_node, bn_layer_node, conv_layer_node):
      return relu_layer_node

    conv_layer_node.layer['config']['activation'] = \
      keras.activations.serialize(quantize_aware_activation.NoOpActivation())
    bn_layer_node.metadata['quantize_config'] = \
      default_8bit_quantize_configs.NoOpQuantizeConfig()

    return relu_layer_node
Пример #3
0
    def replacement(self, match_layer):
        relu_layer_node = match_layer
        bn_layer_node = relu_layer_node.input_layers[0]
        conv_layer_node = bn_layer_node.input_layers[0]

        if self._has_custom_quantize_config(relu_layer_node, bn_layer_node,
                                            conv_layer_node):
            return match_layer

        conv_layer_node.layer['config']['activation'] = \
          keras.activations.serialize(quantize_aware_activation.NoOpActivation())
        bn_layer_node.metadata['quantize_config'] = \
          default_8bit_quantize_configs.NoOpQuantizeConfig()

        return match_layer
Пример #4
0
    def replacement(self, match_layer):
        concat_layer_node = match_layer
        feeding_layer_nodes = match_layer.input_layers

        default_registry = (
            default_8bit_quantize_registry.Default8BitQuantizeRegistry())

        feed_quantize_configs = []
        for feed_layer_node in feeding_layer_nodes:
            quantize_config = feed_layer_node.metadata.get('quantize_config')
            if not quantize_config:
                layer_class = self._get_layer_type(
                    feed_layer_node.layer['class_name'])
                if layer_class is None:
                    # Concat has an input layer we don't recognize. Return.
                    return match_layer

                if layer_class == keras.layers.Concatenate:
                    # Input layer to Concat is also Concat. Don't quantize it.
                    feed_layer_node.metadata['quantize_config'] = (
                        default_8bit_quantize_configs.NoOpQuantizeConfig())
                    continue

                if not default_registry._is_supported_layer(layer_class):
                    # Feeding layer is not supported by registry
                    return match_layer

                quantize_config = default_registry._get_quantize_config(
                    layer_class)
                feed_layer_node.metadata['quantize_config'] = quantize_config

            feed_quantize_configs.append(quantize_config)

        # TODO(pulkitb): this currently only disables output quantize config, but
        # cannot properly handle if the FQ was added to the activation. Hand this
        # properly.
        for quantize_config in feed_quantize_configs:
            self._disable_output_quantize(quantize_config)

        if not concat_layer_node.metadata.get('quantize_config'):
            concat_layer_node.metadata['quantize_config'] = (
                default_8bit_quantize_configs.Default8BitOutputQuantizeConfig(
                ))

        return concat_layer_node
Пример #5
0
    def __init__(self, label_count, apply_quantization, **kwargs):
        super(ConvModel, self).__init__(**kwargs)

        # create layers
        self.input_quant = quantize_layer.QuantizeLayer(
            AllValuesQuantizer(num_bits=8,
                               per_axis=False,
                               symmetric=False,
                               narrow_range=False))

        self.conv1 = quantize.quantize_layer(
            tf.keras.layers.Conv2D(filters=2,
                                   kernel_size=[1, 3],
                                   padding='SAME'))
        self.bn1 = quantize.quantize_layer(
            tf.keras.layers.BatchNormalization())
        self.relu1 = quantize.quantize_layer(tf.keras.layers.ReLU())

        self.conv2 = ring_buffer.RingBuffer(
            quantize.quantize_layer(
                tf.keras.layers.Conv2D(filters=2,
                                       kernel_size=(3, 1),
                                       dilation_rate=1,
                                       strides=2,
                                       use_bias=False), apply_quantization,
                quantize.NoOpActivationConfig(['kernel'], ['activation'],
                                              False)),
            use_one_step=False,
            inference_batch_size=self.inference_batch_size,
            pad_time_dim='causal')
        self.bn2 = quantize.quantize_layer(
            tf.keras.layers.BatchNormalization(),
            default_8bit_quantize_configs.NoOpQuantizeConfig())
        self.relu2 = quantize.quantize_layer(tf.keras.layers.ReLU())

        self.flatten = ring_buffer.RingBuffer(
            quantize.quantize_layer(tf.keras.layers.Flatten(),
                                    apply_quantization),
            use_one_step=True,
            inference_batch_size=self.inference_batch_size)

        self.dense = quantize.quantize_layer(
            tf.keras.layers.Dense(label_count,
                                  activation='softmax',
                                  use_bias=False), apply_quantization)
Пример #6
0
    def replacement(self, match_layer):
        if _has_custom_quantize_config(match_layer):
            return match_layer

        sepconv1d_layer = match_layer.layer
        sepconv1d_config = sepconv1d_layer['config']
        sepconv1d_weights = list(match_layer.weights.values())

        padding = sepconv1d_config['padding']
        # SepConv2D does not accept causal padding, and SepConv1D has some special
        # handling for it.
        # TODO(pulkitb): Add support for causal padding.
        if padding == 'causal':
            raise ValueError(
                'SeparableConv1D with causal padding is not supported.')

        # TODO(pulkitb): Handle other base_layer args such as dtype, input_dim etc.

        sepconv2d_layer = tf.keras.layers.SeparableConv2D(
            filters=sepconv1d_config['filters'],
            kernel_size=(1, ) +
            _normalize_tuple(sepconv1d_config['kernel_size']),
            strides=_normalize_tuple(sepconv1d_config['strides']) * 2,
            padding=padding,
            data_format=sepconv1d_config['data_format'],
            dilation_rate=(1, ) +
            _normalize_tuple(sepconv1d_config['dilation_rate']),
            depth_multiplier=sepconv1d_config['depth_multiplier'],
            activation=sepconv1d_config['activation'],
            use_bias=sepconv1d_config['use_bias'],
            depthwise_initializer=sepconv1d_config['depthwise_initializer'],
            pointwise_initializer=sepconv1d_config['pointwise_initializer'],
            bias_initializer=sepconv1d_config['bias_initializer'],
            depthwise_regularizer=sepconv1d_config['depthwise_regularizer'],
            pointwise_regularizer=sepconv1d_config['pointwise_regularizer'],
            bias_regularizer=sepconv1d_config['bias_regularizer'],
            activity_regularizer=sepconv1d_config['activity_regularizer'],
            depthwise_constraint=sepconv1d_config['depthwise_constraint'],
            pointwise_constraint=sepconv1d_config['pointwise_constraint'],
            bias_constraint=sepconv1d_config['bias_constraint'],
            # TODO(pulkitb): Rethink what to do for name. Using the same name leads
            # to confusion, since it's typically separable_conv1d
            name=sepconv1d_config['name'] + '_QAT_SepConv2D',
            trainable=sepconv1d_config['trainable'])

        sepconv2d_weights = collections.OrderedDict()
        sepconv2d_weights['depthwise_kernel:0'] = np.expand_dims(
            sepconv1d_weights[0], 0)
        sepconv2d_weights['pointwise_kernel:0'] = np.expand_dims(
            sepconv1d_weights[1], 0)
        if sepconv1d_config['use_bias']:
            sepconv2d_weights['bias:0'] = sepconv1d_weights[2]

        if sepconv1d_config['data_format'] == 'channels_last':
            spatial_dim = 1
        else:
            spatial_dim = 2

        sepconv2d_layer_config = keras.layers.serialize(sepconv2d_layer)
        sepconv2d_layer_config['name'] = sepconv2d_layer.name

        # Needed to ensure these new layers are considered for quantization.
        sepconv2d_metadata = {'quantize_config': None}

        # TODO(pulkitb): Consider moving from Lambda to custom ExpandDims/Squeeze.

        # Layer before SeparableConv2D which expands input tensors to match 2D.
        expand_layer = tf.keras.layers.Lambda(
            lambda x: tf.expand_dims(x, spatial_dim),
            name=self._get_name('sepconv1d_expand'))
        expand_layer_config = keras.layers.serialize(expand_layer)
        expand_layer_config['name'] = expand_layer.name
        expand_layer_metadata = {
            'quantize_config':
            default_8bit_quantize_configs.NoOpQuantizeConfig()
        }

        squeeze_layer = tf.keras.layers.Lambda(
            lambda x: tf.squeeze(x, [spatial_dim]),
            name=self._get_name('sepconv1d_squeeze'))
        squeeze_layer_config = keras.layers.serialize(squeeze_layer)
        squeeze_layer_config['name'] = squeeze_layer.name
        squeeze_layer_metadata = {
            'quantize_config':
            default_8bit_quantize_configs.NoOpQuantizeConfig()
        }

        return LayerNode(squeeze_layer_config,
                         metadata=squeeze_layer_metadata,
                         input_layers=[
                             LayerNode(sepconv2d_layer_config,
                                       weights=sepconv2d_weights,
                                       metadata=sepconv2d_metadata,
                                       input_layers=[
                                           LayerNode(
                                               expand_layer_config,
                                               metadata=expand_layer_metadata)
                                       ])
                         ])
Пример #7
0
def model(flags):
    """CNN model.

  It is based on paper:
  Convolutional Neural Networks for Small-footprint Keyword Spotting
  http://www.isca-speech.org/archive/interspeech_2015/papers/i15_1478.pdf
  Model topology is similar with "Hello Edge: Keyword Spotting on
  Microcontrollers" https://arxiv.org/pdf/1711.07128.pdf

  Args:
    flags: data/model parameters

  Returns:
    Keras model for training
  """

    input_audio = tf.keras.layers.Input(shape=modes.get_input_data_shape(
        flags, modes.Modes.TRAINING),
                                        batch_size=flags.batch_size)
    net = input_audio

    if flags.preprocess == 'raw':
        # it is a self contained model, user need to feed raw audio only
        net = speech_features.SpeechFeatures(
            speech_features.SpeechFeatures.get_params(flags))(net)

    if flags.quantize:
        net = quantize_layer.QuantizeLayer(
            AllValuesQuantizer(num_bits=8,
                               per_axis=False,
                               symmetric=False,
                               narrow_range=False))(net)

    net = tf.keras.backend.expand_dims(net)
    for filters, kernel_size, activation, dilation_rate, strides in zip(
            utils.parse(flags.cnn_filters), utils.parse(flags.cnn_kernel_size),
            utils.parse(flags.cnn_act), utils.parse(flags.cnn_dilation_rate),
            utils.parse(flags.cnn_strides)):
        net = stream.Stream(cell=quantize.quantize_layer(
            tf.keras.layers.Conv2D(filters=filters,
                                   kernel_size=kernel_size,
                                   dilation_rate=dilation_rate,
                                   activation='linear',
                                   strides=strides), flags.quantize,
            quantize.NoOpActivationConfig(['kernel'], ['activation'], False)),
                            pad_time_dim='causal',
                            use_one_step=False)(net)
        net = quantize.quantize_layer(
            tf.keras.layers.BatchNormalization(),
            default_8bit_quantize_configs.NoOpQuantizeConfig())(net)
        net = quantize.quantize_layer(
            tf.keras.layers.Activation(activation))(net)

    net = stream.Stream(cell=quantize.quantize_layer(
        tf.keras.layers.Flatten(), apply_quantization=flags.quantize))(net)

    net = tf.keras.layers.Dropout(rate=flags.dropout1)(net)

    for units, activation in zip(utils.parse(flags.units2),
                                 utils.parse(flags.act2)):
        net = quantize.quantize_layer(tf.keras.layers.Dense(
            units=units, activation=activation),
                                      apply_quantization=flags.quantize)(net)

    net = quantize.quantize_layer(
        tf.keras.layers.Dense(units=flags.label_count),
        apply_quantization=flags.quantize)(net)
    if flags.return_softmax:
        net = quantize.quantize_layer(tf.keras.layers.Activation('softmax'),
                                      apply_quantization=flags.quantize)(net)
    return tf.keras.Model(input_audio, net)