Конвертація ML-моделі у формат TensorFlow Lite для Android

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1735 послуг
Конвертація ML-моделі у формат TensorFlow Lite для Android
Середній
від 1 дня до 3 днів
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    495

Конвертація ML-моделі в TensorFlow Lite формат для Android

TFLite — це не просто конвертація ваг. Це вибір формату квантизації, оптимізація графу, вибір набору операцій, сумісного з цільовими версіями Android, та перевірка того, що числовий результат відповідає оригіналу. Кожен крок має конкретні грабли.

Шляхи конвертації

З TensorFlow SavedModel — прямий шлях. З PyTorch — через ONNX проміжний формат. З JAX — через TensorFlow експорт.

# Шлях 1: TF SavedModel → TFLite (найнадійніший)
converter = tf.lite.TFLiteConverter.from_saved_model("saved_model_dir/")
tflite_model = converter.convert()

# Шлях 2: Keras модель → TFLite
converter = tf.lite.TFLiteConverter.from_keras_model(keras_model)
tflite_model = converter.convert()

# Шлях 3: PyTorch → ONNX → TF → TFLite
import subprocess
subprocess.run(["python", "-m", "tf2onnx.convert",
    "--onnx", "model.onnx",
    "--output", "model_tf",
    "--opset", "17"])
converter = tf.lite.TFLiteConverter.from_saved_model("model_tf/")

Шлях через ONNX вносить додаткові потенційні несумісності — використовуйте тільки коли прямий шлях недоступний.

Квантизація при конвертації

# FP16 — мінімальна деградація, модель у 2 рази менша, GPU delegate прискорення
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]
tflite_fp16 = converter.convert()

# Dynamic INT8 — ваги int8, активації float32. Не потрібен калібрувальний набір.
converter2 = tf.lite.TFLiteConverter.from_saved_model("saved_model_dir/")
converter2.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_dynamic_int8 = converter2.convert()

# Full INT8 — обидві ваги та активації. Вимагає калібрувального набору. Потрібен для Hexagon DSP.
def representative_dataset():
    dataset = load_calibration_data()  # 100-500 прикладів
    for sample in dataset:
        yield [sample[np.newaxis, :].astype(np.float32)]

converter3 = tf.lite.TFLiteConverter.from_saved_model("saved_model_dir/")
converter3.optimizations = [tf.lite.Optimize.DEFAULT]
converter3.representative_dataset = representative_dataset
converter3.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter3.inference_input_type = tf.uint8   # або tf.int8
converter3.inference_output_type = tf.uint8
tflite_full_int8 = converter3.convert()

Full INT8 з inference_input_type = tf.uint8 — вхідні дані передаються як uint8 (0–255), без нормалізації до float32 в Java/Kotlin. Видаляє крок попередньої обробки, але вимагає обережної синхронізації з параметрами квантизації моделі.

Непідтримувані операції

Не всі TF/PyTorch операції існують у TFLite builtin ops. Перевірка:

# Які операції в моделі не підтримуються TFLite
converter.target_spec.supported_ops = [
    tf.lite.OpsSet.TFLITE_BUILTINS,
    tf.lite.OpsSet.SELECT_TF_OPS  # fallback на TF операції
]

SELECT_TF_OPS включає підмножину TF операцій — збільшує розмір TFLite runtime (~5 МБ) та сповільнює деякі операції. Краще переписати модель, уникаючи SELECT_TF_OPS — дозволяє NNAPI та Hexagon сумісність.

Користувацька операція через C++:

// Реєстрація користувацької операції
static TfLiteRegistration* GetMyCustomOpRegistration() {
    static TfLiteRegistration reg = {
        nullptr, nullptr,
        [](TfLiteContext* ctx, TfLiteNode* node) -> TfLiteStatus {
            // Реалізація інференсу
            return kTfLiteOk;
        },
        nullptr, "MyCustomOp", 1
    };
    return ®
}

