- BrainTools - https://www.braintools.ru -

Как внедряется ИИ на стройке: особенности масштабирования, данных и обучения моделей под российские реалии

Процесс внедрения ИИ на стройке имеет свою специфику. Дело в том, что здесь есть свои подводные камни при масштабировании обработки видеопотоков, при самом процессе обработки данных и при дополнительном обучении [1] модели YOLO под наши российские реалии. Расскажу обо всём по порядку. 

Как происходит масштабирование обработки видеопотоков с 5 до 500 камер

На старте проекта мы имели 5–7 камер от заказчика. В таком случае в качестве архитектуры системы себя отлично показывает монолит, и вот почему: при маленьком количестве видеокамер микросервисы лишь добавляют трудностей в виде повышенной сложности разработки и затраченного времени. На раннем этапе такое не нужно: мы стремимся быстро собрать MVP‑системы. Для этого вставляли RTSP‑поток, потом прогоняли кадры через ML‑модели и формировали инциденты. Дробить архитектуру пришлось в тот момент, когда монолитом физически стало трудно управлять, а на внесение правок уходило слишком много времени.

Когда в системе оказалось больше 20 камер, поняли, что пора менять архитектуру. В этот момент часть потоков попросту начала отваливаться, их загрузка длилась до 2 минут, росла задержка от детекторов, а порой и вовсе приходилось перезапускать сервис, чтобы восстановить работу некоторых камер. Однажды новый заказчик вместо настройки платформы потребовал очередные изменения в коде. В какой‑то момент число таких изменений становится критическим, и речь уже идёт не о масштабировании продукта, а его поддержании через набор костылей. И именно тогда мы поняли: надо пересобирать архитектуру, а не чинить дыры.

Ожидалось, что самым первым не справится GPU, но он‑то как раз и продолжил работать, а вот вся обвязка вокруг него начинала подводить: ломалась запись потоков, декодирование видео и подготовка кадров. В общем из‑за большого потока данных не справился CPU.

Сразу скажу, что камеры никогда не работают нормально. А мы изначально старались работать практически в режиме real‑time, но быстро поняли, что необходима буферизация. Однако тут главное — не перестараться, потому что нет никакого смысла обрабатывать по минуте то, что происходило эту самую минуту назад. Уж лучше потерять несколько кадров.

Наш основной стек мы построили вокруг FFmpeg и GStreamer. Системы по мере своего роста стали чётко разделять получение потока, декодирование и непосредственно инференс. Благодаря этому получилось независимо масштабировать разные части пайплайна и изолировать проблемы с отдельными потоками или камерами. Тут есть другая проблема, а именно разные кодеки и разрешение от камеры разных производителей. Тому, что написано в паспорте камеры, быстро перестаёшь верить. На реальном объекте оказывается и H.264, и H265. Появляется разница в FPS, выявляется нестандартный GOP или нестабильный RTSP‑сервер. Так мы создали промежуточный слой обработки видеопотока. Он нормализовал параметры входных данных, и в систему передавался уже предсказуемый поток кадров.

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

Хранить все полученные видео силами системы видеоаналитики попросту бессмысленно. Заниматься задачами архива необходимо отдельному хранилищу или s3. У себя мы храним короткие фрагменты, связанные с событием, метаданные и изображения. Когда камер сотня, такие данные масштабируются намного лучше.

Появлялась и latency‑проблема: была задержка между событием на камере и алертом оператору. Тогда мы решили измерять задержку по всему пайплайну вместо одной цифры: смотрели на камеры, получение кадров, очередь, инференс, бизнес‑логику, отправку события. При таком анализе сразу видно, где появляется задержка. В такие моменты выясняется, что в большинстве случаев нейросеть не имеет никакого отношения к этой проблеме. Вообще, как показывает практика, многие проблемы зачастую находится не в нашем коде: камера может продолжать отвечать по RTSP, но продолжительное время отдавать зависший кадр. В таком случае система считает, что всё работает, и нам, помимо соединения, пришлось мониторить данные внутри потока.

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

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

Архитектуру довольно быстро удалось сделать гибкой. Мы решили так: если есть смысл, работает много камер и плохой внешний канал, то вычисления делаем непосредственно на объекте. Технически и экономически не всегда разумно гонять сотни исходных видеопотоков в облако. Хотя, как правило, канал всё же хороший, и вся обработка происходит именно у нас в облаке.

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

Данные на стройке — худшие, с которыми я работал

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

Нашим основным инструментом разметки стал CVAT. Для машинного зрения [2] он достаточно удобный, поддерживает разные типы разметки, командную работу и, за счёт трекинга и автоматической предразметки, сильно ускоряет процесс.

