Почему одна модель на весь парк камер не работает
Модель, обученная на объединённых кадрах всего парка, на отдельных камерах работает заметно хуже нужного уровня. В проектах, которые описывает AWS, это заканчивалось одним и тем же: каждая камера получала собственную дообученную модель (AWS Machine Learning Blog).
Типичный старт такого проекта: proof of concept на одной камере проходит, завод просит повторить результат на 40 линиях, а на каждой линии стоит несколько камер. Дальше выясняется, что скопировать одну модель на весь парк нельзя, сцены различаются даже внутри одного цеха.
Причины конкретные и воспроизводимые: у камер разный угол обзора, разные блики на одной и той же поверхности из нержавеющей стали, разное окружающее освещение в зависимости от того, какая дверь бокса открыта. Различия систематические, они повторяются изо дня в день. Общая модель усредняет их и теряет чувствительность к дефекту на каждой отдельной камере.
На практике это выглядит так: одна модель на парк даёт повышенную долю пропусков именно на камерах, которые сильнее всего отличаются от среднего по парку. Такие камеры найдутся всегда. Per-camera дообучение убирает усреднение, но добавляет жизненный цикл: у каждой модели свои обучение, проверка, компиляция, версия и откат.
Что именно ломает общая модель
Факторы делятся на три группы. Геометрия сцены: угол обзора и перспектива меняют форму одного и того же дефекта на уровне пикселей. Оптика и отражения: блики на металле уходят в другие области кадра, и признак «тёмное пятно рядом с кромкой» перестаёт работать. Освещение: открытая дверь бокса меняет цветовую температуру и уровень засветки, а вместе с ними и порог, при котором детектор срабатывает.
Общая модель вынуждена искать признаки, устойчивые сразу ко всем вариантам съёмки. Для редкого дефекта это плохой компромисс: то, что помогает на одной камере, на другой превращается в источник ложных срабатываний. Дообучение на кадрах одной камеры позволяет подстроиться под её геометрию, блики и свет без оглядки на остальной парк.
Когда per-camera модель не нужна
Признаки, при которых подход избыточен: камеры стоят в одинаковых условиях (одна высота, один угол, стабильный свет), парк небольшой, цена пропущенного дефекта ниже стоимости инфраструктуры. В такой конфигурации одна модель плюс мониторинг дрейфа дадут сопоставимый результат дешевле.
Подход плохо масштабируется по числу сущностей. Каждый запуск пайплайна потребляет вычислительные ресурсы, каждая камера занимает свою цепочку версий в реестре, каждый параллельный запуск держит слот в оркестраторе. Per-camera схема окупается качеством на каждой камере, и эту цену стоит считать заранее.
Обзор референсной архитектуры AWS на SageMaker SDK v3
Архитектура связывает пять сервисов в один цикл: SageMaker Pipeline обучает и проверяет модели, Model Registry хранит версии с метаданными камеры, SageMaker Neo компилирует одобренную модель под конкретное edge-устройство, Step Functions ведёт очередь переобучения по парку, а разворачивается всё через AWS CDK.
Ключевое свойство цикла: в реестр попадают только скомпилированные модели. Каждый одобренный пакет уже содержит артефакт, готовый к выгрузке на устройство, поэтому следующий запуск стартует с него без отдельной операции сборки.
Компоненты и их роли
| Компонент | Роль в жизненном цикле |
|---|---|
| Amazon SageMaker SDK v3 | код шагов пайплайна, синтез и запуск |
| Amazon SageMaker Pipeline | обучение и проверка, 13 шагов за запуск, параметр - камера |
| SageMaker Model Registry | версии моделей с метаданными camera ID, база для warm-start |
| Amazon SageMaker Neo | компиляция под настроенную edge-цель |
| AWS Step Functions | очередь запросов на переобучение и ограничение параллельной работы |
| AWS Cloud Development Kit (AWS CDK) | развёртывание всей инфраструктуры примера |
Почему Edge Manager заменён на Neo
Amazon SageMaker Edge Manager устарел, и в этой архитектуре его место занимает Amazon SageMaker Neo для компиляции моделей под edge-устройства. Для читателя это означает конкретную вещь: гайды, написанные вокруг Edge Manager, придётся переписать под Neo, включая упаковку артефакта и настройку цели компиляции.
Двухветочный SageMaker Pipeline: 13 шагов от кадров до одобренной модели
Обучение собрано в один SageMaker Pipeline, параметризованный камерой, на каждый запуск приходится 13 шагов. Внутри запуска работают две ветки: детектор аномалий на небольшом свёрточном автоэнкодере и классификатор ResNet18, дообученный подтверждать дефект. Каждая ветка проходит свой путь обучения, экспорта в ONNX, оценки и проверки качества, после чего модель компилируется через Neo под edge-цель и регистрируется в Model Registry.
Параллельные входные шаги: Preprocess и fetch последних моделей
Три шага стартуют одновременно: Preprocess, Fetch Latest Anomaly и Fetch Latest Classifier. Fetch-шаги идут в реестр за последней одобренной моделью этой камеры, Preprocess готовит данные. Параллельный старт вместо последовательного сокращает длительность каждого запуска, а при парке в десятки камер экономия умножается на число запусков.
Ветка автоэнкодера: детектор аномалий по ошибке реконструкции
Небольшой свёрточный автоэнкодер учится воспроизводить нормальный продукт. На инференсе он восстанавливает кадр и сравнивает результат с входом: высокая ошибка реконструкции означает подозрение на аномалию. Для обучения детектора достаточно кадров без дефектов, размечать сам дефект не требуется.
Дальше ветка экспортирует модель в ONNX, оценивает артефакт на отложенных данных и проходит quality gate.
Ветка ResNet18: классификатор, подтверждающий дефект
ResNet18 дообучается подтверждать дефект. Связка работает как двухступенчатый фильтр: автоэнкодер ищет всё подозрительное и потому даёт много срабатываний, классификатор отсекает ложные. Разделение обязанностей полезно для производства: пропуск дефекта стоит дороже лишней проверки оператором, поэтому первая ступень настроена на полноту, а вторая отвечает за точность.
У этой ветки те же шаги после обучения: экспорт в ONNX, оценка на held-out данных, quality gate.
Экспорт в ONNX и оценка именно экспортированного артефакта
Обе ветки оценивают не исходную модель, а ONNX-артефакт. Смысл в том, что проверку проходит ровно то, что поедет на устройство. Ошибки конвертации (несовпадение операций, другая нормализация, иная форма входа) на исходной модели не видны, а после компиляции проявятся уже на камере. Оценка на экспортированном файле ловит их на этапе пайплайна.
Quality gate: почему accuracy обманывает и что проверять вместо неё
В опубликованном фрагменте материала конкретный набор метрик quality gate не расписан. Логика, которая нужна при редком дефекте, строится вокруг balanced accuracy и recall по дефектному классу, и вот почему обычная точность здесь плохой советчик.
Ловушка обычной accuracy при редком дефекте
Возьмём 1000 кадров, из которых 10 содержат дефект. Модель, всегда отвечающая «норма», даёт accuracy 99% и ноль пойманных дефектов. Recall по дефектному классу равен 0%. Balanced accuracy считается как среднее recall по классам: (0 + 1) / 2 = 50%. Одна и та же модель показывает 99% и 50% в зависимости от метрики, и второе число честно говорит, что дефекты она не находит.
| Метрика | Что показывает | Слабое место |
|---|---|---|
| Accuracy | доля верных ответов по всем кадрам | при 1% дефектов модель «всегда норма» даёт 99% |
| Recall по дефектному классу | какую долю реальных дефектов поймали | ничего не говорит о цене ложных срабатываний |
| Balanced accuracy | среднее recall по классам | не различает цену ошибок разных классов |
Практический вывод: accuracy годится как справочная цифра, порог отсева ставят по метрикам, которые не дают редкому классу раствориться в фоне. Как балансировать recall и precision в задачах с проверяемым результатом, разобрано на примере reward-функции в материале про кастомизацию Qwen3-8B в SageMaker.
Как метрики встроены в пайплайн
Gate стоит после оценки ONNX-артефакта и до компиляции Neo и регистрации. Модель ниже порога не попадает в реестр, а значит не станет warm-start для следующего запуска: плохая версия не тянет за собой всю дальнейшую историю камеры. Конкретные значения порогов в источнике не приводятся, их выбирают по цене пропуска и цене ложного срабатывания на конкретной линии.
Model Registry и warm-start: как метаданные камеры превращаются в per-camera историю
Пакеты моделей несут camera ID в качестве метаданных, а выборка warm-start для каждой ветки фильтрует по этому идентификатору. Так общий поток версий превращается в отдельную историю для каждой камеры.
Зачем camera ID в метаданных пакета
Без метаданных версии лежат одной кучей, и Fetch Latest Anomaly вернёт модель последнего запуска, возможно с другой камеры. Старт с чужой модели означает перенос чужих бликов и геометрии, то есть возврат к тому самому усреднению, от которого уходили. Один идентификатор в пакете решает эту проблему на уровне фильтра.
Цикл warm-start от запуска к запуску
- Step Functions отправляет пайплайн в работу с параметром camera_id.
- Fetch Latest Anomaly и Fetch Latest Classifier берут последнюю одобренную модель по этому camera_id.
- Обе ветки дообучаются от полученных весов.
- Модели экспортируются в ONNX и оцениваются на отложенных данных.
- Срабатывает quality gate.
- Прошедшая модель компилируется через SageMaker Neo под настроенную edge-цель.
- Пакет регистрируется в Model Registry с camera_id в метаданных.
- Следующий запуск начинается с шага 2 и берёт уже эту версию.
Компиляция стоит перед регистрацией намеренно: в истории камеры остаются только артефакты, которые прошли и проверку качества, и сборку под устройство. Для первой камеры в цепочке истории ещё нет, поэтому стартовые веса приходят из базовой модели. Как это реализовано в коде примера, стоит смотреть в самом репозитории.
Оркестрация парка: Step Functions и семафор в DynamoDB
Слой оркестрации на AWS Step Functions ставит запросы на переобучение в очередь и ограничивает параллельную работу в пределах квот аккаунта. Без такого ограничителя парк камер упирается в лимиты на инстансы и параллельные job'ы, и запуски начинают падать с ошибками квот вместо того, чтобы просто подождать.
Зачем семафор именно в DynamoDB
Механику семафора в DynamoDB опубликованный фрагмент источника не детализирует, поэтому описанную ниже схему нужно сверить с кодом примера. Идея простая: в таблице хранится счётчик занятых слотов, перед стартом Step Functions делает условную запись (захват слота), после завершения пайплайна счётчик уменьшается. Потолок счётчика равен числу параллельных job'ов, которое выдерживают квоты аккаунта. DynamoDB здесь удобна тем, что условная запись даёт атомарный захват без отдельного сервиса блокировок.
Поток выглядит так: запрос на камеру попадает в очередь, проверяется семафор, при свободном слоте стартует пайплайн, по завершении слот освобождается. Запрос, которому слота не хватило, ждёт в очереди, а не падает.
Практические подводные камни SageMaker SDK v3 и Neo
Два места, где легко потерять время при переносе примера в свой аккаунт. В опубликованном фрагменте источника детали не раскрыты, поэтому ниже чек-лист для проверки на своей версии SDK и Neo, а не цитата.
Валидация роли при синтезе пайплайна
Роль исполнения проверяется на этапе синтеза пайплайна, до первого запуска, поэтому ошибки в правах всплывают раньше, чем начнётся обучение. Проверять стоит сразу: доступ к бакету с кадрами и артефактами, права на образы тренировочных контейнеров, работу с Neo и запись в Model Registry. Откладывать это на первый боевой запуск дорого, потому что пайплайн упадёт на синтезе и не покажет, где именно не хватает прав.
Требования Neo: тарбол и фиксированные формы
Neo принимает модель в виде входного тарбола, а формы входа должны быть фиксированными. Практика: зафиксировать input shapes ещё на экспорте в ONNX (батч 1, конкретные высота и ширина), собрать тарбол по требованиям Neo до вызова компиляции. Иначе компиляция упадёт после успешно пройденного gate, то есть в самом неудобном месте цикла, когда модель уже признана годной.
Развёртывание примера и стоимость прогона
Всё разворачивается через AWS Cloud Development Kit (AWS CDK), полный пример доступен в репозитории aws-samples на GitHub. Полный прогон пайплайна на синтетических данных стоит около $0.07 вычислительных затрат (AWS Machine Learning Blog).
Что даёт прогон на синтетике
Синтетика прогоняет все 13 шагов и проверяет инфраструктуру: шаги стартуют в нужном порядке, ONNX-артефакт экспортируется, quality gate срабатывает, Neo компилирует модель, пакет появляется в реестре с camera ID, Step Functions ведёт очередь и держит лимит слотов. Качество модели на синтетических кадрах ничего не говорит о качестве на реальной линии.
Семь центов относятся к прогону на синтетике, а не к эксплуатации парка. На реальных данных добавляются хранение и обработка кадров, обучение на настоящих объёмах и компиляция под каждую камеру, поэтому бюджет production-развёртывания считается отдельно.
Ограничения подхода и когда он не окупается
Стоимость и сложность растут вместе с числом камер: свой запуск пайплайна, своя цепочка версий в реестре, свой слот в оркестрации. Добавьте edge-таргет: Neo компилирует под конкретное устройство, и если железо на линиях разное, компиляций становится больше. Ещё один пункт, который часто недооценивают: quality gate требует отложенных размеченных данных по каждой камере, иначе порог не на чем проверить.
Отдельное ограничение связано с устареванием Edge Manager: материалы, написанные вокруг него, придётся переписать под Neo, включая упаковку и настройку цели компиляции. И общая рамка: источник описывает референсную архитектуру и пример, а не гарантированный результат в произвольном производстве.
Кому подходит, а кому нет
Подходит паркам с систематически разными сценами, где цена пропущенного дефекта высока: контроль дефектов на металле, линии с разным светом и геометрией съёмки, несколько камер на одну линию. Дополнительные условия: есть размеченные отложенные данные по камерам и понятный edge-таргет под Neo.
Не подходит, когда камеры стоят в одинаковых условиях, парк ограничен несколькими устройствами или цена ошибки низкая. Здесь проще вести одну модель с мониторингом дрейфа.
Самый дешёвый способ проверить решение у себя: развернуть пример через CDK, прогнать пайплайн на одной камере и посмотреть, проходит ли модель gate на ONNX-артефакте. Если проходит, раскатывать на парк через Step Functions с ограничением параллелизма становится задачей настройки, а не эксперимента.