Skip to content

Add guide for exporting Keras models to LiteRT#2260

Open
pctablet505 wants to merge 2 commits intokeras-team:masterfrom
pctablet505:master
Open

Add guide for exporting Keras models to LiteRT#2260
pctablet505 wants to merge 2 commits intokeras-team:masterfrom
pctablet505:master

Conversation

@pctablet505
Copy link

This pull request introduces a new guide to the guides list and updates the Keras project version reference in the autogen.py script. The main changes are as follows:

Guides update:

  • Added a new guide entry with the path litert_export and the title "Exporting Keras models to LiteRT" to the guides configuration in guides_master.py.

Version reference update:

  • Changed the Keras project URL in the PROJECT_URL dictionary in autogen.py to reference version v3.13.0 instead of v3.13.1.Introduces comprehensive documentation and code examples for exporting Keras models to TensorFlow Lite (LiteRT) format. Includes guides in Jupyter notebook, Python script, and Markdown formats, covering basic export, different model architectures, quantization, dynamic shapes, custom signatures, model validation, and advanced export options. Updates autogen scripts to support the new guide.

Introduces comprehensive documentation and code examples for exporting Keras models to TensorFlow Lite (LiteRT) format. Includes guides in Jupyter notebook, Python script, and Markdown formats, covering basic export, different model architectures, quantization, dynamic shapes, custom signatures, model validation, and advanced export options. Updates autogen scripts to support the new guide.
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @pctablet505, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the documentation by introducing a detailed guide on exporting Keras models to TensorFlow Lite (LiteRT) format. This new resource provides developers with essential information and practical examples for deploying Keras models efficiently on mobile and edge devices, covering various model types, optimization strategies like quantization, and advanced configuration options. Additionally, it includes a minor update to a Keras project version reference in the autogeneration scripts.

Highlights

  • New Guide for Keras to LiteRT Export: A comprehensive guide titled "Exporting Keras models to LiteRT (TensorFlow Lite)" has been added, providing detailed instructions and examples for deploying Keras models on mobile and edge devices.
  • Diverse Model Architecture Support: The new guide demonstrates how to export various Keras model architectures, including Sequential, Functional API, Subclassed models, and models from KerasHub, to the LiteRT format.
  • Quantization Techniques: Detailed explanations and code examples are provided for different quantization strategies (basic, Float16, and dynamic range quantization) to optimize model size and inference speed for edge deployment.
  • Dynamic Shapes and Custom Signatures: The guide covers advanced topics such as handling dynamic input shapes for flexible model inference and defining custom input signatures for models with complex input/output requirements.
  • Model Validation and Advanced Options: It includes a section on validating exported LiteRT models against their Keras counterparts and explores advanced export options for fine-tuning the conversion process.
  • Keras Version Reference Update: The Keras project version reference in the scripts/autogen.py file has been updated from v3.13.1 to v3.13.0.
  • Guide Index Update: An entry for the new LiteRT export guide has been added to the scripts/guides_master.py file, making it discoverable within the documentation.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a comprehensive guide for exporting Keras models to LiteRT, covering various model types, quantization, dynamic shapes, and validation. The guide is well-structured and provides clear examples. The autogen.py and guides_master.py updates correctly integrate the new guide and adjust the Keras project version reference.

Comment on lines +88 to +111
try:
from ai_edge_litert.interpreter import Interpreter

print("Using ai_edge_litert for inference")
litert_available = True
except ImportError:
try:
from tensorflow.lite import Interpreter

print("Using tensorflow.lite for inference")
litert_available = True
except ImportError:
try:
import tensorflow as tf

Interpreter = tf.lite.Interpreter

