type
status
date
slug
category
password
tags
This blog records the process and issues solved during Deploying a pytorch model on an Android Phone. The code are uploaded on Github:
mobilenet-v2-android
wenyanglyu โ€ข Updated Feb 15, 2025

Introduction

The first step is to choose the Right Pathway for Your Android ML Deployment, here is a list for different pathways. TFLite is chosen in this project.
Deployment Pathway
Best For
Pros
Cons
TFLite (TensorFlow Lite)
Small, efficient models
Fast, optimized for mobile
Needs conversion
PyTorch Mobile
PyTorch-based models
No conversion needed
Larger size
ONNX Runtime
Cross-platform models
Works with TF & PyTorch
Needs ONNX conversion
MLKit (Google Firebase)
Pre-trained ML models
No training needed
Limited customization
Core ML
iOS + Android apps
Optimized for Apple devices
Needs conversion for Android
This is a list of using different models while choosing TFLite deployed on Android. PyTorch is chosen to convert to TFLite in this project.
Model Type
Conversion Pathway
Output Format
TensorFlow / Keras
SavedModel โ†’ TFLiteConverter
.tflite โœ…
PyTorch
PyTorch โ†’ ONNX โ†’ TensorFlow โ†’ TFLite
.tflite โœ…
Scikit-learn / XGBoost
Sklearn โ†’ ONNX โ†’ TensorFlow โ†’ TFLite
.tflite โœ…
Unsupported TF Operations
Must replace layers with TFLite-compatible ops
.tflite ๐Ÿšจ
This project aims to deploy a pre-trained PyTorch ML model on Android, allowing for a quick implementation of the PyTorch โ†’ ONNX โ†’ TensorFlow โ†’ TFLite conversion pathway and Android deployment.
Once the pipeline is established, it can be used to deploy custom ML models or other pre-trained models efficiently.

1 Python - Virtual Environment & Dependency Management

1.1 Setting Up a Virtual Environment (venv)

To isolate dependencies and avoid conflicts, create and activate a virtual environment:

1.2 Issues & Key Takeaways

Issue 1.2.1: ModuleNotFoundError: No module named 'keras.src.engine'

TensorFlow Addons (TFA) only supports tf.keras, but because standalone Keras (3.x) is installed, Python prioritizes it over tf.kerasTFA tries to load keras.src.engine, which does not exist in tf.keras.
Solution: Remove standalone Keras to force TFA to use tf.keras
Key Takeaway: Using tested low version is better than using latest versions

Issue 1.2.2: Dependency Conflicts with TensorFlow, TFA, and TFP

By default, pip installs the latest version of each package, without checking compatibility. This led to incompatible versions being installed.
Solution: Install Compatible Versions Explicitly
Key Takeaway: I took too long too solve this issue, so I saved the versions in to file requirements.txt pip freeze > requirements.txt , then I wonโ€™t suffer for the next project.

Issue 1.2.3: typing-extensions Conflict Between TensorFlow and PyTorch

I tested the requirements.txt in a new venv and failed to install all package because of the following dependency conflict:
Solution: These versions cannot be installed simultaneously because torch requires a higher version typing_extensions while tensorflow requires a very low one. So I Split Dependencies into Separate requirements.txt files and install them sequentially:
Key Takeaway: If dependencies have conflicting requirements, install them in separate stages. This solution is tested working in new venv.

2 Python - Model Preparation


2.1 Model Selection

I tried several github models and it has different issues, before I lost my patience, I found this MobileNetV2 model from PyTorch.
MobileNetV2 is a light weight classificaiton model of 1000 classes.
The official link has given detialed guide such as the input of MobileNetV2 (3x224x224) and normalization requirement. https://pytorch.org/hub/pytorch_vision_mobilenet_v2/

2.1 Model Test

The first step is to test the model and evaluate its performance, giving me a clear expectation of its capabilities and how it will function on my Android phone.
Well, it works well, the classification is very accurate after testing several images.

3 Python - Model Conversion

3.1 Converting to TFLite

coremltools converts models into MobileNetV2.mlmodel for iOS, while TFLite converts TensorFlow models into .tflite format for Android.
ONNX serves as a bridge between PyTorch and TensorFlow.
  • ONNX (Open Neural Network Exchange) is an open-source format for representing machine learning models.
  • ONNX enables ML model interoperability across PyTorch, TensorFlow, and other frameworks.
  • ONNX is the best option when moving a model from PyTorch to TensorFlow Lite (for Android)
The reason for using TFLite for Android is TensorFlow models are too large and inefficient for mobile deployment.

4 Android - Building the Mobile App

I am using Android Studio for deploying and testing the application on a Samsung phone, with the converted TFLite machine learning model.
The project started by creating an empty Android project targeting Android 12 (API level 31). Below is a directory list of modified files:

4.1 Summary of Modified Files and Their Functions

Most of the project files we donโ€™t need to touch, and they are configured and linked with each other perfectly.

4.1.1 AndroidManifest.xml (Application Configuration)

Configures necessary permissions for file access, as the app selects images from storage for classification.

