Для начала я хотел бы обозначить, что данная статья не про генерацию синтетики (хотя частично затронем), она про работу с ней и проблемы, которые могут возникнуть в ходе обучения детектора на этой самой синтетике.
В качестве введения я хотел бы рассказать о задаче, в которой мне впервые пришлось столкнуться с обучением детектора на полностью синтетических данных.
Задача тривиальная - контроль над сборкой объекта на производстве. Выставляется одна или несколько камер в разных частях сборочного цеха. Еще есть вариант с использованием очков дополненной реальности, но это совсем другая история, о ней расскажу как-нибудь потом.
Перед сборщиком помещается монитор, в котором он может отслеживать нужные детали на каждом из этапов и подсказки, которые описывают последовательность действий сборщика. В зависимости от сценария переход на следующий шаг сборки может происходить как по классификации нужной подсборки, так и по какой-нибудь операции (например, забивание молотком). Вроде ничего сложного, все стандартно и никаких проблем..
А может, ну его..
В стандартном понимании процесса обучения детектора всё бы свелось к простой схеме:
Съемка видео и дальнейшая его раскадровка
Сплитим на train/valid
Если необходимо - докидываем аугментацию на наши тренировочные данные
Ставим на обучение, подбираем гиперпараметры, контролируем метрики и т.д.
Профит!
Но вот есть в этой задачке одна проблемка..снять сборку можно было один единственный раз.. И стоит ли говорить о том, что такого количества данных не хватит для адекватной работы системы? И аугментация нам тут точно не поможет. Использовать сегментацию? Можно попробовать, но есть причина, по которой сегментация нежелательна (о ней в самом конце), плюс разметка такого количества деталей заняла бы не одну неделю.Что же делать?
И вот тут на сцену выходит его величество Blender.
Пластмассовый мир победил
Будем исходить из условия, что на многих крупных заводах есть (ну, по крайней мере, должны быть) CAD-ы объектов. Поэтому, казалось бы, что проще, загружаем CAD, генерируем синтетику, закидываем на обучение и радуемся жизни, да? Ммм,нет.
Одна из действительно нерешаемых проблем: несоответствие CAD с реальными объектами
К сожалению, никаких вариантов, кроме исправления/создания с нуля объекта не существует. Поэтому просто надеемся и свято верим, что таких моментов будет по минимуму.
Теперь перейдем к трем столпам, китам, называйте как хотите, основным проблемам в детекции реальных объектов с помощью синтетики: свет, текстура, ракурс.
Свет, камера, мотор.. и блики
В ходе подготовки данных выяснилось, что сборка объекта может осуществляться на разных предприятиях, и если в случаях вопроса текстуры и ракурса это не настолько критично (к этому вернемся чуть позже), то вопрос света стоит ребром - модель придется делать максимально робастной к свету и бликам, так как мы не знаем какой интенсивности будет свет, где располагаться источники и так далее.
Благо для этого в blender существуют все для этого необходимое:
Glossy Color Pass (блики, отражательная способность)
Diffuse Color Pass (рассеивающая составляющая, в нашем случае должна иметь высокое значение)
Ambient Occlusion Pass (интенсивность света)
Shadow Pass (тени)
Normal Pass (карта нормалей)
В данной статье на Хабр можно ознакомиться с приемами работы с Blender. Также полно туториалов на youtube, например, вот такой, поэтому не будем на этом долго останавливаться, а лучше поговорим про само обучение, текстуры и ракурс.
Давайте уже обучать!
Всё обучалось на yolov5, с подбором гиперпараметров. После первого же прогона стало понятно,что модели из blender получились слишком идеальными и вообще не похожи (кроме формы) на реальные объекты, что ж, добавим текстуру и шереховатость.
Смотрим метрику mAP по всем 40 классам и получаем 0.51, мягко говоря - не очень. Попробуем сгенерировать еще немного синтетики и посмотреть на результат. Что странно, но результат практически не изменился.. начинаем разбираться.
Подключаем gradcam для того,чтобы понимать на что именно смотрит сеть и обнаруживаем,что в случаях, когда объекты, которые близки друг к другу или хоть как-то пересекаются - один из объектов просто не определяется, а это говорит об одном - в нашем датасете не хватает (или их вообще нет) примеров, когда одна деталь лежит поверх другой. Вариант генерировать новые данные - слишком затратный, поэтому пишем небольшой скрипт, который позволит нам накладывать одну сцену на другую, при этом создавая правильные видимые маски для новой сцены. Ну и как бонус, сможем повысить робастность системы к различным фонам.
Снова запускаем обучение и наш mAP становится 0.845, что уже выше поставленной цели в 0.8, но можно чуть лучше. Добавим немного аугментации из библиотеки albumentation, поиграемся со светом и шумом, переведем в grayscale.
Теперь вернемся к вопросу о ракурсе. Так как расположение камеры разрешено устанавливать нам, то и синтетика генерировалась с учетом расстояния и возможных углов, поэтому изменение на уровне аугментации может не только не улучшить метрики, но и навредить. Совсем другой разговор, когда в следующих проектах нам пришлось устанавливать камеру на шлем сборщика..но это, как и история с очками дополненной реальности, другая история.
После всех экспериментов с аугментацией и с продолжительным подбором гиперпараметров и не менее продолжительным обучением - мы получаем финальный mAP на уровне 0.89. К сожалению, по причине NDA показать видео сборки не является возможным.
Заключение
Перед тем, как закончить, хотелось бы вернуться к вопросу - почему бы просто не использовать сегментацию. Причина проста - идея заказчика заключается в том,чтобы создать универсальную и автономную систему, работающую по принципу:
К сожалению, на данный момент, построить полностью автоматизированный pipeline не представляется возможным. Причина кроется в самом первом пункте - несоответствие CAD и реальных объектов на производстве убивают всю идею на корню. Добавим к этому некоторые сложности при генерации синтетики (контроль над пересечениями, подбор правильных ракурсов), получаем красивую идею, но, увы, пока нереализуемую без вмешательства человека.
Подытожим общий pipeline, который позволил нам покрыть уже несколько действительно крупных предприятий:
Получаем CAD объектов, загружаем их в blender
Проверяем их на соответствие с реальными объектами, исправляем, если таковые нашлись
Генерируем синтетику с указанными в статье правилами
Добавляем аугментацию, в том числе с заменой фона
Подбор гиперпараметров и обучение
Проверяем обученную модель уже на реальных данных (проверять на синтетике не имеет никакого смысла)
Убеждаемся в работоспособности системы и готовимся выкатывать в прод, ура!
Надеюсь такая небольшая статья позволит хоть немного сэкономить время и не допустить тех ошибок, что допустил я, когда ставил эксперименты над синтетическими данными.