Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TFLite failures resulted from TF latest version upgrade resolved #6774

Merged
merged 2 commits into from
Oct 29, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docker/install/ubuntu_install_tflite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,22 @@ pip3 install flatbuffers
# Build the TFLite static library, necessary for building with TFLite ON.
# The library is built at:
# tensorflow/tensorflow/lite/tools/make/gen/*/lib/libtensorflow-lite.a.
git clone https://github.com/tensorflow/tensorflow --branch=r2.1
git clone https://github.com/tensorflow/tensorflow --branch=r2.3
./tensorflow/tensorflow/lite/tools/make/download_dependencies.sh
./tensorflow/tensorflow/lite/tools/make/build_lib.sh

# Setup tflite from schema
mkdir tflite
cd tflite
wget -q https://raw.githubusercontent.com/tensorflow/tensorflow/r2.1/tensorflow/lite/schema/schema.fbs
wget -q https://raw.githubusercontent.com/tensorflow/tensorflow/r2.3/tensorflow/lite/schema/schema.fbs
flatc --python schema.fbs

cat <<EOM >setup.py
import setuptools

setuptools.setup(
name="tflite",
version="2.1.0",
version="2.3.1",
author="google",
author_email="google@google.com",
description="TFLite",
Expand Down
15 changes: 14 additions & 1 deletion python/tvm/relay/frontend/tflite.py
Original file line number Diff line number Diff line change
Expand Up @@ -2770,7 +2770,7 @@ def convert_transpose_conv(self, op):
raise ImportError("The tflite package must be installed")

input_tensors = self.get_input_tensors(op)
assert len(input_tensors) == 3, "input tensors length should be 3"
assert len(input_tensors) >= 3, "input tensors length should be >= 3"

# Input (data) Tensor. NHWC layout
input_tensor = input_tensors[2]
Expand Down Expand Up @@ -2843,6 +2843,19 @@ def convert_transpose_conv(self, op):
out_dtype=output_tensor_type_str,
)

# if we have bias
if len(input_tensors) == 4:
bias_tensor = input_tensors[3]
bias_tensor_type = bias_tensor.tensor.Type()
# bias tensor type should be INT32 (quantization) or FLOAT32
assert bias_tensor_type in (TensorType.INT32, TensorType.FLOAT32)
bias_tensor_type_str = self.get_tensor_type_str(bias_tensor_type)
bias_expr = self.exp_tab.new_const(
self.get_tensor_value(bias_tensor), dtype=bias_tensor_type_str
)
channel_axis = 3
out = _op.nn.bias_add(out, bias_expr, axis=channel_axis)

return out

def convert_quantize(self, op):
Expand Down
115 changes: 60 additions & 55 deletions tests/python/frontend/tflite/test_forward.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,20 @@ def vmobj_to_list(o):
raise RuntimeError("Unknown object type: %s" % type(o))


def _quantize_keras_model(keras_model, representative_data_gen):
def _quantize_keras_model(
keras_model, representative_data_gen, is_float_input=False, is_float_output=False
):
"""Utility function to quantize a Keras model using TFLite converter."""
converter = interpreter_wrapper.TFLiteConverter.from_keras_model(keras_model)
converter.optimizations = [tf.lite.Optimize.OPTIMIZE_FOR_SIZE]
converter.representative_dataset = representative_data_gen
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8
# NOTE: If representative dataset is provided, and inference input type is not set,
# then converter will self add quant & dequant Op accordingly.
if not is_float_input:
converter.inference_input_type = tf.uint8
if not is_float_output:
converter.inference_output_type = tf.uint8
return converter.convert()


Expand Down Expand Up @@ -973,6 +979,7 @@ def _test_convolution(
[out],
quantized=quantized,
input_range=input_range,
experimental_new_converter=True,
)
else:
# Quantized the inputs and feed them to the convolution
Expand Down Expand Up @@ -1000,6 +1007,7 @@ def _test_convolution(
[out],
quantized=quantized,
input_range=input_range,
experimental_new_converter=True,
)
else:
data_array = np.reshape(data_array, tensor_in_sizes).astype("float32")
Expand Down Expand Up @@ -1078,18 +1086,18 @@ def test_forward_convolution():
)

