В этой статье я хочу рассказать о том, как мы решаем неизвестные проблемы в Syzygy AI, на примере нашего пути миграции конвейера компьютерного зрения с голого Python в облаке AWS на встроенную библиотеку cpp в смартфонах.

Иногда вы можете оказаться в огромном космическом пространстве, полном неизведанного. Эти звери могут быть самыми разными — от «Я никогда этого раньше не делал» до «Боже мой, никто этого раньше не делал, и только Бог знает, возможно ли это вообще!11». Представьте, что вам нужно интегрировать какого-то нового поставщика услуг, создать что-то поверх новой библиотеки/языка/инструмента или даже погрузиться в настоящую задачу RnD.

Как ориентироваться в неизвестности? Как свести к минимуму ущерб от потерянного времени и при этом иметь возможность выполнять итерации быстро? тлдр; :

  • шипы — экспериментировать и учиться на практике
  • нарезка задач
  • дорожная карта на основе вехи (т.е. если вы не можете достичь критической вехи — дорожная карта должна быть скорректирована и, возможно, отменена)

О проекте

Наука о данных\ИИ по-прежнему является модным словечком для привлечения внимания к тому, что вы делаете, но статистика показывает, что большинство прототипов не доходят до производства. Может быть, что-то опасное притаилось за занавесками золотой клетки блокнотов Юпитер?

Один из проектов, над которым мы работаем, — Умное зеркало — мы хотим создать технологию, которая будет подсказывать пользователю, как лучше выглядеть на фото.

В нем есть куча увлекательных задач — от философских — что «лучше» и что это «лучше» означает для конкретного пользователя, до более приземленных вопросов, вроде сравнения независимой от масштаба мимики между кадрами.

Вооружившись некоторыми знаниями в области математики, встраиваемых систем и низкоуровневого программирования, мы были настроены оптимистично, но все же решили начать медленно. Исходный эскиз конвейера обработки выглядит следующим образом:

  • анализировать портрет пользователя
  • на его основе — генерировать несколько лиц пользователей с разными эмоциями и выражениями
  • выяснить, что является наиболее эстетически привлекательным
  • сравните идеальный портрет с прямой трансляцией с камеры и покажите подсказки

Для таких проектов важно сразу же съесть лягушку — проверить, выполнимо ли это (с нашей командой) вообще — разобрать самые сложные и сомнительные компоненты решения и попытаться их реализовать. Если основные функции окажутся рабочими, мы можем разделить их на несколько этапов, чтобы развертывать один за другим.

Понимание того, что такое Лучше в контексте красоты человека, является субъективной сложной темой, поэтому мы решили, что для POC мы можем начать немного проще — что если пользователь просто покажет нам свое лучшее фото — тогда мы можем исключить 2 этапа? Таким образом, первым продуктом стало приложение, которое сравнивало эталонное фото с живым видеопотоком и показывало подсказки.

В настоящее время под капотом нашего конвейера компьютерного зрения находится более десятка нейронных сетей, и он может обрабатывать более 20 кадров в секунду — в зависимости от аппаратного обеспечения смартфона.

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

Нам нужна обработка в реальном времени (*) — скорость, скорость, скорость — поэтому давайте использовать наши навыки низкоуровневого программирования и делать все в cpp и, возможно, в cuda!11 (* — Хорошо, в реальном времени — это немного расплывчатая тема, давайте перефразируем ее так, чтобы иметь возможность обрабатывать не менее 24 кадров в секунду через наш конвейер CV).

Есть зрелые библиотеки, которые можно подобрать для подключения нужных алгоритмов. И есть много предварительно обученных моделей (обратите внимание на лицензию!), которые можно сравнительно легко сложить вместе для эскиза прототипа. Если задача, которую вы хотите сделать, уже выполнена — вы просто используете их как строительные блоки без особой настройки — запускаете детектор лиц, а затем детектор ориентиров лица, а затем… 🤞.

Наверняка некоторые модели, которые вы найдете, могут быть неисправными или иметь некоторые характеристики производительности/качества, которые не соответствуют вашим ожиданиям. Но настоящее веселье начнется, когда вы обнаружите, что для вашего варианта использования нет открытых исследований.

В любом случае, чем быстрее вы начнете пробовать, тем быстрее получите пищу для размышлений. Совершенно нормально, если то или иное не работает так, как ожидалось (или вообще не работает :D) — это та часть пути, которую вам предстоит пройти, чтобы исследовать неизведанные территории.

