Почему конвертация модели в Core ML ломается на проверке
Конвертация модели в Core ML выглядит как один вызов конвертера, но ошибка при переносе модели почти никогда не возникает на этом шаге. Первый барьер — неподдерживаемые операции: исследовательский прототип обычно содержит слои, для которых в Apple нет прямого аналога, и конвертер либо останавливается, либо молча подставляет упрощённую замену. Модель собирается и запускается, но считает уже другое — на этом расходятся ожидания и реальность.
Второй барьер — расхождение результатов. При переносе меняются вычислительные типы: обучение идёт на полной точности, на устройстве включается половинная, а с ней — другое округление и порядок операций. Разница, которая в тестовой среде выглядит третьей цифрой после запятой, на выходе превращается в другой класс или смещённую рамку. Поэтому проверка на устройстве обязана идти не на одном удачном примере, а на наборе эталонных ответов, снятых до конвертации.
Третий барьер — условия реальной эксплуатации. Устройство ограничено по памяти, нагревается и сбрасывает частоты, камера и микрофон отбирают ресурсы, приложение сворачивают в фоне. Модель, стабильная на стенде, в бою даёт задержки и отказы; часть дефектов видна только в логах на живых сборках.
Разбираем, как это закрывается: разбор графа на несовместимые узлы, замена их эквивалентными, тесты на паритет ответов и профилирование на реальных моделях устройств.
Что даёт оптимизация: скорость, отклик, ресурсы устройства
Локальный запуск модели меняет профиль приложения сильнее, чем кажется на этапе прототипа. Вычисления идут на самом устройстве через Core ML, поэтому время отклика перестаёт зависеть от качества сети: кадр или текст обрабатывается за доли секунды, а не после круга до сервера и обратно. Пользователь видит реакцию интерфейса сразу — на этом уровне разница между «работает» и «работает приятно» становится очевидной.
Отдельно считаем расход батареи. Неквантованная модель на каждом кадре нагружает вычислитель по максимуму, и устройство греется уже через несколько минут работы. После конвертации и подбора типа вычислений (процессор, графика, нейромодуль) нагрузка ложится на профильный блок чипа, а заряд расходуется заметно ровнее при том же качестве ответа.
Объём приложения — третья метрика, которую видно в отчётах магазина. Вес модели входит в сборку и напрямую влияет на долю отменённых установок: чем больше пакет, тем чаще пользователь прерывает загрузку. Сжатие весов и отказ от неиспользуемых слоёв уменьшают вклад модели в размер сборки в разы, а тяжёлые ветки можно догружать по требованию — уже после первого запуска.
Часть отказов при этом уходит целым классом. Пропадают таймауты, сетевые ошибки и недоступность сервиса на стороне сервера: сценарий работает офлайн — в метро, в самолёте, на слабом канале. Остаются только отказы, связанные с данными и памятью устройства: неподходящий вход, редкий формат, нехватка ресурсов на старых моделях — их закрываем проверками и запасным путём обработки.
Варианты конвертации: на устройстве, в облаке или смешанный режим
Конвертация модели в Core ML формально даёт один артефакт, но исполняться он может в трёх разных режимах — и это разные архитектурные решения, а не переключатель в настройках. Режим определяет, где живут веса, как обновляется модель после дообучения и какие требования предъявляются к памяти и питанию устройства.
| Режим | Когда подходит | Ограничения |
|---|---|---|
| Локальный запуск | Персональные данные не должны покидать устройство, нужен отклик без сети, аудитория на актуальной линейке | Размер модели упирается в доступную память; тяжёлые сценарии греют корпус и расходуют батарею; обновление только вместе с релизом приложения |
| Облачный запуск | Тяжёлые вычисления, редкие дорогие операции, нужна смена модели без выпуска новой сборки | Требуется сеть, отклик зависит от канала связи, данные уходят на сервер |
| Смешанный режим | Частые лёгкие операции — на устройстве, тяжёлые — на сервере | Дороже в разработке: две ветки вычислений, синхронизация версий, единая схема предобработки данных |
Выбор режима исполнения начинается не с модели, а с ограничений продукта: чувствительность данных, допустимая задержка отклика, требования к приватности. Дальше мы считаем бюджет памяти и нагрева для целевой линейки устройств и только после этого решаем, что выносить на сервер, а что оставлять локально.
Этапы работы: аудит, схема, сборка, проверка, передача
Любая оптимизация начинается с замеров, а не с пересборки модели: без цифр по времени отклика, памяти и нагреву непонятно, где узкое место — в графе вычислений, в весах или в том, как приложение обращается к модели. Поэтому работа идёт по фиксированным этапам, и на каждом остаётся артефакт, который можно проверить.
Как выглядит работа по шагам
- Аудит текущего решения — разбираем, как модель обучалась и в каком виде её отдаёт команда, какие слои не переносятся напрямую и где возможна потеря точности.
- Профилирование на целевых устройствах — снимаем время отклика, потребление памяти и нагрев на реальных телефонах и планшетах, а не на тестовом стенде.
- Схема преобразования — фиксируем, какие операции заменяем в графе, где квантуем веса и какой запас по точности считаем допустимым.
- Конвертация модели в Core ML — собираем пакет, проверяем поддержку операций и сверяем выходы с исходной моделью на контрольном наборе примеров.
- Сборка под устройство — компонуем модель с приложением, выбираем режим ускорения и проверяем холодный старт.
- Проверка на реальных сценариях — прогоняем редкие и шумные входные данные, смотрим поведение при нехватке памяти и переключении между приложениями.
- Приёмка результата — сравниваем метрики до и после по одной методике, передаём конфигурации, сборочные инструкции и отчёт, а при расхождении откатываемся на предыдущую сборку.
Артефакты проекта: конфигурации, схемы, регламенты, документация
Конвертация модели в Core ML — только верхний слой работы. Без описания того, как сборка воспроизводится, следующее обновление превращается в переписку с подрядчиком, поэтому после сдачи у заказчика остаётся весь контур: конфигурации сборки, схемы, правила версионирования и регламент обновления.
- Конфигурации сборки — как модель и обвязка собираются под нужную версию системы и разрядность устройства, с зафиксированными зависимостями: повторная сборка даёт тот же результат.
- Схемы обработки данных — предобработка, нормализация и постобработка выходов, с указанием точек вызова модели в приложении.
- Правила версионирования — как нумеруются веса и конфигурации, что считается несовместимым изменением и как версия модели связывается с версией приложения.
- Регламент обновления — пошаговый выпуск новой версии: прогон на контрольном наборе, проверка метрик, условия отката на предыдущую сборку.
- Документация по модели — входы и выходы, ограничения по размеру и времени отклика, известные слабые места и метрики приёмки.
- Контрольный набор и тесты — фиксированные примеры входов с ожидаемыми результатами, чтобы увидеть расхождение до выката.
- Схема интеграции — точки вызова, обработка ошибок и поведение при отказе модели в приложении.
Комплект лежит в репозитории заказчика рядом с кодом, поэтому обновление модели остаётся обычной инженерной задачей, а не отдельным проектом с нами.
Пример из практики: ускорение работы приложения после оптимизации
Проект — мобильный сервис распознавания объектов на фото: пользователь снимает кадр и ждёт результат. Изначально модель считалась на серверной стороне — кадр уходил на обработку и возвращался по сети. На тестовом стенде схема выглядела рабочей, но на живых пользователях упиралась в два места: задержку отклика и потери при нестабильной связи.
Где именно теряли
Каждый запрос проходил полный круг: сжатие кадра, отправка, очередь на обработку, обратный путь. В пиковые часы очередь росла, и отклик растягивался с 0,8 до 2,5 секунды — пользователь успевал закрыть приложение. На мобильной сети часть запросов обрывалась на середине: около 6,5% операций заканчивались неуспехом. Это класс отказов, который на серверной стороне не лечился — причина была в канале, а не в самой модели.
Что изменили
Вывод модели перенесли на само устройство: конвертировали сеть в Core ML, сжали веса, снизили точность вычислений там, где это не влияло на распознавание, предобработку кадра вынесли в отдельный поток. Кадр больше не покидает устройство — ушли и очередь, и сетевой круг.
Отклик сократился в 8-9 раз, с 0,8 до 0,09 секунды. Доля неуспешных операций упала до 0,4%, размер модели на устройстве уменьшился с 240 до 70 МБ, а нагрузка на серверный контур снизилась настолько, что его мощность перестали наращивать по мере роста аудитории. Качество распознавания на контрольной выборке при этом не просело — это проверяли отдельным прогоном до выката.
Что делать, если приложение уже использует другую среду исполнения?
Переписывать приложение целиком не нужно: среда исполнения — это слой вывода модели, а не бизнес-логика. Экраны, работа с камерой и хранение данных остаются прежними, меняется только то, что стоит за вызовом «получить предсказание». Объём работ зависит от того, насколько исходная модель опирается на возможности прежней среды.
Пересборка готовой модели — базовый сценарий. Если архитектура собрана из стандартных слоёв, веса переносятся как есть, а выходы совпадают с прежними в пределах допустимого расхождения. Переход без переписывания держится на адаптере вызова: входные и выходные тензоры приводятся к прежним типам, остальной код не трогаем.
Дообучение требуется, когда часть операций целевая среда не поддерживает напрямую: их заменяют эквивалентными и доучивают модель на тех же данных, чтобы вернуть исходное качество. Повторное обучение и пересмотр архитектуры — для моделей, завязанных на серверные особенности: динамические формы входа, нестандартные преобразования признаков.
| Вариант | Когда подходит | Ограничения |
|---|---|---|
| Пересборка готовой модели | Стандартные слои, веса без изменений | Не проходят редкие операторы |
| Дообучение | Часть операций заменена эквивалентными | Нужна обучающая выборка и прогон проверки |
| Повторное обучение | Архитектура завязана на серверную среду | Дольше, требует сверки метрик с текущей версией |
| Пересмотр архитектуры | Модель целиком переезжает на устройство | Меняются требования к памяти и размеру сборки |
Порядок один: сначала измеряем расхождение выходов на контрольном наборе, и только при выходе за порог идём в дообучение или пересборку. Так переход укладывается в дни и не требует переписывания приложения.
Ограничения, совместимость и требования к данным
Не каждый граф вычислений переносится на устройство напрямую: часть операторов не имеет аппаратной реализации, и конвертер либо заменяет их цепочкой поддержанных, либо уводит расчёт в медленный путь. Мы заранее строим карту операций и показываем, что останется на устройстве, а что придётся переписать.
Требования к данным проверяем до старта: формат разметки, баланс классов, доля пропусков, совпадение распределений в обучающей и проверочной выборках. Если выборки собирались разными способами, просадка после конвертации в Core ML окажется следствием данных, а не оптимизации — это видно на разборе, а не после релиза.
Какие операции не переносятся на устройство?
Динамические формы тензоров, нестандартные слои внимания, собственные операторы. Их либо выражают через поддержанные, либо оставляют на серверной стороне — решение принимаем по замеру качества и времени отклика.
Как проверяется качество после оптимизации?
Готовим эталонный набор входов, фиксируем ответы исходной модели и сравниваем с ответами сконвертированной: расхождение по целевой метрике, доля несовпавших ответов, поведение на краевых примерах. Отдельно прогоняем на реальных устройствах целевого парка.
Что с устройствами прошлых поколений?
Собираем матрицу совместимости: на каких поколениях и версиях системы модель работает, где включается резервный путь. Для слабых устройств заранее готовим облегчённую ветку, чтобы приложение не теряло функциональность.
Обсудим задачу: что нужно для оценки сроков
Срок оценки по переносу модели на устройство определяется не её размером, а числом слоёв, у которых нет штатного отображения в Core ML, и объёмом предобработки входных данных. Чем раньше мы видим архитектуру и живые примеры, тем меньше в плане запаса на неизвестность. Ниже — что достаточно прислать, чтобы мы вернулись с планом работ, а не с широким диапазоном.
- Архитектура и веса обученной модели: стек обучения, скрипт сборки графа, чекпойнт, список нестандартных операций.
- Набор реальных входных данных с ожидаемыми ответами — 100–300 примеров хватает, чтобы поймать расхождение численных результатов после конвертации.
- Метрики приёмки: доля верных ответов, допустимое расхождение с исходной моделью, требования к времени отклика и расходу батареи.
- Сценарий работы на устройстве: полностью локальный вывод, подгрузка обновлённых весов или гибрид с обращением к серверу.
- Ограничения: поддерживаемые версии системы, парк устройств, размер приложения, работа без сети.
- Доступы: репозиторий, среда сборки, тестовый парк устройств, учётные записи для публикации.
- Требования к приватности: какие данные не должны покидать устройство.
Возвращаемся планом работ: этапы, содержание каждого, точки приёмки и то, что считаем результатом. Первый этап — пилотный: переносим одну модель, замеряем качество и скорость на живых устройствах, фиксируем расхождения. После него видно, тиражируется ли подход на остальные модели и с каким темпом, — оценка сроков становится предметной.







