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

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

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

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

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

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

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

Часто задаваемые вопросы

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

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    896
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    1003
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    597

Представьте: вы обучили детектор объектов на 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 Все Базовый вариант, совместимость
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-совместимости. Закажите консультацию, чтобы оптимизировать модель под ваш целевой парк устройств.