У вас и вашей команды может возникнуть опасное искушение «Попробовать еще кое-что», которое может легко затянуть вас на несколько дней безрезультатно. Чтобы уберечь себя от ловушки «сильно давить в неправильном направлении», мы устанавливаем временные границы, определяя, сколько времени мы готовы посвятить конкретному делу. Когда время истекает — делимся всеми находками и по ним решаем — стоит ли на этом останавливаться.

Также очень полезно иметь возможность поспрашивать людей за пределами вашей команды — например, бывших коллег — пробовали ли они то, что теперь нравится всей команде.

Первый свод — клиент-сервер и облако для упрощения цикла обратной связи

Пару недель спустя — время поделиться результатами с заинтересованными сторонами (конечно, дистанционно!) — ранняя обратная связь необходима для принятия решения о следующих шагах (если таковые будут!). Итак, как они могут попробовать это? Ну это просто — клонируйте код, убедитесь, что у вас установлен CMake и необходимые зависимости… .

Вы спросите, чей `клон` им нужен? У вас есть видеокарта NVidia GPU? Нет, мы пока не можем подготовить приложение для iPad. Эммм, да, давайте подумаем о чем-нибудь другом!

Мы измерили время обработки кадра, и самый большой вклад в продолжительность внесло время вывода моделей (и, скорее всего, ввод-вывод к GPU и обратно) — поэтому все было переписано на python ради скорости разработки. Облачные провайдеры были рады поделиться виртуальными машинами с мощным GPU — просто платите деньги, это просто! (ну, нет :( ) — значит, мы больше не зависим от железа пользователя! Давайте подготовим какой-нибудь упрощенный интерфейс и выложим UI через веб-страницу (но по-прежнему будем работать с веб-камерой).

Это был значительный прорыв в формировании первоначальной идеи, и попутно он выявил две проблемы:

1. Обычно готовые к использованию модели работают наилучшим образом, когда данные, на котором мы проводим вывод, похожи на то, что использовалось для обучения. Следовательно, портреты студийного качества белых бородатых мужчин в возрасте 40 лет могут быть не лучшим учебным набором для случаев использования, когда ваша целевая аудитория — девочки-подростки, делающие селфи в среде с неравномерными условиями освещения.

Если то, что вы хотите сделать, это не школьный проект с классификатором кошек или собак — вам лучше знать, что такое машинное обучение на самом деле — копаться в последних или не очень статьях, подготавливать данные и иметь возможность быстро экспериментировать, тщательно и честно объясняя себе — почему вы решили пойти именно по этому пути.

2. Когда ваше программное обеспечение работает в облаке — оно может преподнести всевозможные сюрпризы из-за проблем с распределенной системой — от кражи процессорного времени на общих инстансах до неявного размера буфера для клиента, которые предполагают, что это отличная идея накопить пару кадров, прежде чем сбросить их в сокет. И, конечно же, вам нужно установить совместимую версию драйверов и библиотек libcuda*.so, чтобы ваш код Python работал. Ах да, железо там может быть немного устаревшим в плане вычислительных возможностей по сравнению с последними версиями потребительских видеокарт на машине разработчика. В результате классическая дилемма Это работает на моей машине может противоречить пользовательскому опыту в облаке.

По первому пункту — решение было очевидным (хоть и не простым!): нужны данные. Конкретные данные. Итак, ползаем! С нашей собственной пользовательской аннотацией — благодаря CVAT — вы можете сойти с ума.

Но второй пункт ставит справедливый вопрос — какие варианты у нас есть в отношении продуктизации нашего решения. Или проще говоря — есть ли альтернатива сложной и дорогой клиент-серверной системе с мясистыми GPU-серверами?

В конце чего мы хотим — запустить десятки нейросетей с разной архитектурой (несколько примеров решаемых нами задач: обнаружение ориентиров лица, оценка позы головы, сегментация, оценка условий освещения) и классические манипуляции с изображениями (изменение размера, обрезка, фильтрация) с требованиями, близкими к реальному времени.

Говоря о требованиях: что на самом деле означает для нас режим реального времени? Это 24 фпс? А если будет 23? Эксперименты показывают, что в любом случае выше 15 выглядит достаточно плавно для начальной демонстрации.

Тайна TFLOP — удивительная мощь в наших карманах

Хороший инженер — это ленивый инженер. И позвольте мне объяснить, что я имею в виду: хороший инженер не боится сложности и более чем счастлив победить ее, КОГДА это действительно необходимо, и не показывать себя никому другому.

Пришло время выяснить — что у нас внутри современных смартфонов? Можем ли мы переложить на них часть работы вместо создания сложного серверного приложения? По крайней мере, чтобы уменьшить сетевой ввод-вывод? И устранить целый класс проблем, связанных с распределением нагрузки/безопасностью данных.

Первое, что привлекает наше внимание — сравнение производительности ноутбуков с процессорами Intel i5 и Snapdragon: tldr; qualcomm оказался на удивление быстрым.

Второй — бенчмарки ИИ для мобильного оборудования — на первый взгляд сложно понять, как трактовать эти цифры, но сам факт наличия бенчмарка для мобильных устройств весьма интригует!

Поэтому мы решили погрузиться глубже — и потратить время на изучение этой области. Информация ниже может быть слишком технической, но я хочу проиллюстрировать, как то, что мы обнаруживаем, меняет наше понимание того, что может быть дальше.

Несколько заметных уроков для нас из одного из пиковых билетов 2020 года:

Snapdragon — это не отдельный процессор, а SoC — то есть система на кристалле, то есть содержит различные компоненты, кроме процессора.

Львиный зев 865

  • Процессор: Kryo 585, до 2,84 ГГц, 64-разрядный, набор инструкций ARMv8-A ПРИМЕЧАНИЕ: производный от ARM Cortex-A77 и Cortex-A55.
  • Графический процессор: Adreno 650, OpenCL 2.0 FP, Vulkan 1.1, OpenGL ES 3.2, DX12
  • DSP: Шестиугольник 698
  • Оперативная память: LPDDR5, скорость: 2750 МГц

Apple:

  • 2019 A13: архитектура — A64 — ARMv8.4-A, шестиядерный процессор, 2 ядра по 2,65 ГГц + 4 энергоэффективных ядра
  • 2020 A14: архитектура — A64 — ARMv8-A, шестиядерный ЦП, 2 до 3,1 ГГц + 4 до 1,8 ГГц, LPDDR4X

Huawei:

  • конец 2019 года: Kirin 990: 4 ядра ARM Cortex-A76 + 4 ядра ARM Cortex-A55, Mali-G76 M16
  • 2020: Kirin 9000: 4 ядра ARM Cortex-A77 до 3,13 ГГц + 4 ядра ARM Cortex-A55 до 2,05 ГГц, Mali-G78 MP24

Samsung:

  • Q4 2019: Exynos 980: 2 ядра ARM Cortex-A77 + 6 ядер ARM Cortex-A55, LPDDR4
  • 2020: Exynos 990: 2 пользовательских процессора с тактовой частотой до 2,73 ГГц + 2 ядра ARM Cortex-A77 с тактовой частотой до 2,5 ГГц + 4 ядра ARM Cortex-A55 с тактовой частотой до 2 ГГц, Mali-G77 MP11, LPDDR5X, выделенный двухъядерный NPU

Сам Cortex-A* — это всего лишь набор инструкций, реализуемых конкретным процессором (и, естественно, разные вендоры имеют тенденцию реализовывать их с некоторыми нюансами).

GPU — тоже более-менее понятно — многие из нас несколько дней назад проводили ночи, сражаясь с монстрами, но что, черт возьми, такое DSP\NPU\TPU\VPU\?!

Есть класс нейронных сетей — сверточные — которые полагаются на тяжелые операции умножения матриц. Часто используется для задач, связанных с компьютерным зрением. Если матрица не двумерная, а трехмерная — она называется тензорной.

Поскольку многие задачи на устройствах связаны с изображениями — производители решили создать специализированный вычислительный блок ~ ASIC — для эффективного выполнения этих операций.

Что касается разницы между GPU и TPU:

TPU очень ограничен с точки зрения поддерживаемых операций (и, как мы узнаем позже, на самом деле ввода формы и размера) — организация памяти очень проста, в то время как GPU имеет гораздо более высокий набор поддерживаемых команд и иерархию памяти с кэшами. Современные смартфоны более высокого класса обычно имеют выделенные блоки NPU, поэтому стоит явно указать соответствующие возможности устройств высшего уровня (по состоянию на 2020 год).

Kirin: NPU разделен на две вычислительные части: 1 Lite + 1 Tiny.

  • Da Vinci Lite оснащен 3D Cube Tensor Computing Engine (2048 MAC-адресов FP16 + 4096 MAC-адресов INT8), векторным блоком (1024-битные INT8/FP16/FP32)
  • Da Vinci Tiny оснащен вычислительным движком 3D Cube Tensor Computing Engine (256 MAC-адресов FP16 + 512 MAC-адресов INT8), векторным блоком (256-битный INT8/FP16/FP32)

Львиный зев 865: 15 ТОП.

Для сравнения (*) — характеристики ускорителей, используемых для задач ИИ:

  • Google Coral: 4 ТОП.
  • JETSON Xavier NX: 6 TFLOPS (FP16) и 21 TOPS (INT8)
  • JETSON Xavier AGX: 5,5–11 TFLOPS (FP16), 20–32 TOPS (INT8)

(*) Хорошие цифры! Но что, черт возьми, они на самом деле означают?

В вычислениях тип данных (8-битное целое число против 32-битного числа с плавающей запятой), с которым вы работаете, действительно имеет значение, поскольку ваше оборудование может быть настроено для очень быстрого выполнения операций с определенными типами данных. Или нет.

Следовательно, необходимо немного новой терминологии:

  • TOPS — операций terra в секунду ~ пропускная способность операции.
  • MAC= операция умножения-накопления
  • FMA (плавное умножение–сложение) — большинство современных аппаратных архитектур используют инструкции для операций с тензорами. FMA вычисляет: a*x+b как одну операцию. Примерно GMAC = 0,5 * GFLOP.

Бонусный момент — вы не можете напрямую сравнивать эти цифры для разных аппаратных средств. Есть и другие факторы, резко влияющие на реальную производительность — связанные с копированием данных туда и обратно и возможностями другого оборудования, задействованного в пост- или предварительной обработке.

Как и во многих подобных случаях — это была веская причина просто попробовать — поэтому мы подготовили Raspberri Pi с Google Coral (🙈), и началось веселье.

Фреймворки машинного обучения для мобильных устройств — действительно ли есть выбор?

Прежде всего, выделим два варианта использования:

  • вывод — когда у вас есть модель и вы хотите запустить ее на устройстве
  • обучение — когда у вас нет модели (но хочется иметь!)

Большинство мобильных платформ машинного обучения не поддерживают обучение на устройствах.

Существует подавляющее большинство различных устройств — читается как различное оборудование — устройства верхнего уровня имеют NPU и GPU, а младшие иногда могут полагаться только на CPU. Наличие необходимого оборудования не обязательно означает, что программный уровень может правильно использовать его на месте. т.е. это ВАША обязанность убедиться, что приложение так или иначе будет работать на устройстве пользователя.

Существует ряд библиотек и пакетов SDK для конкретных поставщиков, которые могут помочь вам ускорить определенные вычисления на оборудовании конкретного поставщика. С одной маленькой оговоркой — все они работают следующим образом:

вы создаете модель –› затем конвертируете в формат, специфичный для фреймворка –› затем вы должны выполнить развертывание в среде выполнения, специфичной для фреймворка устройства, которая знает, как выжать дополнительные операции из поддерживаемого оборудования под ним:

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

Один из возможных обходных путей здесь — подготовить набор моделей, адаптированных для разных устройств — чтобы при запуске приложения вы могли задать этот экзистенциальный вопрос — Где я работаю и к чему у меня есть доступ и вытащить из своего зоопарка моделей то, что может есть. наилучшее соответствие» и откат к ЦП только в случае отсутствия доступных оптимизированных версий.

Есть open source — TVM — и собственные решения, которые пытаются делать именно это — берут вашу модель и оптимизируют ее под разное железо.

Иногда даже не нужно идти по этому тернистому пути — если то, что вы хотите сделать с помощью ML, полустандартно — возможно, вы можете попытать счастья с полуготовыми решениями из отрасли: ML Kit, Create ML, МедиаПайп. Некоторые из них могут обслуживать ваши модели через API, а также вы можете попробовать их обучить, отправив размеченные данные: Firebase ML, Lobe.ai, MakeML.

Если вы хотите изучить, какие варианты у вас есть для независимой от поставщика установки, чтобы запустить ее полностью в автономном режиме, выбор на самом деле не такой уж большой:

Каково золотое правило выбора технологического стека для важного срочного проекта? Используйте то, с чем вы знакомы! Вот как мы начали с tensorflow lite.

Темное искусство преобразования моделей

Перво-наперво — вы не можете просто запустить свою модель keras в TF lite — вам нужно преобразовать ее в формат tflite.

И угадай что? — после конвертации это будет другая модель. С разной точностью и отзывом.

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

Термин «поддерживаемые операции» неоднозначен — помните, где-то выше я упоминал, что аппаратно может поддерживать работу, а софт — нет? Ну, может случиться и обратное (но мы доберемся до этого через минуту)!

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

Когда модель окончательно сконвертирована — на самом деле ничего еще не закончено — теперь вам нужно убедиться, что

  • он может работать на реальном устройстве
  • он дает результат, более или менее близкий к тому, что сделала ваша модель keras

На самом деле, у вас есть возможность запустить интерпретатор TF Lite на вашем ноутбуке\настольном компьютере, однако он вообще не оптимизирован для такого случая, и время вывода может сильно повлиять на вашу прокрастинацию, но вы сможете получить первое представление о фактическое качество вывода (но на целевом устройстве он все равно будет вести себя по-разному из-за другого оборудования и делегатов :D ).

Еще одно ложное предположение, которое у нас было — что мы можем протестировать преобразованную модель, используя доступные одноплатные компьютеры (читай Raspberry Pi) и TPU, поддерживающие Tensorflow Flow Lite (читай Google Coral). Изначально идея была многообещающей — дружественная Linux-система установлена ​​и работает, совместимая архитектура процессора — ARMv8. Но характеристики процессоров намного ниже, чем у современных телефонов: меньше ядер, нет мобильного GPU, а производительность блоков TPU кажется избыточной по сравнению даже с лучшим порядковым GPU — т.е. мы не можем разумно оценить, что мы можем или не можем делать на реальные клиенты.

Но главное — и урок, который мы усвоили на собственном горьком опыте, — когда что-то работает на Raspberry с Coral — это не обязательно означает, что оно будет работать гладко (или вообще! :D) на смартфонах.

Блин, ладно, у меня есть код на python и cpp, модель TF Lite и два устройства с Android и iOS, что дальше?

Этот бит может быть на удивление простым (*) — вам просто нужно создать соответствующий настольный инструмент из исходного дерева Tensorflow:

(*) легко, если вы хотите познакомиться с bazel как с инструментом goto для построения монорепозитория, если вам нравится гибкость adb и вы не против подправить проект XCode — например, исключить эмулятор из таргета.

Не уверен, что считаю инструмент iOS очень полезным, так как он работает как черный ящик — не позволяет указать, где именно вы хотите запустить свою модель. Но какой полезный результат этого упражнения — узнать, что в iOS вы не запускаете модель tflite напрямую — после запуска приложения она конвертируется в формат CoreML, и эта модель будет использоваться для вывода.

С другой стороны, с помощью стендового инструмента для Android вы можете напрямую изучить, что произойдет, если вы попытаетесь запустить свою модель на NPU\GPU\CPU.

Эти ранние эксперименты были для нас настоящим ключом, хотя и открыли печальную правду:

ERROR: Attempting to use a delegate that only supports 
static-sized tensors with a graph that has dynamic-sized tensors.

и

ERROR: NN API returned error ANEURALNETWORKS_OP_FAILED at line 3779 
while completing NNAPI compilation.
ERROR: Node number 536 (TfLiteNnapiDelegate) failed to prepare.

В логах logcat нам удалось найти нечто более конкретное:

07-17 15:44:42.210 14380 15006 I ExecutionPlan: Device qti-dsp can't do operation MAX_POOL_2D

В некоторых случаях — бывает и хуже — т.е. поддерживает какие-то операции на NPU, какие-то на GPU, а остальные на CPU.

INFO: CoreML delegate: 41 nodes delegated out of 315 nodes, with 46 partitions.

Из моего прошлого опыта работы с GPU, а более позднего в рамках Spark и распределенных вычислений — я помню одну важную вещь — время ввода-вывода — для передачи данных на ускоритель\вычислительный узел — может пренебрегать и резко снижать производительность таких вычислений.

т.е. возможно, будет быстрее выполнять все на ЦП, чем выполнять одну часть вычислений на ЦП, а другую часть на ГП.

Еще один интересный момент — делегаты: допустим, в вашей сети есть какая-то операция — например, ReLu. TF lite может попытаться использовать свой собственный код, чтобы выразить это с помощью простых математических операций, или, если вам повезет (?) — вы можете делегировать эти вычисления оптимизированной библиотеке, которая умеет использовать инструкции процессора для повышения производительности. Итак, у вас есть делегаты NNAPI для Android, делегаты CoreML для iOS, которые пытаются выбрать лучшее оборудование для ваших операций, или выделенные делегаты для GPU или CPU.

Для того, чтобы преодолеть заминки конвертации-совместимости — прямого пути к успеху нет — это действительно вопрос проб и неудач: когда вы используете другой формат (сохраненная модель — или h5 — или pb — просто или протокольный буфер) полученная модель может отличаться (очень!).

Я слышал забавные истории, когда людям приходилось запускать цепочку преобразований, чтобы получить совместимый набор операций: Pytorch -> Onnx -> CoreML и указать конкретную версию opset или делать удивительные вещи, такие как настройка операции из a - b в a + (-b), чтобы модель успешно работала. .

В наших случаях приходится отказываться от идей использования NPU для вычислений — в первую очередь из-за проблем с совместимостью операций — т.е. например, 2D max pooling в NNAPI работает только с входным тензором с рангом равным 4 и расположение данных должно быть таким, которого ожидает реализация NNAPI.

Следовательно, вы не можете подготовить одну модель и быть уверенным, что она будет работать на всех устройствах. Усилия, необходимые для настройки модели для конкретного NPU, не перевешивают (пока?) ее возможное преимущество в скорости. GPU, тем не менее, показывает весьма впечатляющие параметры — в наших бенчмарках в среднем мы наблюдаем ускорение в ~x5 раз по сравнению с CPU. Теперь большая часть нашей сети успешно работает на графическом процессоре (ну, на данный момент у нас нет связанных с этим отчетов об ошибках!)

Но когда модель работает — это еще не значит, что она будет работать!

Все эти делегаты должны поддерживать операции в вашей сети и при всей оптимизации должны возвращать одинаковые результаты — в противном случае накопленные отклонения точности могут привести к неправильной метке класса в конце — это как раз тот случай, который укусил нас по ходу дела. путешествие.

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

И для этого могут пригодиться еще несколько интерактивных приложений.

Но как на самом деле это запустить — т.е. у вас есть бизнес-логика в Java\Kotlin или Swift\Objective-C или, может быть, флаттер \ реагировать нативно на клиенте, а там код на питоне с реальным конвейером, который немного больше, чем просто запустить это модель?

Наш подход заключался в том, чтобы встроить все в старую (?) хорошую (?) библиотеку C++, т. е. единую кодовую базу — единую точку входа для взаимодействия клиентов с функциями машинного обучения.

Единая кодовая база — в теории была хорошей идеей, но на деле приводит к небольшим последствиям:

  • вы должны скомпилировать его для целевой арки — добро пожаловать в мир кросс-компиляции!
  • чтобы использовать его на устройстве — вы также должны связать его со всеми необходимыми зависимостями — например, Tensorflow lite и OpenCV и их сторонние зависимости!

Я упоминал, что в репозитории Tensorflow Bazel является первоклассным гражданином, а старый (?) хороший (?) CMake не так поддерживается, поэтому нам нужно подправить Tensorflow немного (и, к сожалению, это не все, что было необходимо — не было возможности подготовить оставшиеся биты), чтобы это произошло.

Немного позабавившись с Docker — мы подготовили образ со всем необходимым, чтобы использовать его в нашем CI для тестов.

А затем начните обращать внимание на фактические результаты тестов и размер модели. Обычно они довольно родственны.

Наверняка вы знаете о TensorRT, который может быть удобен для оптимизации модели на устройстве Cuda, для периферии вы все еще можете использовать его для подготовки модели перед преобразованием и применять аналогичные настройки для оптимизации модели:

  • Квантование
  • Обрезка модели
  • Дистилляция знаний

Что было для нас действительно прорывом — количественное осознанное обучение, которое помогает сократить размер модели со 150 МБ до ~ 1 МБ без заметной потери точности.

Каждый Ага!/Ой!!! момент в истории выше был для нас поворотным моментом — когда мы натыкаемся на контрольно-пропускной пункт, мы всегда останавливаемся, ругаемся (вздох) и решаем, как нам двигаться дальше — учитывая другие проекты и приоритеты, должны ли мы выделять какой-то бюджет времени на следующий шаг( с)?

PS. Хотя мы все еще ломаем голову над потоком пользователей через приложение с UX-дизайнерами — мы не затрагивали тему модели защиты устройства (шифрование, обфускация) — с чем определенно не приходится иметь дело облачным решениям. Однако, учитывая все, что написано выше — возможно, люди, которые могут понять из структуры модели и разобрать код на С++ внутри пакета мобильного приложения — как его использовать — лучше работать с нами? :)