4.1.2 app/build.gradle.kts (Dependencies)

  • Added dependencies for TensorFlow Lite and Android UI components. There are serveral build.gradle.kts files, modify the one under app folder.

    4.1.3 MainActivity.kt (App Logic & Model Inference)

    • Handles image selection from the gallery.
    • Loads and initializes the TFLite model.
    • Runs image preprocessing and inference on the selected image.
    • Uses imagenet_classes.txt text-based label mapping.

    4.1.4 activity_main.xml (XML-Based User Interface)

    • Created manually as it was not originally present in the project.
      • It defines the visual structure of the screen for MainActivity.kt.
    • When MainActivity.kt is launched, it loads this XML file using: setContentView(R.layout.activity_main)
      • This means the UI elements in activity_main.xml will be displayed when the app starts.
      • ImageView for selected image.
      • Button to classify the image.
      • TextView to show the classification result.

    4.1.5 assets/ (Model and Labels)

    • Added manually to store necessary assets.
    • mobilenet_v2.tflite: The TensorFlow Lite model for image classification.
    • imagenet_classes.txt: Label mappings for classification results.

    4.2 Key Configurations in MainActivity.kt

    The MainActivity.kt is the most important file in the project, the functions include Image Selection, loading TFLite model, pre-process the selected image, and run inference then display result.

    4.2.1 UI Setup & Image Selection

    • Users can select an image from their gallery by tapping on an ImageView.
    • The selected image is then displayed in the UI for classification.
    Process Overview:
    • The app registers an Activity Result to handle image selection.
    • When an image is chosen, it is stored in selectedBitmap and displayed in the ImageView.

    4.2.2 Loading the TensorFlow Lite Model

    • Loads mobilenet_v2.tflite from assets.
    • Configures TensorFlow Lite Interpreter with specific options.
    Process Overview:
    • The model is loaded into a tflite interpreter for running inference.
    • The settings ensure compatibility across different devices without GPU acceleration conflicts.

    4.2.3 Preprocessing the Image for Inference

    • Converts the selected image into a ByteBuffer that matches the input format of MobileNetV2.
    • Normalizes pixel values using ImageNet mean & standard deviation values.
    Process Overview:
    • The image is resized to 224x224 pixels.
    • Normalization applies ImageNet preprocessing values.
    • The formatted ByteBuffer is ready for inference in TensorFlow Lite.

    4.2.4 Running Inference & Displaying Results

    • Runs inference asynchronously.
    • Identifies the highest confidence prediction and displays it.
    Process Overview:
    • Runs inference on a background thread (Dispatchers.IO).
    • Finds the class with the highest confidence score.
    • Displays the predicted label in the UI.

    4.3 Android Forecasting Error Troubleshooting

    The same image produces correct predictions in Python, but incorrect predictions in Android. I tested different images on my Samsung phone, the results are far from correct.

    4.3.1 Model Verification

    The original MobileNetV2 model was converted using a standard pipeline:
    • MobileNetV2 (verified in Python)
    • Converted to ONNX
    • Converted to TFLite
    • Deployed TFLite on Android โ†’ Incorrect predictions
    I verified that TFLite runs correctly in Python, so the issue is not related to model conversion.
    The image preprocessing on Android appeared correct, the input data shape matched expectations, and the output values had the correct dimensionsโ€”yet the forecast was inaccurate. This raised the question of whether the same model could produce different results on different platforms. However, given that this conversion pipeline is a well-established method, any discrepancies should be minimal.

    4.3.2 Input and Output Comparison

    I got stuck here. I consulted an expert in the field, who emphasized that the model's input and output should be exactly the same across platforms. Following this advice, I systematically verified each step of the image preprocessing pipeline.
    I tested the same image on both Python and Android:
    • The first 10 preprocessed input values were printed in both environments.
    • The first 10 output values were also compared.
    The results showed that input & output values in Android were both different from Python. So the problem is obviously coming from the input.

    4.3.3 Comparison of Image Preprocessing in Python vs. Android

    The preprocessing steps for both implementations were compared to identify discrepancies.
    Step
    Python (Debug Script)
    Kotlin (Android Implementation)
    Match?
    Image Resizing
    image.resize((224, 224), Image.BILINEAR)
    Bitmap.createScaledBitmap(bitmap, 224, 224, true)
    โœ… Yes
    Convert to Float
    np.array(image, dtype=np.float32) / 255.0
    ((pixel shr X and 0xFF) / 255.0f)
    โœ… Yes
    Standardization
    (image - mean) / std
    ((pixel_component / 255.0f) - mean) / std
    โœ… Yes
    Reorder Channels
    np.transpose(image, (2, 0, 1)) (HWC โ†’ CHW)
    Missing explicit channel reordering
    โŒ No
    Add Batch Dimension
    np.expand_dims(image, axis=0)
    Implicitly handled in ByteBuffer
    โœ… Yes
    The issue is Identified as missing Channel Reordering:
    • The MobileNetV2 model expects input in CHW format ((C, H, W), Channels First).
    • Image is loaded in HWC format ((H, W, C), Channels Last).
    Python explicitly converts HWC โ†’ CHW using np.transpose(image, (2, 0, 1)), butAndroid did not include this step, leading to incorrect input tensors. After reordering the channel the input values are the same as shown below and the classification is correct. ISSUE SOLVED!
    Source
    First 10 Preprocessed Input Values
    Android (Kotlin)
    [2.2489083, 2.2489083, 2.2489083, ...]
    Python (NumPy)
    [2.2489083, 2.2489083, 2.2489083, ...]

    5. Git Version Control

    5.1 GitHub Login & Setup

    Create a repo on Github and connect with Github.

    5.2 Checking Repository & Status

    Check previous uploaded files on github repo, lists all tracked files currently in the repository.
    Remove Old Python and Android Folder.

    5.3 Uploading Updated Python and Android Project Files

    The new files are verified and reviewed in new environment. They are ready to be used for new user
    Push Updates to Remote Repository and verify the change

    5.4 Uploading README.md


    6 Next Steps

    The Android app's loading speed is reasonable but has noticeable delays, leaving room for improvement.
    ย 
    NZ Govt Leaders Slaughter Low-IQ Opposition LeadersBig Data: SQL, Hive and ElasticSearch