single frame task engineering
В этой статье будет описан подход (идея), как при помощи детектирующей нейросети решать более сложные задачи, чем детекция. Идея, лежащая в основе: давайте решать не задачу детекции объекта, а задачу детекции ситуации. Причем, вместо того, чтобы конструировать новую нейросетевую архитектуру, мы будем конструировать входящий кадр. А решать саму задачу будем при помощи стандартных предобученных сетей.
В качестве детектирующей нейросети использована архитектура YOLO, и все гипотезы этого подхода проверены для неё. Вероятно, эти же подходы будут работать и на других архитектурах. Действительно ли они будут работать, надо проверять отдельно.
Сегодня задача детекции (object detection), в рамках которой необходимо найти на изображении баундинг боксы для определённых классов объектов, выглядит довольно понятной и относительно рядовой. Если повезло, и у тебя есть достаточно большой и разнообразный датасет, то размечай данные, бери стандартную архитектуру и обучай модель.
В этой заметке я покажу как «переформулировать» задачу детекции так, чтобы решать другие, более сложные задачи. А именно, при помощи YOLO можно не только решать задачу детекции, но и задачу трекинга. И даже больше.
Механизм детекции
Процесс детектирования можно разбить на последовательные этапы работы с изображением внутри нейронной сети:
поиск некоторых простых паттернов (линия/угол/дуга и т. д.) в первых слоях НС
соединение этих паттернов более в сложные паттерны, или комбинации паттернов в средних слоях НС
анализ некоторого контекста* в предпоследних слоях
"выбор" классов и локации объектов в последних слоях.
*Здесь и далее контекстом я называю то, что не является частью детектируемого объекта, но имеет отношение к нему.
Посмотреть подробнее на то, что происходит внутри НС можно вот тут.
Если задуматься одновременно над третьим пунктом из списка выше, и примером детекции рук йолой, можно сделать вывод: в современных архитектурах, применяемых для детекции, так или иначе используется не только запоминание паттернов, из которых состоит сам объект, но и запоминание контекста.
Идея: нейронные сети придуманы по подобию устройства мозга. Давайте тогда будем перенимать не только архитектуру, но и способ/подход обработки информации мозгом. Мы точно не знаем как устроен и работает мозг, но можем кое-что перенять из собственного опыта:
Искать неизвестный объект проще тогда, когда есть его визуальный образ, чем описательный на словах. Это как навигация по карте проще чем навигация со слов прохожего. Есть на что посмотреть и с чем сравнить.
Анализировать происходящую ситуации проще по серии фото, чем по одной.
Определить что изменилось на изображении проще, имея перед глазами прошлое изображение тоже, чем по памяти.
Так родилась идея подавать на вход нейросети рядом с целевым изображением некоторый референс. Референсом может быть как конкретный объект, так и некий набор объектов, или последовательность объектов, или же дополнительный контекст.
Найди отличие или сравни с шаблоном
Простой пример. Пускай есть две фотографии одного и того же снеговика, с разницей в 5 минут. Фотографии сделаны с одного и того же места и ракурса. Со штатива, для определенности. На первой фотографии у снеговика только две пуговицы, а на второй добавили третью. Итого, есть две фото с отличием в одну пуговицу (подразумевается, что за 5 минут изменился свет и попиксельно фотографии точно не совпадают). Давайте обучим нейросеть искать это отличие. Обучать будем YOLO.
Чтобы нейросеть определяла отличия между двумя фотографиями, очевидно, ей на вход надо отправить оба снимка. Второе очевидное - нейросеть должна указывать на отличия на выходе.
Так и сделаем: склеим два изображения в мозаику: одно слева, одно справа. Пускай слева - изображение, на котором надо найти отличие, а справа - исходное. В качестве разметки выделим баундинг-боксом отличающуюся область только на левом снимке. То есть новую пуговицу. Так получили первое изображение в датасете. По аналогии получим и второе: сфотографируем пляж, усыпанный камнями. Потом заберем один камень, опять сделаем фото. Склеим и баундинг боксом отметим ту область кадра, с которой пропал камень. Примерно таким образом создаем датасет. Гипотеза состоит в том, что можно обучить нейросеть сравнивать два кадра и находить отличия на абсолютно незнакомых кадрах.
Гипотеза была проверена следующим образом. Взяты случайные фотографии. Из них генерировался синтетический датасет. Каждое изображение датасета состояло из двух половинок: левой и правой. Правая половина - исходное изображение, левая - то же изображение с двумя искажениями: поворот и случайный сдвиг интенсивностей(I) пикселей,
а - константа в рамках одного кадра. Дополнительно к искажениям на кадр добавлялся дефект в виде случайного пятна.
![Пример обучающего батча таких изображний. Пример обучающего батча таких изображний.](https://habrastorage.org/getpro/habr/upload_files/e64/2a2/91e/e642a291e3f4d9927d3191f0b3b13a53.jpeg)
Наглядные примеры работы yolo
На рисунках ниже показаны склейки, состоящие из четырёх кадров (это не те склейки, которые подаются в нейросеть, а просто более удобный вид представления данных и результатов). По порядку, слева направо:
1й кадр - исходное изображение
2й кадр - целевое изображение. Оно получено из исходного шаблона, для которого посредством следующих операций: сдвиг по х/у на случайное значение, поворот на случайный небольшой угол, случайный сдвиг для интенсивности кадра, а также добавлен дефект случайной формы и случайной интенсивности (0-255). Дефект сделан с размытием по краям. Цвет на краю дефекта плавно переходит в цвет изображения в данной области. Дефектов добавляется случайное количество, до трёх штук.
3й кадр - изображение из предыдущего пункта, на котором красной рамкой отмечена область дефекта или ground truth.
4й кадр - целевое изображение с результатом работы нейросети или prediction. Число - вероятность дефекта или «уверенность» нейросети.
![](https://habrastorage.org/getpro/habr/upload_files/2a9/f7c/379/2a9f7c379c3f079ced068e946ad96946.png)
![](https://habrastorage.org/getpro/habr/upload_files/5e7/295/365/5e7295365e8deb9bd635ccdad73bc6fc.png)
![](https://habrastorage.org/getpro/habr/upload_files/145/0cd/6f6/1450cd6f6c543c4d5bc7dadb390fbce7.png)
![](https://habrastorage.org/getpro/habr/upload_files/c67/ec5/d89/c67ec5d892c4a5a88d54c2cb00c555dd.png)
![](https://habrastorage.org/getpro/habr/upload_files/c8f/d8b/16f/c8fd8b16f8614caa42e93547454ee6d8.png)
Еще раз подчеркну, что на вход нейросети подаются два изображения: исходное(шаблон) и "дефектное". Чтобы убедиться, что работает именно сравнение с шаблоном проделано следующее: вместо шаблона, в паре с целевым изображением был подан полностью черный кадр. В такой ситуации определяются случайные пятна, но не дефекты.
![Батч без изображений без референсов. Батч без изображений без референсов.](https://habrastorage.org/getpro/habr/upload_files/5c6/d33/4a1/5c6d334a10be89fef00edaa88c06070f.jpeg)
Для большей убедительности приложу Precision-Recall кривые для тестового датасета из 50ти картинок для двух случаев. В первом случае на вход нейросети подавались пары шаблон-целевое изображение, во втором - вместо шаблона подавался черный прямоугольник (как в батче на изображении выше).
![Метрики для задачи поиска отличий. Метрики для задачи поиска отличий.](https://habrastorage.org/getpro/habr/upload_files/636/edf/e6e/636edfe6e1a528fe1b958de918cb4dce.png)
Трекинг объекта или one-shot detection
Второй пример еще более интересный. Примерно таким же образом, как в первом случае, можно решать задачу object-tracking. Для этой задачи даже есть специальная технология DeepSort, которая используется для трекинга объектов на последовательных кадрах видеопотока. Трекинг DeepSort реализован в несколько этапов.
Сначала на двух последовательных кадрах определяются баундинг-боксы (ббоксы) для всех объектов целевого класса (например - людей).
Потом специальная нейросеть визуально сравнивает содержимое ббоксов первого кадра со вторым. И по этому сравнению определяет, в каких ббоксах второго кадра находятся люди из первого кадра.
Было проверено, что задачу objeсt-tracking можно решать при помощи yolo, причем в один шаг. Главное - придумать правильный "инжиниринг" кадра и поставить задачу трекинга в виде задачи детекции.
Вот как это было сделано: есть размеченные видеозаписи, на которых люди ходят под камерой. Берутся два кадра из этой записи, которые могут быть последовательными или быть разнесенными во времени на один, три, четыре, десять или тридцать кадров. Важно, что это пара кадров, 1й и 2й. Два кадра соединяются в мозаику: один слева, второй справа. На 1м кадре (на левой половине изображения) обводится зелёным (в данном случае цвет значения не имеет) прямоугольником тот человек, трек которого надо получить. А в разметку записываются координаты ббокса для этого же человека со 2го кадра, с правой половины изображения (если на 2м кадре человека уже нет, то в разметку ничего не записывается).
Вот пример изображения, которое подаётся на вход нейросети:
![Пример обучающего изображения. Пример обучающего изображения.](https://habrastorage.org/getpro/habr/upload_files/91d/6df/b8e/91d6dfb8e122fdffcdd576b4d6b6a53e.jpg)
На левой части нарисован зеленый прямоугольник вокруг человека. Суть в том, что на вход нейросети изображение так и отправляется: на нём выделен тот объект, который нужно определить на правом кадре. В данном случае, на выходе нейросети ожидаются координаты ббокса вокруг человека в розовой куртке с правой половинки изображения.
![Пример визуализации разметки для обучающего изображения. Пример визуализации разметки для обучающего изображения.](https://habrastorage.org/getpro/habr/upload_files/f71/ba9/b23/f71ba9b23d7226d0228015eb8627da54.jpg)
Ббокс желтого цвета - это тот результат, который ожидается на выходе нейросети.
Причем одновременно можно делать трекинг нескольких людей. Тогда инжиниринг кадра выполняется следующим образом: на левой половинке изображения объекты просто обводятся ббоксами разного цвета; а на выходе нейросети ожидаем объекты разных классов. Объект, отмеченный красным ббоксом,- первого класса. Объект, отмеченный зеленым ббоксом,- второго класса. Объект который отмечен желтым ббоксом - это объект третьего класса и тд.
Пример метрик для такой задачи:
![Метрики для задачи тренинга/реидентификации людей. Метрики для задачи тренинга/реидентификации людей.](https://habrastorage.org/getpro/habr/upload_files/76b/72c/d46/76b72cd46a04b957d2e0be2d2d2cebe3.png)
В данном случае решалась задача трекинга одного человека в кадре.
Отличие предложенного метода от DeepSort в том, что DeepSort сначала определяет ббоксы всех людей, а потом по визуальному наполнению ббоксов определяет, какой ббокс из второго кадра похож на ббокс из первого. Новый метод позволяет по визуальному наполнению ббокса первого кадра сразу искать конкретный объект на втором кадре.
Анализ события во времени
Завершающий и самый интересный пример. Есть задача: посчитать по видеозаписи количество вошедших людей. Одно из существующих решений состоит в следующем:
Задетектировать всех людей на каждом кадре видео;
Алгоритмом DeepSort определить какие ббоксы на соседних кадрах видео обводят одного и того же человека;
Построить трек движения человека во времени по той области, которую наблюдает камера;
Классифицировать трек человека на "вошедший", "вышедший", "никакой";
Посчитать количество треков "вошедших" (и/или "вышедших").
Ту же самую задачу можно решить и при помощи YOLO, придумав соответствующий инжиниринг кадра. Берем раскадровку нашего видео и соединяем в мозаику: 3 строки по 5 кадров.
![Пример инжиниринга кадра. Пример инжиниринга кадра.](https://habrastorage.org/getpro/habr/upload_files/901/f22/c33/901f22c332e6cc28439194dc9f24a7e0.jpg)
Верхняя и нижняя строки кадров нужны для контекста. А на средней строке (и только на ней) будем требовать от yolo детектировать следующее: отметь мне того человека, который находится в том моменте, когда он только вошёл в дверь.
Отправляя в разметку такие мозаики, важно определить в какой момент мы будем считать, что человек входит в дверь (в данном случае - это момент, когда голова пересекает линию порога). Тут так же важно подчеркнуть, что объектом детекции, на самом деле, является не человек, а ситуация. То есть чтобы решать задачу, мы сделали такой инжиниринг кадра, в котором одновременно
достаточно информации для описания ситуации,
ситуацию можно задетектировать как объект.
![](https://habrastorage.org/getpro/habr/upload_files/ffd/2c2/811/ffd2c28114a38a87b90aed5fc73b7031.png)
![](https://habrastorage.org/getpro/habr/upload_files/cea/0df/684/cea0df684c96cc5332870e6cc0250ec3.png)
![](https://habrastorage.org/getpro/habr/upload_files/feb/0d5/d9d/feb0d5d9de1c8fcc68de7f0fbeefad7e.png)
![Метрики для задачи детекции входящего/выходящего человека. Метрики для задачи детекции входящего/выходящего человека.](https://habrastorage.org/getpro/habr/upload_files/a2b/c24/6bd/a2bc246bd0cab4a3ffef6583031aab0f.png)
![Confusion matrix для задачи детекции входящего/выходящего человека. Confusion matrix для задачи детекции входящего/выходящего человека.](https://habrastorage.org/getpro/habr/upload_files/17c/6b5/af5/17c6b5af5109f671dda9b3f340f06a8d.png)
Выше представлены результаты работы нейросети, обученной для такой задачи. Интересно, что событие выходящего человека часто детектируется на нескольких кадрах. Возможно потому, что войти в автобус проще, чем выйти, и выход занимает больше времени.
Для задачи определения количества вошедших/вышедших в дверь эти метрики - скорее оценка снизу. На примерах инференса было видно, что часто событие "выходящий человек" детектируется на трёх кадрах подряд. Очевидно, это ухудшает метрику F1. Однако на эти рамки накладывается простая логика при постобработке, благодаря которой вышедший человек будет учтён один раз, а не три.
И огромный плюс такого подхода - это то, что один инференс YOLO запускается сразу на несколько кадров видео. Что уменьшает вычислительную сложность задачи.
Заключение
В заключение необходимо сказать, что все приведенные тесты были сделаны "на скорую руку". Кроме того, использовалась некачественная разметка, сгенерированная автоматически. И YOLO, возможно, тут не самая подходящая архитектура. Задача была проверить жизнеспособность подобных подходов. Результаты получились хорошие, показывающие, что идея рабочая.
Подведем итоги:
Объектом детекции может быть не только простой "объект" с его физическими границами, но и ситуация, или комплекс объектов, и т. п.
Конструирование кадра позволяет использовать стандартные архитектуры для нестандартных задач. А стандартные архитектуры хорошие тем, что над ними уже долго трудилось большое количество разработчиков. Такие архитектуры предобучены, продуманы, и проверены временем.
При хитром инжиниринге кадра можно существенно уменьшать вычислительную сложность задачи.
Следующая задача, которую нужно попробовать решить подобным методом - это задача one-shot detection. Уже есть понимание как сделать для неё инжиниринг кадра.
Boris Ginzburg
OOO DataDep
Комментарии (10)
LewXie
27.08.2023 13:30+2Хорошо бы еще убедиться, что в первом случае сеть определяет именно различия, а не пятна, сгенерированные конкретным способом. Для этого можно нанести одинаковые дефекты на оба изображения, а на одном ещё несколько.
В третьем случае сеть может определять направление по позе человека. Чтобы убедиться, что она ловит именно движение, можно "проиграть" запись задом наперед (разместить кадры справа налево и снизу вверх).
А, вообще, прикольноginbor Автор
27.08.2023 13:30+1По первому случаю: обучение на дефектах одинаковой природы создаёт отпечаток образа этих дефектов внутри весов.
Я делал "проверку на вшивость" на реальной задаче. Искал дефекты печати при шелкографии.
На прикрепленных картинках тройки изображений.
Верхнее изображение: дефектное слева + нормальное справа
Среднее изображение: дефектное слева + дефектное справа
Нижнее изображение: GT для первого изображенияПримеры работы на реальных данных. Отмечу, что Йолка чувствительна к размеру объекта на который она была обучена. В данном случае она не была обучена на огромные дырки в краске, как на первом и втором примере.
Бывает такое, что определяет дефекты просто потому, что они похожи на дефект. То есть правая часть не всегда играет роль. Пока что думаю, что это недостаточное обучение.
По третьему случаю: задача не только определить направление, но и поймать именно тот момент, когда человек на пороге. То есть "поза над порогом" тоже важна :)
IamSVP
27.08.2023 13:30+1А как вы пришли к пониманию, как это работает? Как свертки, по вашему мнению, "видят" контект с соседних фреймов внутри слепленного кадра? На последнем примере F1 составила 0,6 при "бинарной" детекции. На первый взгляд вылгядит как детекция голов и угадывание (чуть лучше чем просто угадывать "вход" или "выход", возможно из-за дисбаланса классов) классов. Да и судя по Confusion matrix выглядит удручающе
LewXie
27.08.2023 13:30"Видеть" то они "видят", а "понимают" ли и используют ли вообще - тайна сия велика есть...
Можно было бы попробовать обучить детекцию по одному кадру и посмотреть, не станет ли лучшеIamSVP
27.08.2023 13:30как по мне, то метрики говорят о том, что процесс детекции похож на процесс угадывания
ginbor Автор
27.08.2023 13:30К точному пониманию как это работает я не пришел. Есть только догадки, которые не проверял. Появилась идея -> проверил на скорую руку. По результатам проверки есть намёки что оно работает.
Заметку как раз написал, чтобы послушать чужие мнения.
По поводу F1=0.6. Из кадров видно, что определение выходящего человека работает хуже. Оно может работать хуже по разным причинам:
1. Обучающий дотасет был сформирован автоматически. Причем следующим образом: При помощи дипсорта детектировался человек. Затем я для каждого человека (если он входит или выходит) брал 10й кадр его нахождения в поле зрения камеры. Считал что он примерно попадет на порог. Понятно, что далеко не все люди в обучающей выборке попали на порог. Но я их не фильтровал, обучал как есть.
2. Часто встречаются два FP детектирования. Одно на кадр раньше, второе - на кадр позже. Но они FP именно с точки зрения разметки. Такие ложные детектирования не мешают определять что человек вышел.
Kwent
Очень необычный и оригинальный подход детектирования временных событий, спасибо за статью, а это на основе какой-то статьи или сами придумали?
ginbor Автор
Всё сам
ginbor Автор
Спасибо)