В первую очередь мы разметили людей и СИЗ (каски, жилеты). Потом взялись за разметку техники и сложных событий. Проблема здесь заключалась не в том, чтобы найти человека, а в том, чтобы понять, что на нём надето. Когда он занимает 50–100 пикселей в кадре, сделать это непросто.

Чтобы собрать первый датасет, мы брали реальные видео со строительных объектов наших дружественных застройщиков. Тогда поняли, что нет смысла размечать все кадры подряд: получались тысячи почти одинаковых изображений, которые не давали ничего полезного. Поэтому начали специально выбирать разные ракурсы, освещение, стадии стройки, погоду и сложные случаи. Так картина становилась намного объективнее. 

Для улучшения качества датасета мы фиксировали правила разметки и разбирали спорные примеры всей командой. Количество приграничных и спорных случаев было огромным. Человек мог нести каску в руке, каска могла сдвинуться на голове, поверх каски мог быть надет капюшон, каску могло закрыть чем‑то — и это лишь малая часть подобных примеров. В таком случае мы учили модель только после формализации бизнес‑правила. А теперь учтём, что у каждого застройщика цвета и форма касок и жилетов могут различаться. Если информации об этом нет в train, модель может начать ошибаться. Это решается только за счёт разнообразия данных.

Чтобы добавить новые классы в модель и при этом ничего не сломать, приходилось сохранять предыдущую версию дата‑сета и набор regression‑тестов по уже существующим данным. Нельзя заканчивать обучение модели только на новом классе и считать, что задача выполнена. После каждого обновления всегда проверяем, достигло ли качество новых классов определённого уровня, и нет ли просадок по precision/recall на старых классах.

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

Кстати, мы не делали отдельные модели для ночного мониторинга. Да, в датасет добавляли реальные ночные данные и соответствующие аугментации, но если ночью камера физически ничего не видит, то здесь не поможет никакая аугментация.

На качество работы системы довольно сильно влияла грязь и погодные условия. Такие проблемы, как правило, можно решить не только при помощи дополнительного машинного обучения. Качество изображений мы стали контролировать отдельно. Порой правильный алерт от системы может звучать не как «человек не надел каску», а «камера грязная, её необходимо почистить».

До первой рабочей модели прошло очень много итераций. Обычно первая модель показывает, где инструкция была неоднозначной, и мы после каждого цикла смотрим ошибки [3], периодически меняем правила разметки и добавляем те случаи, на которых модель непосредственно ошибалась. Мы продолжаем делать это уже третий год. За счёт этого удалось собрать большой датасет, благодаря которому мы не наблюдаем выраженного дисбаланса по классам и ситуации, когда модель «не видит» редкие события.

Отдельно расскажу о ложных срабатываниях. Зачастую для клиентов false positive хуже, чем частичное снижение recall. Оператор очень быстро теряет доверие к системе, если она десяток раз за смену указывает на нарушение, которого не было. В таком случае после нашего пилота мы работали именно с теми ложными срабатываниями, которые больше всего были заметны пользователю.

Подытожу. Порой несколько тысяч хороших разнообразных примеров дают намного больше информации и возможностей, чем сотни тысяч практически одинаковых кадров. Сейчас с учётом нашего опыта [4] мы сначала смотрим на вариативность задачи, а потом уже определяем, какой объём данных нам для этого нужен. Мы владеем большими данными со стройки, и эти данные мы правильно храним и размечаем, благодаря чему можем быстро собирать вариабельные датасеты под задачи заказчиков. Но всё это пришло с опытом, полученным в ходе работы с данными, имеющими большое количество особенностей.

Бывало и такое, что мы обучали модель, а данные оказывались некачественными. В таком случае приходилось их либо переразмечать, либо попросту удалять. Фактически датасет — это обычный продукт, который необходимо чистить, версионировать и периодически выбрасывать из него данные, которые не идут модели на пользу и делают её только хуже.

YOLO на стройке: как мы дообучали модель под российские реалии

В завершение хотел бы рассказать о главном инструменте. Поговорим о YOLO.

Итак, мы начали с YOLOv5. Этот стек был зрелым и понятным за счёт большого количества документации, стабильного обучения, простого экспорта и нормальной производительности на нашем оборудовании. Затем начали использовать более новые версии.

Задачи, которые мы ставили инструменту, не могли работать из коробки. Стандартные модели COCO в условиях стройки не работают так, как нужно, потому что люди в основном находятся вдалеке от камеры и выглядят слишком маленькими в кадре. К тому же они носят одежду, которая нетипична для датасета (опять же каски, жилеты, спецовки). В таких условиях ещё возможно обнаружить человека, но для детекции других объектов, связанных с реальными условиями на стройплощадке, необходимо дообучать на уже имеющихся собственных данных. 

