def testSeparableConvQuantize_(self, kwargs):
        kwargs['filters'] = 2
        kwargs['kernel_size'] = 3
        num_samples = 2
        stack_size = 3
        num_row = 7
        num_col = 6

        sepconv_model = tf.keras.Sequential([
            tf.keras.Input(shape=(num_row, num_col, stack_size),
                           batch_size=num_samples),
            tf.keras.layers.SeparableConv2D(**kwargs)
        ])

        transformed_model, updated_metadata = ModelTransformer(
            sepconv_model,
            [default_8bit_transforms.SeparableConvQuantize()],
        ).transform()

        self.assertContainsSubset(updated_metadata.keys(),
                                  {'depthwise_conv2d', 'conv2d'})
        # Transformed model should have the same output shape
        self.assertEqual(sepconv_model.output_shape,
                         transformed_model.output_shape)

        x = np.random.rand(*sepconv_model.input_shape)
        y = np.random.rand(*sepconv_model.output_shape)

        # Ensure model is equivalent, and forward pass results are the same.
        self.assertAllClose(sepconv_model.predict(x),
                            transformed_model.predict(x))

        # Ensure model is equivalent, and training results are the same.
        sepconv_model.compile(loss='categorical_crossentropy', optimizer='sgd')
        transformed_model.compile(loss='categorical_crossentropy',
                                  optimizer='sgd')

        epochs = 100
        for _ in range(epochs):
            sepconv_model.fit(x, y, epochs=1, verbose=2)
            transformed_model.fit(x, y, epochs=1, verbose=2)
            self.assertAllClose(sepconv_model.get_weights(),
                                transformed_model.get_weights())
            # To prevent accumulated numerical errors.
            transformed_model.set_weights(sepconv_model.get_weights())
            self.assertAllClose(sepconv_model.predict(x),
                                transformed_model.predict(x))
    def testSeparableConvQuantize_(self, kwargs):
        kwargs['filters'] = 2
        kwargs['kernel_size'] = 3
        num_samples = 2
        stack_size = 3
        num_row = 7
        num_col = 6

        sepconv_model = tf.keras.Sequential([
            tf.keras.Input(shape=(num_row, num_col, stack_size),
                           batch_size=num_samples),
            tf.keras.layers.SeparableConv2D(**kwargs)
        ])

        transformed_model, updated_metadata = ModelTransformer(
            sepconv_model,
            [default_8bit_transforms.SeparableConvQuantize()],
        ).transform()

        self.assertContainsSubset(updated_metadata.keys(),
                                  {'depthwise_conv2d', 'conv2d'})
        # Transformed model should have the same output shape
        self.assertEqual(sepconv_model.output_shape,
                         transformed_model.output_shape)

        x = np.random.rand(*sepconv_model.input_shape)
        y = np.random.rand(*sepconv_model.output_shape)

        # Ensure model is equivalent, and forward pass results are the same.
        self.assertAllClose(sepconv_model.predict(x),
                            transformed_model.predict(x))

        # Ensure model is equivalent, and training results are the same.
        sepconv_model.compile(loss='categorical_crossentropy', optimizer='sgd')
        sepconv_model.fit(x, y, epochs=100)
        transformed_model.compile(loss='categorical_crossentropy',
                                  optimizer='sgd')
        transformed_model.fit(x, y, epochs=100)

        # Over a long training cycle with constraints and regularizers, the model
        # can build very minute differences. Hence reducing tol to 1e-5.
        self.assertAllClose(sepconv_model.predict(x),
                            transformed_model.predict(x),
                            atol=1e-5,
                            rtol=1e-5)
Пример #3
0
    def apply(self, model, layer_quantize_map):
        """Implement default 8-bit transforms.

    Currently this means the following.
      1. Pull activations into layers, and apply fuse activations. (TODO)
      2. Modify range in incoming layers for Concat. (TODO)
      3. Fuse Conv2D/DepthwiseConv2D + BN into single layer.

    Args:
      model: Keras model to be quantized.
      layer_quantize_map: Map with keys as layer names, and values as dicts
        containing custom `QuantizeConfig`s which may have been passed with
        layers.

    Returns:
      (Transformed Keras model to better match TensorFlow Lite backend, updated
      layer quantize map.)
    """

        transforms = [
            default_8bit_transforms.InputLayerQuantize(),
            default_8bit_transforms.SeparableConv1DQuantize(),
            default_8bit_transforms.SeparableConvQuantize(),
            default_8bit_transforms.Conv2DReshapeBatchNormReLUQuantize(),
            default_8bit_transforms.Conv2DReshapeBatchNormActivationQuantize(),
            default_8bit_transforms.Conv2DBatchNormReLUQuantize(),
            default_8bit_transforms.Conv2DBatchNormActivationQuantize(),
            default_8bit_transforms.Conv2DReshapeBatchNormQuantize(),
            default_8bit_transforms.Conv2DBatchNormQuantize(),
            default_8bit_transforms.ConcatTransform6Inputs(),
            default_8bit_transforms.ConcatTransform5Inputs(),
            default_8bit_transforms.ConcatTransform4Inputs(),
            default_8bit_transforms.ConcatTransform3Inputs(),
            default_8bit_transforms.ConcatTransform(),
            default_8bit_transforms.AddReLUQuantize(),
            default_8bit_transforms.AddActivationQuantize(),
            OptFlowQuantize(),
            FlowQuantize()
        ]
        return model_transformer.ModelTransformer(
            model, transforms, set(layer_quantize_map.keys()),
            layer_quantize_map).transform()