print("Using tf.lite.Interpreter for inference")
litert_available = True
except (ImportError, AttributeError):
print("LiteRT interpreter not available. Skipping inference test.")
print(
"To test inference, install ai_edge_litert: pip install ai-edge-litert"
)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The logic for importing the LiteRT interpreter is repeated here and in the validate_tflite_model function. Encapsulating this logic into a helper function would improve code readability and maintainability, adhering to the DRY (Don't Repeat Yourself) principle. This also makes it easier to update the import strategy in the future if needed.

def _get_litert_interpreter_and_status():
    """Attempts to import a LiteRT interpreter and returns its status."""
    litert_available = False
    Interpreter_class = None
    try:
        from ai_edge_litert.interpreter import Interpreter as Interpreter_class
        print("Using ai_edge_litert for inference")
        litert_available = True
    except ImportError:
        try:
            from tensorflow.lite import Interpreter as Interpreter_class
            print("Using tensorflow.lite for inference")
            litert_available = True
        except ImportError:
            try:
                import tensorflow as tf
                Interpreter_class = tf.lite.Interpreter
                print("Using tf.lite.Interpreter for inference")
                litert_available = True
            except (ImportError, AttributeError):
                print("LiteRT interpreter not available. Skipping inference test.")
                print("To test inference, install ai_edge_litert: pip install ai-edge-litert")
    return Interpreter_class, litert_available

Interpreter, litert_available = _get_litert_interpreter_and_status()

Copy link
Collaborator

@divyashreepathihalli divyashreepathihalli left a comment

Choose a reason for hiding this comment

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

Thank you for the PR! Left some comments!

"""
## Introduction

TensorFlow Lite (LiteRT) is TensorFlow's solution for running machine learning models
Copy link
Collaborator

Choose a reason for hiding this comment

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

This may make it sound like it is a tensorflow solution.
Maybe reword it to - "LiteRT is a solution for running machine learning models..."


# Generate dummy data for demonstration
X_train = np.random.random((1000, 28, 28))
y_train = np.random.randint(0, 10, 1000)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Keep the names consistent
X_train> x_train


# Load and test the exported model
litert_available = False
try:
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a demo colab - you should assume the environment will support the interpreter instead of this nested try except blocks. please remove.

output = interpreter.get_tensor(output_details[0]["index"])

print(f"\nInference successful! Output shape: {output.shape}")
else:
Copy link
Collaborator

Choose a reason for hiding this comment

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

remove the if else block
and let the block throw an error

"""

keras_hub_available = False
try:
Copy link
Collaborator

Choose a reason for hiding this comment

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

remove the try except blocks!

Please add relevant install instructions in the beginning of the Colab - for what is needed to run this guide.

print("keras-hub not available. Skipping Keras-Hub example.")
print("To run this example, install keras-hub: pip install keras-hub")

if keras_hub_available:
Copy link
Collaborator

Choose a reason for hiding this comment

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

remove the if and try blocks - if there is an error let it throw the error

vision_model.export("resnet.tflite", format="litert")

print("Exported Keras-Hub vision model")
except Exception as e:
Copy link
Collaborator

Choose a reason for hiding this comment

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

remove the try and except!

- **Memory issues**: Reduce model size with quantization
- **Accuracy drops**: Start with float16 instead of full int8 quantization

## Next Steps
Copy link
Collaborator

Choose a reason for hiding this comment

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

are these next steps guide available? - if not - lets remove

@pctablet505
Copy link
Author

@gemini-code-assist review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a comprehensive guide on exporting Keras models to LiteRT (TensorFlow Lite) format. The guide is provided in Jupyter Notebook, Python script, and Markdown formats. The changes also include adding the new guide to the site's master list and updating a Keras version reference in an autogeneration script.

My review focuses on improving the code examples in the new guide to follow Keras best practices, such as using keras.Input for defining model input shapes. I've also suggested a minor improvement for character encoding to ensure cross-platform compatibility. The changes to the build scripts look good.

"# Create a simple MNIST classifier\n",
"model = keras.Sequential(\n",
" [\n",
" keras.layers.Flatten(input_shape=(28, 28)),\n",
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

While using input_shape in the first layer works, the recommended best practice for Sequential models is to use a keras.Input object as the first layer. This makes the model's inputs and their shapes more explicit.

Here's how you could refactor the model definition:

model = keras.Sequential(
    [
        keras.Input(shape=(28, 28)),
        keras.layers.Flatten(),
        keras.layers.Dense(128, activation="relu"),
        keras.layers.Dropout(0.2),
        keras.layers.Dense(10, activation="softmax"),
    ]
)

"# Create a model for quantization\n",
"quantization_model = keras.Sequential(\n",
" [\n",
" keras.layers.Dense(64, activation=\"relu\", input_shape=(784,)),\n",
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For clarity and consistency with best practices, it's better to define the input shape of a Sequential model using a keras.Input layer instead of the input_shape argument in the first layer.

Here's how you could refactor it:

quantization_model = keras.Sequential(
    [
        keras.Input(shape=(784,)),
        keras.layers.Dense(64, activation="relu"),
        keras.layers.Dense(32, activation="relu"),
        keras.layers.Dense(10, activation="softmax"),
    ]
)

Comment on lines +556 to +564
"dynamic_model = keras.Sequential(\n",
" [\n",
" keras.layers.Dense(64, activation=\"relu\"),\n",
" keras.layers.Dense(10, activation=\"softmax\"),\n",
" ]\n",
")\n",
"\n",
"# Use None for dynamic dimensions\n",
"dynamic_model.build((None, 784)) # None = dynamic batch size\n",
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Instead of defining an empty Sequential model and then calling .build(), you can define the input shape directly using a keras.Input layer. This makes the model definition more self-contained and readable. Using batch_size=None in keras.Input explicitly declares a dynamic batch size.

Here's a suggested refactoring:

dynamic_model = keras.Sequential(
    [
        keras.Input(shape=(784,), batch_size=None),  # None = dynamic batch size
        keras.layers.Dense(64, activation="relu"),
        keras.layers.Dense(10, activation="softmax"),
    ]
)

# Create a simple MNIST classifier
model = keras.Sequential(
[
keras.layers.Flatten(input_shape=(28, 28)),
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

While using input_shape in the first layer works, the recommended best practice for Sequential models is to use a keras.Input object as the first layer. This makes the model's inputs and their shapes more explicit.

Here's how you could refactor the model definition:

model = keras.Sequential(
    [
        keras.Input(shape=(28, 28)),
        keras.layers.Flatten(),
        keras.layers.Dense(128, activation="relu"),
        keras.layers.Dropout(0.2),
        keras.layers.Dense(10, activation="softmax"),
    ]
)

# Create a model for quantization
quantization_model = keras.Sequential(
[
keras.layers.Dense(64, activation="relu", input_shape=(784,)),
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For clarity and consistency with best practices, it's better to define the input shape of a Sequential model using a keras.Input layer instead of the input_shape argument in the first layer.

Here's how you could refactor it:

quantization_model = keras.Sequential(
    [
        keras.Input(shape=(784,)),
        keras.layers.Dense(64, activation="relu"),
        keras.layers.Dense(32, activation="relu"),
        keras.layers.Dense(10, activation="softmax"),
    ]
)


# Compare outputs
np.testing.assert_allclose(keras_output.numpy(), tflite_output, atol=1e-5)
print("✓ Model validation passed!")
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Using the unicode character directly might cause rendering issues on some systems or terminals. It's safer to use its unicode escape sequence \u2713 to ensure consistent display.

Suggested change
print(" Model validation passed!")
print("\u2713 Model validation passed!")

# Create a simple MNIST classifier
model = keras.Sequential(
[
keras.layers.Flatten(input_shape=(28, 28)),
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

While using input_shape in the first layer works, the recommended best practice for Sequential models is to use a keras.Input object as the first layer. This makes the model's inputs and their shapes more explicit.

Here's how you could refactor the model definition:

model = keras.Sequential(
    [
        keras.Input(shape=(28, 28)),
        keras.layers.Flatten(),
        keras.layers.Dense(128, activation="relu"),
        keras.layers.Dropout(0.2),
        keras.layers.Dense(10, activation="softmax"),
    ]
)

# Create a model for quantization
quantization_model = keras.Sequential(
[
keras.layers.Dense(64, activation="relu", input_shape=(784,)),
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For clarity and consistency with best practices, it's better to define the input shape of a Sequential model using a keras.Input layer instead of the input_shape argument in the first layer.

Here's how you could refactor it:

quantization_model = keras.Sequential(
    [
        keras.Input(shape=(784,)),
        keras.layers.Dense(64, activation="relu"),
        keras.layers.Dense(32, activation="relu"),
        keras.layers.Dense(10, activation="softmax"),
    ]
)

Comment on lines +1293 to +1302
# Create model with dynamic batch size
dynamic_model = keras.Sequential(
[
keras.layers.Dense(64, activation="relu"),
keras.layers.Dense(10, activation="softmax"),
]
)

# Use None for dynamic dimensions
dynamic_model.build((None, 784)) # None = dynamic batch size
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Instead of defining an empty Sequential model and then calling .build(), you can define the input shape directly using a keras.Input layer. This makes the model definition more self-contained and readable. Using batch_size=None in keras.Input explicitly declares a dynamic batch size.

Here's a suggested refactoring:

# Create model with dynamic batch size
dynamic_model = keras.Sequential(
    [
        keras.Input(shape=(784,), batch_size=None),  # None = dynamic batch size
        keras.layers.Dense(64, activation="relu"),
        keras.layers.Dense(10, activation="softmax"),
    ]
)


# Compare outputs
np.testing.assert_allclose(keras_output.numpy(), tflite_output, atol=1e-5)
print("✓ Model validation passed!")
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Using the unicode character directly might cause rendering issues on some systems or terminals. It's safer to use its unicode escape sequence \u2713 to ensure consistent display.

Suggested change
print(" Model validation passed!")
print("\u2713 Model validation passed!")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants