tensorflow: TFLiteSavedModelConverterV2 breaks ordering of multi output models
System information
- OS Platform and Distribution (e.g., Linux Ubuntu 16.04): macOS
- TensorFlow installation (pip package or built from source): binary and source
- TensorFlow library (version, if pip package or github SHA, if built from source): 2.5.0-dev20210319, 5abe2b515db51d3aa35f6acf5869c1ce51a6b09c
Describe the current behavior
tf.lite.TFLiteConverter.from_saved_model
doesn’t support multi output models and outputs non-deterministic ordering which breaks users of the generated flatbuffers.
This is due to the fact that TFLite converter relies on the output ordering, but the saved model import function purposefully breaks this assumption by scrambling the inputs and outputs: https://github.com/tensorflow/tensorflow/blob/c36991b0367a12bc81bf37dfdc5cf4793c7a8bde/tensorflow/compiler/mlir/tensorflow/translate/import_model.cc#L3708-L3721
Describe the expected behavior
tf.lite.TFLiteConverter.from_saved_model
should behave the same way as tf.lite.TFLiteConverter.from_keras_model
and preserve the output ordering. This issue is especially problematic when relying on models using @tf.function(experimental_implements=True)
which are only supported by the saved model converter.
Standalone code to reproduce the issue
I opened PR #47928 which includes a failing test case (093f927aa9c217bfbecf7350c3c3f651964587af) that reproduces this issue when running the unittests with bazelisk test tensorflow/lite/python:lite_v2_test --test_output=all
.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 1
- Comments: 20 (17 by maintainers)
@abattery Thanks for re-opening the issue. I tried out using
SignatureDefs
with Keras models and discovered a few bugs and usability issues which can be reproduced in this colab notebook.The first problem is related to using full int8 quantization (/cc @MeghnaNatraj) by setting
This breaks the signature runner since the signature still refers to tensors that have been removed when converting to full int8 quantization.
The second problem is more a usability issue. Since the signature input and output names are set via Keras layer names, the signature of a Keras model depends on whether layers with the same name have already been instantiated prior to model saving which would lead to a change in leayer names. I think this is problematic since users will need to rely on fixed names in their TFLite code when relying on signature defs as far as I can tell. Otherwise this means during training great care needs to be taken that the model is saved in a fresh environment to not mess up the names (this can be very tricky during fine tuning where multiple instances of the same model might exist in the training code).
Let’s construct a model using dictionaries as inputs and outputs which would provide a unique mapping in multi-output models that does not rely on the ordering
Unfortunately the signature def would include layer names that might not be uniquely identifiable across model training runs.
Please take a look at this colab notebook for a fully reproducible code example.
For me, all of these issues would be solved by maintaining the input/output order of the Keras model during serialization and conversion to TFLite so that the order of
model.inputs
andmodel.outputs
(returns a list of tensors) are preserved during conversion. Alternatively, relying onSignatureDefs
would work very well too, if it supports full int8 conversion and if there exists an easy way to repeatedly name inputs and outputs during Keras model saving that does not depend on the automatic layer naming of Keras.For the multiple input/output naming/ordering issue, we recommend using TFLite signature def API.
SignatureDef provides meaningful/generic names for inputs/outputs which doesn’t rely on specific model details. More on SignatureDefs here. If your saved model has a defined signatureDef then it will be exported during conversion to TFLite and then you can use the Signature inputs/outputs for inference and not relying on inputs/outputs order or tensor names.
SignatureDef support is new thing available in nightly and will be available in 2.5
Then use the nightly for converting to tflite. The generated tflite file will have the SignatureDef details. Using Python API (as an example) you can do something like
I agree that using the signature def API makes a lot of sense when working with
tf.functions
and saved models directly.However, I think users only working with Keras models tend to expect that output ordering is preserved similar to how Python functions returning tuples work. So when converting models with
tf.lite.TFLiteConverter.from_keras_model
the fact that output ordering is not preserved is surprising since the fact that models get serialized as saved models during conversion is only an implementation detail that changed in TF 2.4. Is there a concrete reason for why preserving output ordering is not possible for Keras models? When saving and loading Keras models usingmodel.save
andtf.keras.models.load_model
the ordering is preserved as well, which is why I am confused that this is not possible when converting to TFLite.I am currently facing the same issue as lgeiger@
As shown in this comment above, once I train a keras model and specify input and output names, the input name stays as is but the output name is not preserved.
I am guessing the reason is because the outputs are
tf.Tensor
and not atf.keras.layer.Layer
type.To overcome this, I have added a
tf.keras.layer.Identity
to each of my outputs.eg: In the above scenario, that would translate to:
This ensures that the signature runner names are correct:
However, as TFLite models are usually operating under smaller resource constraints, adding another layer doesn’t seem like a good solution. Ideally, it would be better if the issue is fixed in TFLite (ensure signature names are the same as the name of the output tensor)
Thanks @lgeiger for finding a bug! I took a look at the above colab. It looks like the signature API can be broken after the model optimization is applied. Could you copy and paste the comment (https://github.com/tensorflow/tensorflow/issues/47927#issuecomment-804240854) to create a separate issue? I will take a look at this issue with the team.
Actually, you can override the output signature names by wrapping the keras model.
For example,
For the above cases, I would recommend exporting your keras model to the corresponding saved model with a signature def before putting it to the TensorFlow Lite converter API for now to avoid the multi output names/ordering issue.
Thank you for providing the valuable feedback. At least, there should be improvements in the document side.