# TFLite2 quantized convolution testing
if package_version.parse(tf.VERSION) >= package_version.parse("2.1.0"):
_test_tflite2_quantized_convolution(
[1, 8, 8, 176], [1, 1, 176, 32], [1, 1], [1, 1], "SAME", "NHWC"
if package_version.parse(tf.VERSION) >= package_version.parse("2.3.0"):
_test_convolution(
[1, 8, 8, 176], [1, 1, 176, 32], [1, 1], [1, 1], "SAME", "NHWC", quantized=True
)
_test_tflite2_quantized_convolution(
[1, 17, 17, 12], [3, 3, 12, 32], [1, 1], [2, 2], "VALID", "NHWC"
_test_convolution(
[1, 17, 17, 12], [3, 3, 12, 32], [1, 1], [2, 2], "VALID", "NHWC", quantized=True
)
_test_tflite2_quantized_convolution(
[1, 17, 17, 19], [3, 3, 19, 19], [1, 1], [2, 2], "VALID", "NHWC"
_test_convolution(
[1, 17, 17, 19], [3, 3, 19, 19], [1, 1], [2, 2], "VALID", "NHWC", quantized=True
)
_test_tflite2_quantized_convolution(
[1, 17, 17, 124], [1, 1, 124, 19], [1, 1], [1, 1], "SAME", "NHWC"
_test_convolution(
[1, 17, 17, 124], [1, 1, 124, 19], [1, 1], [1, 1], "SAME", "NHWC", quantized=True
)

# Disable as tests are flaky - https://github.com/apache/incubator-tvm/issues/6064
Expand Down Expand Up @@ -2280,7 +2288,7 @@ def representative_data_gen():
for i in range(1):
yield [data]

tflite_model_quant = _quantize_keras_model(keras_model, representative_data_gen)
tflite_model_quant = _quantize_keras_model(keras_model, representative_data_gen, True, True)

tflite_output = run_tflite_graph(tflite_model_quant, data)
tvm_output = run_tvm_graph(tflite_model_quant, data, input_name)
Expand All @@ -2307,7 +2315,7 @@ def representative_data_gen():
for i in range(1):
yield [data]

tflite_model_quant = _quantize_keras_model(keras_model, representative_data_gen)
tflite_model_quant = _quantize_keras_model(keras_model, representative_data_gen, True, True)

tflite_output = run_tflite_graph(tflite_model_quant, data)
tvm_output = run_tvm_graph(tflite_model_quant, data, input_name)
Expand Down Expand Up @@ -2548,14 +2556,17 @@ def test_forward_padv2():
np.array([2], dtype=np.float32),
]
)
_test_padv2(
[
np.arange(0, 256, dtype=np.uint8).reshape((1, 256)),
np.array([[1, 1], [2, 2]], dtype=np.int32),
np.array([2], dtype=np.uint8),
],
quantized=True,
)
# NOTE: In recent version, there is a bug in Tensorflow package for this scenario.
# Hence, it is disabled temporarily for latest TF version.
ANSHUMAN87 marked this conversation as resolved.
Show resolved Hide resolved
if package_version.parse(tf.VERSION) <= package_version.parse("2.1.0"):
_test_padv2(
[
np.arange(0, 256, dtype=np.uint8).reshape((1, 256)),
np.array([[1, 1], [2, 2]], dtype=np.int32),
np.array([2], dtype=np.float32),
],
quantized=True,
)

# Constant Values input can be scalar
_test_padv2(
Expand All @@ -2565,14 +2576,17 @@ def test_forward_padv2():
np.float32(2),
]
)
_test_padv2(
[
np.arange(0, 256, dtype=np.uint8).reshape((1, 256)),
np.array([[1, 1], [2, 2]], dtype=np.int32),
np.uint8(10),
],
quantized=True,
)
# NOTE: In recent version, there is a bug in Tensorflow package for this scenario.
# Hence, it is disabled temporarily for latest TF version.
ANSHUMAN87 marked this conversation as resolved.
Show resolved Hide resolved
if package_version.parse(tf.VERSION) <= package_version.parse("2.1.0"):
_test_padv2(
[
np.arange(0, 256, dtype=np.uint8).reshape((1, 256)),
np.array([[1, 1], [2, 2]], dtype=np.int32),
np.uint8(10),
],
quantized=True,
)


#######################################################################
Expand Down Expand Up @@ -2870,37 +2884,28 @@ def test_forward_tanh():
def _test_relu(data, quantized=False):
""" One iteration of ReLU """

if quantized:
if package_version.parse(tf.VERSION) < package_version.parse("2.1.0"):
pytest.skip("Testcase requires tflite version >= 2.1.0")
data_in = tf.keras.layers.Input(shape=data.shape[1:])
relu = tf.keras.layers.ReLU()(data_in)
keras_model = tf.keras.models.Model(inputs=data_in, outputs=relu)
input_name = data_in.name.split(":")[0]

# To create quantized values with dynamic range of activations, needs representative dataset
def representative_data_gen():
for i in range(1):
yield [data]

tflite_model_quant = _quantize_keras_model(keras_model, representative_data_gen)

tflite_output = run_tflite_graph(tflite_model_quant, data)
tvm_output = run_tvm_graph(tflite_model_quant, data, input_name)
tvm.testing.assert_allclose(
np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-5
)
else:
with tf.Graph().as_default():
in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype)
with tf.Graph().as_default():
in_data = array_ops.placeholder(shape=data.shape, dtype="float32", name="in_0")

if quantized:
inq_data = tf.quantization.fake_quant_with_min_max_args(
in_data, min=-10, max=10, name="inq_0"
)
input_range = {"inq_0": (-10, 10)}
out = nn_ops.relu(inq_data)
out = tf.quantization.fake_quant_with_min_max_args(out, min=0, max=6, name="out")
compare_tflite_with_tvm(
data, "inq_0:0", [inq_data], [out], quantized=True, input_range=input_range
)
else:
Comment on lines -2873 to +2900
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you give a hint as to the reason for these changes ? is there any reason why the existing mechanism doesn't work in your research ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, generally, we want to move towards keras quantization as TF gets more mature. What issues do you see?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue here was the test case was not behaving as expected. When we need a quantized graph with quantized inference, then we should provide quant input(Uint8 or int8, based on settings chosen). But here it was feeding float input to the graph, so the failure. Also i think current change is to keep a uniform steps as followed similar to case of other operators. Any specific reason to move towards Keras quantization than TF quant ?

Please let me know, if still need to keep Keras quant. Thanks!

out = nn_ops.relu(in_data)
compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out])
compare_tflite_with_tvm(data, "in_0:0", [in_data], [out])


def test_forward_relu():
""" ReLU """
_test_relu(np.arange(6.0, dtype=np.float32).reshape((1, 6)))
_test_relu(np.arange(6.0, dtype=np.float32).reshape((1, 6)), quantized=True)
_test_relu(np.random.uniform(0, 255, (3, 6)).astype(np.uint8), quantized=True)


#######################################################################
Expand Down