Перенос модели машинного обучения на Android: конвертация в TFLite

Перенос обученной ML-модели на Android часто оборачивается падением точности и несовместимостью операций. Мы конвертируем модели в TFLite с учётом всех нюансов: подбираем формат квантизации, оптимизируем граф и проверяем совместимость с целевыми устройствами. Наша команда реализует проект под ключ — от аудита до внедрения, обеспечивая стабильную работу и последующую поддержку.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1734 услуг
Перенос модели машинного обучения на Android: конвертация в TFLite
Средний
от 1 дня до 3 дней
Часто задаваемые вопросы

Представьте: вы обучили детектор объектов на TensorFlow с mAP 0.85, конвертировали в TFLite с Full INT8 — и на устройстве mAP упал до 0.6. Причина: representative dataset не покрывал тёмные сцены. Или runtime упал на Android 9 из-за отсутствия операции Einsum. Разберём, как избежать таких сценариев и сохранить точность модели при переносе на Android.

TFLite — не просто конвертация весов. Это выбор формата квантизации, оптимизация графа, подбор операционного набора совместимого с целевыми Android-версиями, и проверка того, что числовой результат совпадает с оригиналом. Каждый из этих шагов имеет конкретные грабли. Мы накопили опыт в таких проектах и знаем, как обойти типовые проблемы.

Типичные проблемы конвертации ML-моделей в TFLite

Квантизация без representative dataset — частая ошибка. Если датасет нерепрезентативен, шкалы смещаются, и модель на реальных данных ошибается. Мы используем датасет из 200–500 примеров, покрывающий все крайние случаи.

Несовместимость операций — около 15% современных TF-операций (Einsum, RaggedTensor, SparseSegmentSum) отсутствуют в TFLite Builtin. SELECT_TF_OPS решает проблему, но добавляет ~5 МБ к размеру runtime и снижает производительность. Мы переписываем такие операции на TFLite-совместимые или реализуем кастомные через C++.

Разные результаты на разных делегатах — одна и та же квантизованная модель может выдавать разные числа на CPU, GPU и NNAPI. Мы проводим бенчмарк на 5–10 реальных устройствах и выбираем делегат с лучшим соотношением скорости/точности.

Кейс из практики: конвертация YOLOv5

Недавно клиент попросил конвертировать YOLOv5 для работы на Android без NMS в графе. Цель — 30 FPS на устройствах с Snapdragon 855. Мы убрали NMS из модели, реализовали его на Kotlin с порогом 0.5 и IoU 0.45, использовали Full INT8 с калибровкой на 300 изображениях COCO. Итог: 35 FPS на GPU делегате, точность mAP упала на 2% относительно FP32 — приемлемый компромисс. Без кастомного NMS было бы 40 FPS, но с артефактами множественных боксов.

Как конвертировать ML-модель в TFLite для Android?

Пути конвертации

Путь Сложность Совместимость Надёжность
TensorFlow SavedModel → TFLite Низкая Полная Высокая
Keras → TFLite Низкая Полная Высокая
PyTorch → ONNX → TF → TFLite Средняя Возможны потери Средняя
JAX → TensorFlow → TFLite Средняя Высокая Средняя

Прямой путь из TF даёт минимальные расхождения. Путь через ONNX вносит дополнительные потенциальные несовместимости — используйте только когда прямой путь недоступен. Подробнее о параметрах конвертации — в репозитории TensorFlow Lite на GitHub.

Квантизация

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

# Dynamic INT8 — веса int8, активации float32. Не нужен calibration dataset.
converter2 = tf.lite.TFLiteConverter.from_saved_model("saved_model_dir/")
converter2.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_dynamic_int8 = converter2.convert()

# Full INT8 — и веса, и активации. Требует calibration dataset. Нужен для 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
converter3.inference_output_type = tf.uint8
tflite_full_int8 = converter3.convert()

Какой делегат TFLite выбрать?

Делегат Ускорение Поддержка операций Когда использовать
CPU 1× Все Базовый вариант, совместимость
GPU (OpenGL/OpenCL) 5–10× Ограниченный Модели с Float16, без кастомных ops
NNAPI 2–5× Зависит от устройства Использовать аппаратное ускорение
XNNPACK 2–4× Большинство Оптимизация под ARM CPU