Вообще базовая модель YOLO в принципе не обучена на детекцию касок как отдельного класса, и здесь наша проблема заключалась в основном в разнообразии СИЗ: пришлось учитывать и форму, и цвет, и ракурсы, и зимнюю одежду, и сам размер каски в кадре. Чтобы собрать негативные примеры и обнаружить объекты, похожие на каску, но таковой не являющиеся, мы запускали модель на основе большого объёма реальных видео, собирали false positive и возвращали эти случаи в датасет. Этот способ показывает намного большую эффективность, чем попытки самостоятельно придумать объекты, которые модель может перепутать с каской. Вообще перед деплоем на новый объект мы обязательно прогоняли модель отдельно, несмотря на наличие стандартного тестового набора. Общая метрика не гарантирует качественный результат на отдельной площадке из‑за разных камер, высоты, на которой они установлены, формы сотрудников, освещения и самой стройплощадки. Здесь уже важно дообучение.

Демонстрация работы с ошибками наглядно представлена на составленной мной схеме:

Как внедряется ИИ на стройке: особенности масштабирования, данных и обучения моделей под российские реалии - 1

Для дообучения модели решили использовать transfer learning: стартовали с предобученных весов и затем делали fine‑tuning всей сети. Здесь было важно адаптировать не только классификационную часть, но и извлекаемые признаки, поэтому вариант с замороженным backbone нам не подходил. Причина здесь крылась в домене, который сильно отличался от исходных данных.

Чтобы показать итеративный цикл дообучения модели, отрисовал схему:

Как внедряется ИИ на стройке: особенности масштабирования, данных и обучения моделей под российские реалии - 2

До дообучения baseline для большинства специализированных классов был очень близок к нулю. Стандартная модель либо не умеет распознавать их в нашем домене, либо попросту не знает эти классы. На отдельном тестовом датасете внимание [5] уделяется в первую очередь precision и recall, а потом уже приросту относительно COCO. Здесь не очень корректно смотреть на усреднённую метрику, потому что конкретные цифры сильно разнятся в зависимости от класса, сценария и объекта.

Кстати, чтобы справиться с маленькими объектами, пришлось повышать разрешение инференса, следить за количеством маленьких объектов в датасете и работать с кропами зон интереса [6]. Но тут есть и физический предел: если каска занимает всего пару пикселей, то тут никакая YOLO не сможет восстановить информацию из воздуха.

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

Тут бы хотел рассказать в целом про особенности оптимизации системы с YOLO. Камер на объекте много, сама модель тяжёлая, а оборудование на стройплощадке может быть слабым. Тогда появилось простое решение: мы попросту не стали обрабатывать каждый кадр камеры, потому что для большинства событий на стройке 25 FPS не нужны, и частота анализа выбирается под конкретный сценарий. Потом идёт batching, аппаратное декодирование видео, оптимизация модели через TensorRT, выбор размера модели и распределение вычислительной нагрузки между GPU. Благодаря всему этому производительность оптимизируется сразу на нескольких уровнях — от видеопотока до самого инференса. Кстати, там, где можно было получить выигрыш по производительности, пробовали ещё снижение точности вычислений до FP16/INT8. Это очень важно на edge‑устройствах, но оптимизация ради красивого FPS некорректна. Поэтому после каждого подобного изменения мы повторно проверяем precision/recall на реальных данных. Ускорение не должно происходить за счёт заметного падения качества.

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

Здесь возникает другая проблема, а именно ухудшение результата после дообучения. Можно улучшить один сложный кейс и одновременно с этим допустить просадки старых. Поэтому мы сравниваем новую модель с предыдущей на regression‑наборе. К слову, все версии моделей хранятся отдельно. Если новая версия оказывается хуже, мы её либо не выпускаем, либо просто откатываем.

Ну и напоследок: YOLO способна решить не все задачи. Да, модель хорошо отвечает на вопрос «что и где находится в кадре», но плохо подходит для тех событий, где важен контекст во времени. Банальные примеры: человек просто остановился и стоит или же слишком долго бездействует. Это не понять по одному bounding box, тут уже нужен и трекинг, и временная логика [7], и pose‑модели. Для более сложных сценариев необходимо использование VLM, а также применение других подходов поверх обычной детекции.

Автор: Arkadiy_Froym

Источник [8]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/34701

URLs in this post:

[1] обучении: http://www.braintools.ru/article/5125

[2] зрения: http://www.braintools.ru/article/6238

[3] ошибки: http://www.braintools.ru/article/4192

[4] опыта: http://www.braintools.ru/article/6952

[5] внимание: http://www.braintools.ru/article/7595

[6] интереса: http://www.braintools.ru/article/4220

[7] логика: http://www.braintools.ru/article/7640

[8] Источник: https://habr.com/ru/articles/1072848/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1072848

www.BrainTools.ru

Rambler's Top100