LiteRT на Android
LiteRT - среда Google для выполнения моделей машинного обучения непосредственно на устройстве. Ранее эта технология называлась TensorFlow Lite, а .tflite по-прежнему остаётся форматом файла модели.
Используйте LiteRT, когда Android-приложение должно запускать собственную или стороннюю модель, а команде нужен контроль над всем конвейером вывода: доставкой модели, предобработкой, тензорами, выполнением, постобработкой и производительностью.
Когда подходит LiteRT
LiteRT подходит, если:
- частью продукта является собственная
.tflite-модель; - готовый API ML Kit не покрывает задачу;
- вывод должен работать без сети или оставлять исходные данные на устройстве;
- требования к задержке предполагают локальное выполнение;
- команда готова отвечать за совместимость модели и проверку на разных устройствах.
LiteRT выполняет модели, но обычно не обучает их внутри Android-приложения. Модель обучается или получается отдельно, при необходимости конвертируется и оптимизируется, а затем включается в приложение или доставляется на устройство. Для больших языковых моделей, которым нужны токенизация, потоковая генерация, KV-кеш и вызов инструментов, оцените LiteRT-LM вместо самостоятельной реализации этих слоёв поверх базовой среды.
Конвейер вывода
Рабочий файл модели - только одна часть функции:
Входные данные приложения
|
v
Декодирование, изменение размера, нормализация, токенизация
|
v
Входной тензор или буфер
|
v
Выполнение LiteRT
|
v
Выходной тензор или буфер
|
v
Декодирование, порог, сопоставление меток
|
v
Доменный результат
Предобработка и постобработка входят в контракт модели. Неверный порядок каналов, размеры, нормализация, токенизация, параметры квантования или сопоставление меток могут дать правдоподобный, но неправильный результат без исключения.
Храните описание контракта рядом с моделью: имена, формы и типы тензоров, диапазоны значений, цветовое пространство, версию меток или токенизатора и правила интерпретации результата. Метаданные модели могут описывать часть этой информации, но не заменяют версионируемый контракт продукта и проверочные тесты.
Среды выполнения для Android
LiteRT предоставляет два основных API для Android:
CompiledModelAPI - современный API для производительного вывода и упрощённого ускорения на CPU, GPU и NPU.InterpreterAPI - базовый API, сохранённый для обратной совместимости и существующих интеграций. Он также может использовать среду LiteRT, доставляемую через Google Play services.
Для новой интеграции выбирайте CompiledModel, если его требования к SDK, операторам и устройствам совместимы с приложением. Не переносите стабильную реализацию с Interpreter только ради нового названия: сравните охват устройств, поддерживаемые операции, ускорение, размер приложения, измеренную производительность и стоимость миграции.
Возможности среды и требования к Android меняются. Выбирайте версию по актуальной таблице совместимости, а не копируйте номер из старого примера.
Зависимость и доставка модели
Для современной среды добавьте актуальный артефакт LiteRT:
Версия 2.2.0 была актуальна на момент ревью статьи. Перед подключением проверьте таблицу совместимости.
Если модель должна поставляться вместе с приложением, поместите её в src/main/assets/:
Так модель сразу доступна без сети, но увеличивает размер загрузки, а её обновление связано с выпуском приложения. Удалённая доставка позволяет обновлять модель независимо, но требует проверки целостности, версионирования, отката, управления хранилищем и явных состояний загрузки или недоступности. Рассматривайте удалённую модель как исполняемую часть продукта: принимайте её только из доверенного источника и активируйте после проверки.
Минимальный пример с CompiledModel
Современный API создаёт скомпилированную модель для выбранного ускорителя, выделяет буферы, выполняет вывод и читает результат:
val compiledModel = CompiledModel.create(
modelPath,
CompiledModel.Options(Accelerator.CPU),
)
val inputBuffers = compiledModel.createInputBuffers()
val outputBuffers = compiledModel.createOutputBuffers()
inputBuffers[0].writeFloat(inputValues)
compiledModel.run(inputBuffers, outputBuffers)
val outputValues = outputBuffers[0].readFloat()
Для модели из assets используйте перегрузку с AssetManager, если она поддерживается выбранной версией. Если API требует путь в файловой системе, один раз для каждой версии модели скопируйте asset в приватный файл приложения, а не делайте это перед каждым выводом.
Пример показывает механику среды, но не полную реализацию классификатора. Рабочий код должен проверить формы и типы тензоров, выполнить точный контракт предобработки, интерпретировать результат, освободить требуемые выбранным API ресурсы и обработать ошибки инициализации. В этом варианте run() синхронный, поэтому вызывайте его вне главного потока.
Инкапсуляция среды
Типы LiteRT не должны попадать во ViewModel и интерфейс:
interface ImageClassifier {
suspend fun classify(bitmap: Bitmap): List<Classification>
}
data class Classification(
val label: String,
val confidence: Float,
)
Реализация владеет скомпилированной моделью, переиспользуемыми буферами, сопоставлением меток и предобработкой. Создавайте её в области, допускающей фоновую работу, и используйте для многих запросов. Сериализуйте доступ, если среда и стратегия буферов явно не гарантируют безопасные параллельные вызовы. Отмена вызывающей корутины не обязательно прерывает уже начатый нативный вывод, поэтому отбрасывайте поздний результат, когда его владелец или входные данные уже изменились.
Предобработка и постобработка
Для модели, работающей с изображениями, предобработка может включать:
- применение поворота из EXIF или камеры;
- обрезку в соответствии с требованиями продукта;
- изменение размера тем же способом, который использовался при обучении;
- преобразование каналов RGB в ожидаемые тип и диапазон;
- применение нормализации или параметров квантования;
- запись значений в требуемом порядке тензора.
Постобработка может включать softmax, подавление немаксимумов, пороговую фильтрацию, поиск меток, преобразование координат или ранжирование. Не добавляйте преобразование только потому, что оно часто встречается. Необходимость определяет контракт модели; например, некоторые модели уже содержат softmax.
Оставляйте эти преобразования детерминированными и тестируйте отдельно от среды выполнения.
Аппаратное ускорение
Аппаратное ускорение не гарантирует выигрыш для любой модели и устройства.
- CPU обладает широкой совместимостью и подходит как базовый вариант.
- GPU может увеличить пропускную способность совместимых задач, но добавляет расходы на инициализацию и передачу данных.
- Доступность NPU и поддержка операций зависят от устройства, модели и версии среды.
Измеряйте всю функцию вместе с предобработкой и постобработкой на репрезентативной матрице устройств. Проверяйте холодную инициализацию, задержку прогретого вывода, длительную пропускную способность, память, батарею и нагрев. Ускоритель может улучшать отдельный вывод, но проигрывать для короткоживущей функции из-за стоимости инициализации.
Задайте явный резервный вариант с совместимым ускорителем или отмечайте функцию как недоступную. После переключения проверяйте не только успешное выполнение, но и качество результата: разные среды могут давать небольшие численные различия.
Квантование и размер модели
Квантование может уменьшить размер модели и расход памяти, а иногда ускорить выполнение, но способно повлиять на точность. Для полного целочисленного квантования при конвертации обычно нужен репрезентативный набор данных. Приложение должно записывать и читать типы данных, масштаб и нулевую точку, которые требуют квантованные тензоры.
Оценивайте размер, задержку, память и качество на целевой задаче вместе. Меньшая модель полезна, только если её результат соответствует продуктовому порогу на репрезентативных данных и целевых ускорителях.
Потоки, жизненный цикл и непрерывные данные
- Инициализируйте среду вне чувствительной к задержке работы интерфейса.
- Не выполняйте синхронный вывод в главном потоке.
- Переиспользуйте модель и буферы там, где это поддерживается, чтобы уменьшить выделения памяти.
- Задайте владельцу среды явный жизненный цикл и освобождайте нативные ресурсы.
- Для потоков камеры или аудио используйте ограниченное обратное давление и отбрасывайте устаревшие данные.
- Не позволяйте устаревшему результату перезаписать состояние для более новых данных.
- Определите, сериализуются запросы, игнорируются во время занятости или обрабатываются ограниченным пулом работников.
Для разового действия показывайте состояние подготовки, если инициализация заметна. Для непрерывного анализа по возможности прогрейте среду до приёма данных.
Доставка и версионирование модели
Рассматривайте модель и её метаданные как единый версионируемый набор. Полезный манифест содержит:
- версию и контрольную сумму модели;
- требуемую версию среды;
- контракт входных и выходных данных;
- версию меток или токенизатора;
- минимальную поддерживаемую версию приложения;
- метрики качества и состояние развёртывания.
Удалённую модель загружайте в приватное хранилище приложения, проверяйте целостность и совместимость до активации, записывайте атомарно, сохраняйте известную рабочую версию для отката и активируйте только полный проверенный набор.
Тестирование
Используйте несколько уровней тестов:
- Модульные тесты предобработки и постобработки с точными ожидаемыми значениями.
- Дымовой тест, который загружает настоящую модель и проверяет метаданные тензоров.
- Эталонные тесты с отобранным набором данных и ожидаемыми метками или ограниченным диапазоном числового результата.
- Тесты производительности на репрезентативных физических устройствах и ускорителях.
- Регрессионные проверки при изменении модели, среды, меток или предобработки.
Результаты с плавающей точкой могут немного отличаться на разных ускорителях. Используйте подходящие допуски вместо точного равенства, но явно зафиксируйте продуктовые критерии приёмки.
Частые ошибки
.tfliteвоспринимается как самодостаточный контракт продукта.- Вывод выполняется в главном потоке.
- Среда пересоздаётся, а буферы выделяются для каждого запроса.
- Используется неверное изменение размера, нормализация, порядок каналов или токенизатор.
- Предполагается, что GPU или NPU всегда быстрее и полностью совместимы.
- Модель обновляется без соответствующих меток, токенизатора или предобработки.
- Качество проверяется только на нескольких выбранных разработчиком примерах.
- Игнорируются ошибки загрузки, нехватка места, откат, совместимость или целостность.