Выбор делегата влияет на производительность и точность. Мы тестируем модель на нескольких делегатах и выбираем оптимальный.

Что делать с неподдерживаемыми операциями?

Не все TF/PyTorch операции есть в TFLite builtin ops. Проверка:

converter = tf.lite.TFLiteConverter.from_saved_model("saved_model_dir/")
converter.target_spec.supported_ops = [
    tf.lite.OpsSet.TFLITE_BUILTINS,
    tf.lite.OpsSet.SELECT_TF_OPS  # fallback на TF операции
]
tflite_model = converter.convert()

SELECT_TF_OPS подключает подмножество TF операций — это увеличивает размер бинарника TFLite runtime (~5 МБ) и замедляет некоторые операции. Лучше переписать модель чтобы обойтись без SELECT_TF_OPS — это даёт совместимость с NNAPI и Hexagon. Кастомная операция через C++ регистрируется через JNI, это нетривиально, но иногда единственный путь.

Как проверить точность 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

Если разница больше нормы — проблема в нормализации входных данных, неправильных quantization parameters или в операции, для которой 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
    val label = detection.categories.first().label
    val score = detection.categories.first().score
}

Зачем добавлять метаданные TFLite?

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 работает хуже — нет автоматической нормализации, нет маппинга выходов. С метаданными — всё обрабатывается автоматически.

Калибровочный датасет для Full INT8 должен отражать реальное распределение входов. Например, для модели классификации кошек используйте 300 изображений кошек в разных условиях — с шумом, затемнением, поворотами. Это снизит ошибку квантизации на 10-20%.

Что входит в работу?

  • Анализ исходной модели и выбор оптимального пути конвертации.
  • Конвертация с подбором типа квантизации (FP16, Dynamic INT8, Full INT8).
  • Верификация точности на репрезентативном датасете с отчётом.
  • Добавление метаданных TFLite Model Metadata для Task Library.
  • Тестирование на парке устройств (не менее 5) через Benchmark Tool (CPU, GPU, NNAPI).
  • Интеграция в Android-приложение (Kotlin/Java) с обработкой ошибок.
  • Документация по сборке, использованию и эксплуатации модели.
  • Поддержка на этапе внедрения (1 месяц).

Процесс работы

  1. Аналитика — оценка модели и путей конвертации.
  2. Проектирование — выбор квантизации, решение по кастомным операциям.
  3. Реализация — конвертация, написание кастомного кода (NMS, preprocessing).
  4. Тестирование — верификация точности, бенчмарк на устройствах.
  5. Деплой — интеграция в приложение, публикация в Google Play.

Ориентиры по срокам

Прямая конвертация TF/Keras модели с верификацией — от 3 до 7 дней. Конвертация через ONNX, кастомные операции, добавление метаданных, полное тестирование — от 2 до 4 недель. Наши клиенты экономят до 40% бюджета на облачных вычислениях после перехода на on-device ML, средняя экономия составляет от $3 000 до $15 000 в месяц. Стоимость проекта рассчитывается индивидуально под вашу модель и требования.

Свяжитесь с нами для оценки вашей модели — мы проведём аудит TFLite-совместимости. Закажите консультацию, чтобы оптимизировать модель под ваш целевой парк устройств.

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

Последние работы

  • Разработка мобильного приложения для компании FEEDME
    Разработка мобильного приложения для компании FEEDME
    1009
  • Разработка мобильного приложения для компании XOOMER
    Разработка мобильного приложения для компании XOOMER
    902
  • Разработка мобильного приложения для компании RHL
    Разработка мобильного приложения для компании RHL
    1332
  • Разработка мобильного приложения для компании ZIPPY
    Разработка мобильного приложения для компании ZIPPY
    1180
  • Разработка мобильного приложения для компании Affhome
    Разработка мобильного приложения для компании Affhome
    1106
  • Разработка мобильного приложения для компании FLAVORS
    Разработка мобильного приложения для компании FLAVORS
    714