Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
single frame task engineering
В этой статье будет описан подход (идея), как при помощи детектирующей нейросети решать более сложные задачи, чем детекция. Идея, лежащая в основе: давайте решать не задачу детекции объекта, а задачу детекции ситуации. Причем, вместо того, чтобы конструировать новую нейросетевую архитектуру, мы будем конструировать входящий кадр. А решать саму задачу будем при помощи стандартных предобученных сетей.
В качестве детектирующей нейросети использована архитектура YOLO, и все гипотезы этого подхода проверены для неё. Вероятно, эти же подходы будут работать и на других архитектурах. Действительно ли они будут работать, надо проверять отдельно.
Сегодня задача детекции (object detection), в рамках которой необходимо найти на изображении баундинг боксы для определённых классов объектов, выглядит довольно понятной и относительно рядовой. Если повезло, и у тебя есть достаточно большой и разнообразный датасет, то размечай данные, бери стандартную архитектуру и обучай модель.
В этой заметке я покажу как «переформулировать» задачу детекции так, чтобы решать другие, более сложные задачи. А именно, при помощи YOLO можно не только решать задачу детекции, но и задачу трекинга. И даже больше.
Механизм детекции
Процесс детектирования можно разбить на последовательные этапы работы с изображением внутри нейронной сети:
поиск некоторых простых паттернов (линия/угол/дуга и т. д.) в первых слоях НС
соединение этих паттернов более в сложные паттерны, или комбинации паттернов в средних слоях НС
анализ некоторого контекста* в предпоследних слоях
"выбор" классов и локации объектов в последних слоях.
*Здесь и далее контекстом я называю то, что не является частью детектируемого объекта, но имеет отношение к нему.
Посмотреть подробнее на то, что происходит внутри НС можно вот тут.
Если задуматься одновременно над третьим пунктом из списка выше, и примером детекции рук йолой, можно сделать вывод: в современных архитектурах, применяемых для детекции, так или иначе используется не только запоминание паттернов, из которых состоит сам объект, но и запоминание контекста.
Идея: нейронные сети придуманы по подобию устройства мозга. Давайте тогда будем перенимать не только архитектуру, но и способ/подход обработки информации мозгом. Мы точно не знаем как устроен и работает мозг, но можем кое-что перенять из собственного опыта:
Искать неизвестный объект проще тогда, когда есть его визуальный образ, чем описательный на словах. Это как навигация по карте проще чем навигация со слов прохожего. Есть на что посмотреть и с чем сравнить.
Анализировать происходящую ситуации проще по серии фото, чем по одной.
Определить что изменилось на изображении проще, имея перед глазами прошлое изображение тоже, чем по памяти.
Так родилась идея подавать на вход нейросети рядом с целевым изображением некоторый референс. Референсом может быть как конкретный объект, так и некий набор объектов, или последовательность объектов, или же дополнительный контекст.
Найди отличие или сравни с шаблоном
Простой пример. Пускай есть две фотографии одного и того же снеговика, с разницей в 5 минут. Фотографии сделаны с одного и того же места и ракурса. Со штатива, для определенности. На первой фотографии у снеговика только две пуговицы, а на второй добавили третью. Итого, есть две фото с отличием в одну пуговицу (подразумевается, что за 5 минут изменился свет и попиксельно фотографии точно не совпадают). Давайте обучим нейросеть искать это отличие. Обучать будем YOLO.
Чтобы нейросеть определяла отличия между двумя фотографиями, очевидно, ей на вход надо отправить оба снимка. Второе очевидное - нейросеть должна указывать на отличия на выходе.
Так и сделаем: склеим два изображения в мозаику: одно слева, одно справа. Пускай слева - изображение, на котором надо найти отличие, а справа - исходное. В качестве разметки выделим баундинг-боксом отличающуюся область только на левом снимке. То есть новую пуговицу. Так получили первое изображение в датасете. По аналогии получим и второе: сфотографируем пляж, усыпанный камнями. Потом заберем один камень, опять сделаем фото. Склеим и баундинг боксом отметим ту область кадра, с которой пропал камень. Примерно таким образом создаем датасет. Гипотеза состоит в том, что можно обучить нейросеть сравнивать два кадра и находить отличия на абсолютно незнакомых кадрах.
Гипотеза была проверена следующим образом. Взяты случайные фотографии. Из них генерировался синтетический датасет. Каждое изображение датасета состояло из двух половинок: левой и правой. Правая половина - исходное изображение, левая - то же изображение с двумя искажениями: поворот и случайный сдвиг интенсивностей(I) пикселей,
а - константа в рамках одного кадра. Дополнительно к искажениям на кадр добавлялся дефект в виде случайного пятна.
Наглядные примеры работы yolo
На рисунках ниже показаны склейки, состоящие из четырёх кадров (это не те склейки, которые подаются в нейросеть, а просто более удобный вид представления данных и результатов). По порядку, слева направо:
1й кадр - исходное изображение
2й кадр - целевое изображение. Оно получено из исходного шаблона, для которого посредством следующих операций: сдвиг по х/у на случайное значение, поворот на случайный небольшой угол, случайный сдвиг для интенсивности кадра, а также добавлен дефект случайной формы и случайной интенсивности (0-255). Дефект сделан с размытием по краям. Цвет на краю дефекта плавно переходит в цвет изображения в данной области. Дефектов добавляется случайное количество, до трёх штук.
3й кадр - изображение из предыдущего пункта, на котором красной рамкой отмечена область дефекта или ground truth.
4й кадр - целевое изображение с результатом работы нейросети или prediction. Число - вероятность дефекта или «уверенность» нейросети.
Еще раз подчеркну, что на вход нейросети подаются два изображения: исходное(шаблон) и "дефектное". Чтобы убедиться, что работает именно сравнение с шаблоном проделано следующее: вместо шаблона, в паре с целевым изображением был подан полностью черный кадр. В такой ситуации определяются случайные пятна, но не дефекты.
Для большей убедительности приложу Precision-Recall кривые для тестового датасета из 50ти картинок для двух случаев. В первом случае на вход нейросети подавались пары шаблон-целевое изображение, во втором - вместо шаблона подавался черный прямоугольник (как в батче на изображении выше).
Трекинг объекта или one-shot detection
Второй пример еще более интересный. Примерно таким же образом, как в первом случае, можно решать задачу object-tracking. Для этой задачи даже есть специальная технология DeepSort, которая используется для трекинга объектов на последовательных кадрах видеопотока. Трекинг DeepSort реализован в несколько этапов.
Сначала на двух последовательных кадрах определяются баундинг-боксы (ббоксы) для всех объектов целевого класса (например - людей).
Потом специальная нейросеть визуально сравнивает содержимое ббоксов первого кадра со вторым. И по этому сравнению определяет, в каких ббоксах второго кадра находятся люди из первого кадра.
Было проверено, что задачу objeсt-tracking можно решать при помощи yolo, причем в один шаг. Главное - придумать правильный "инжиниринг" кадра и поставить задачу трекинга в виде задачи детекции.
Вот как это было сделано: есть размеченные видеозаписи, на которых люди ходят под камерой. Берутся два кадра из этой записи, которые могут быть последовательными или быть разнесенными во времени на один, три, четыре, десять или тридцать кадров. Важно, что это пара кадров, 1й и 2й. Два кадра соединяются в мозаику: один слева, второй справа. На 1м кадре (на левой половине изображения) обводится зелёным (в данном случае цвет значения не имеет) прямоугольником тот человек, трек которого надо получить. А в разметку записываются координаты ббокса для этого же человека со 2го кадра, с правой половины изображения (если на 2м кадре человека уже нет, то в разметку ничего не записывается).
Вот пример изображения, которое подаётся на вход нейросети:
На левой части нарисован зеленый прямоугольник вокруг человека. Суть в том, что на вход нейросети изображение так и отправляется: на нём выделен тот объект, который нужно определить на правом кадре. В данном случае, на выходе нейросети ожидаются координаты ббокса вокруг человека в розовой куртке с правой половинки изображения.
Ббокс желтого цвета - это тот результат, который ожидается на выходе нейросети.
Причем одновременно можно делать трекинг нескольких людей. Тогда инжиниринг кадра выполняется следующим образом: на левой половинке изображения объекты просто обводятся ббоксами разного цвета; а на выходе нейросети ожидаем объекты разных классов. Объект, отмеченный красным ббоксом,- первого класса. Объект, отмеченный зеленым ббоксом,- второго класса. Объект который отмечен желтым ббоксом - это объект третьего класса и тд.
Пример метрик для такой задачи:
В данном случае решалась задача трекинга одного человека в кадре.
Отличие предложенного метода от DeepSort в том, что DeepSort сначала определяет ббоксы всех людей, а потом по визуальному наполнению ббоксов определяет, какой ббокс из второго кадра похож на ббокс из первого. Новый метод позволяет по визуальному наполнению ббокса первого кадра сразу искать конкретный объект на втором кадре.
Анализ события во времени
Завершающий и самый интересный пример. Есть задача: посчитать по видеозаписи количество вошедших людей. Одно из существующих решений состоит в следующем:
Задетектировать всех людей на каждом кадре видео;
Алгоритмом DeepSort определить какие ббоксы на соседних кадрах видео обводят одного и того же человека;
Построить трек движения человека во времени по той области, которую наблюдает камера;
Классифицировать трек человека на "вошедший", "вышедший", "никакой";
Посчитать количество треков "вошедших" (и/или "вышедших").
Ту же самую задачу можно решить и при помощи YOLO, придумав соответствующий инжиниринг кадра. Берем раскадровку нашего видео и соединяем в мозаику: 3 строки по 5 кадров.
Верхняя и нижняя строки кадров нужны для контекста. А на средней строке (и только на ней) будем требовать от yolo детектировать следующее: отметь мне того человека, который находится в том моменте, когда он только вошёл в дверь.
Отправляя в разметку такие мозаики, важно определить в какой момент мы будем считать, что человек входит в дверь (в данном случае - это момент, когда голова пересекает линию порога). Тут так же важно подчеркнуть, что объектом детекции, на самом деле, является не человек, а ситуация. То есть чтобы решать задачу, мы сделали такой инжиниринг кадра, в котором одновременно
достаточно информации для описания ситуации,
ситуацию можно задетектировать как объект.
Выше представлены результаты работы нейросети, обученной для такой задачи. Интересно, что событие выходящего человека часто детектируется на нескольких кадрах. Возможно потому, что войти в автобус проще, чем выйти, и выход занимает больше времени.
Для задачи определения количества вошедших/вышедших в дверь эти метрики - скорее оценка снизу. На примерах инференса было видно, что часто событие "выходящий человек" детектируется на трёх кадрах подряд. Очевидно, это ухудшает метрику F1. Однако на эти рамки накладывается простая логика при постобработке, благодаря которой вышедший человек будет учтён один раз, а не три.
И огромный плюс такого подхода - это то, что один инференс YOLO запускается сразу на несколько кадров видео. Что уменьшает вычислительную сложность задачи.
Заключение
В заключение необходимо сказать, что все приведенные тесты были сделаны "на скорую руку". Кроме того, использовалась некачественная разметка, сгенерированная автоматически. И YOLO, возможно, тут не самая подходящая архитектура. Задача была проверить жизнеспособность подобных подходов. Результаты получились хорошие, показывающие, что идея рабочая.
Подведем итоги:
Объектом детекции может быть не только простой "объект" с его физическими границами, но и ситуация, или комплекс объектов, и т. п.
Конструирование кадра позволяет использовать стандартные архитектуры для нестандартных задач. А стандартные архитектуры хорошие тем, что над ними уже долго трудилось большое количество разработчиков. Такие архитектуры предобучены, продуманы, и проверены временем.
При хитром инжиниринге кадра можно существенно уменьшать вычислительную сложность задачи.
Следующая задача, которую нужно попробовать решить подобным методом - это задача one-shot detection. Уже есть понимание как сделать для неё инжиниринг кадра.
Boris Ginzburg
OOO DataDep