// У коді Android NDK:
interpreter.AddCustomOp("MyCustomOp", GetMyCustomOpRegistration, 1);

Kotlin через JNI. Нетривіально, але іноді єдиний шлях.

Верифікація числової точності

# Порівняйте PyTorch/TF та TFLite виходи на однакових входах
import numpy as np

# TF оригінал
tf_output = tf_model(test_input).numpy()

# TFLite
interpreter = tf.lite.Interpreter(model_content=tflite_model)
interpreter.allocate_tensors()

input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

interpreter.set_tensor(input_details[0]['index'], test_input)
interpreter.invoke()
tflite_output = interpreter.get_tensor(output_details[0]['index'])

print(f"Max abs diff: {np.max(np.abs(tf_output - tflite_output))}")
print(f"MSE: {np.mean((tf_output - tflite_output)**2)}")
# FP32: < 1e-5, FP16: < 1e-2, INT8: < 0.05

Якщо різниця перевищує норму — проблема в нормалізації входу, неправильних параметрах квантизації або операції, яка використовує інший алгоритм у TFLite.

##特性детекторів об'єктів

YOLO, SSD, EfficientDet містять NMS (Non-Maximum Suppression) постпроцесинг. TFLite не вміє NMS вбудовано (на відміну від Core ML Detection Output). Варіанти:

  1. Видаліть NMS з моделі, реалізуйте в Java/Kotlin після інференсу
  2. Використовуйте TFLite Task Library — містить готовий ObjectDetection API з NMS
// TFLite Task Library: ObjectDetector (включає NMS)
val options = ObjectDetector.ObjectDetectorOptions.builder()
    .setScoreThreshold(0.5f)
    .setMaxResults(20)
    .build()

val detector = ObjectDetector.createFromFileAndOptions(context, "detector.tflite", options)

val image = TensorImage.fromBitmap(inputBitmap)
val results: List<Detection> = detector.detect(image)

for (detection in results) {
    val box = detection.boundingBox  // RectF
    val label = detection.categories.first().label
    val score = detection.categories.first().score
}

Task Library підтримує тільки специфічні модельні сигнатури — модель повинна відповідати форматі TFLite Model Metadata.

Model Metadata: важливо для Interpreter + Task Library

from tflite_support.metadata_writers import image_classifier
from tflite_support.metadata_writers import writer_utils

# Створіть метадані класифікатора
writer = image_classifier.MetadataWriter.create_for_inference(
    writer_utils.load_file("model.tflite"),
    input_norm_mean=[0.0],
    input_norm_std=[255.0],
    labels_file_paths=["labels.txt"]
)

tflite_with_metadata = writer.populate()
writer_utils.save_file(tflite_with_metadata, "model_with_metadata.tflite")

Без метаданих TFLite Task Library працює гірше — без автоматичної нормалізації, без маппінгу виходів. З метаданими — все обраховується автоматично.

Бенчмарк на пристроях

# ADB: запустіть TFLite Benchmark Tool безпосередньо на пристрої
adb push model.tflite /data/local/tmp/
adb shell /data/local/tmp/benchmark_model \
    --graph=/data/local/tmp/model.tflite \
    --use_gpu=true \
    --num_threads=4 \
    --num_runs=50
# Вихід: середня затримка, min/max, час прогрівання

TFLite Benchmark Tool — офіційний Google інструмент, дає чесні цифри без JVM overhead та Android UI. Використовуйте для порівняння делегатів (GPU vs NNAPI vs CPU).

Процес

Вибір шляху конвертації → конвертація з потрібним рівнем квантизації → верифікація точності → додання метаданих → тестування на парку пристроїв через Benchmark Tool → інтеграція в Android додаток.

Орієнтири за часом

Прямої конвертації TF/Keras моделі з верифікацією — 3–7 днів. Конвертація через ONNX, користувацькі операції, додання метаданих, повне тестування — 2–4 тижні.