Год назад моя статья про трекинг была тепло принята на Хабре. Эта статья - продолжение. В ней я сделал обзор современных методов распознавания действий. От самых простых и удобных, до самых сложных. Расскажу в каких ситуациях что использовать, и расскажу как это применяют в некоторых проектах.
Если вдруг вам понравится статья, то имеет смысл обратить внимание на мой канал (youtube, telegram). Я часто рассказываю там о темах вокруг Computer Vision: про решение реальных задач, про подходы, про процессы, о небольших хитростях при решении задач.
Чтобы показать всю сложность задачи распознавания действий, я хочу привести такой пример:
А можете ли понять что я делаю тут? Думаю нет. По крайней мере вы будете не уверены в ответе. Тут я сверлю.
А можете ли понять что я делаю тут?
Скорее всего тоже нет. Ну, тобишь забиваю гвоздь, и это очевидно. Но полное название действия было бы “вешаю картину”.
В первом примере мы имеем неправильную установку камеры.
Действие невозможно распознать. Если только вы не ясновидящий/знаете контекст.
Во втором примере мы имеем нетривиальный контекст, когда описание действия имеет сложную структуру, специфичную для задачи. Я видел задачи где были десятки однотипных действий.
И это лишь малая часть проблем при распознавании действий. Работающий алгоритм должен быть стабилен к таким сложностям! А столкнуться придется:
Неполнота постановки задачи (непонятны границы действий, не понятно как трактовать промежуточные действия)
Решение задачи требует больших датасетов
Мощные алгоритмы современного Action Recognition требуют хорошего железа
Задача очень изменчива: новый подвес камеры, новая одежда, новый способ действия и.т.д.
Но, если бы все было так грустно - я бы не делал эту статью. Сегодня мы будем говорить о том как можно срезать углы, какие задачи решаются, какие работы появились в последнее время и какие лайфхаки есть в постановке задачи.
Определим понятия
Начнем с того что все же попробуем структурировать задачу. Хотя сразу скажу что в общем случае это невозможно. Что такое “действие”? Если мы посмотрим исследовательскую задачу “Action recognition”, то и тут не будет консенсуса. Первый по популярности академический датасет содержит клипы по 2-20 секунды с снятыми ситуациями с участием людей:
Второй по популярности датасет содержит записи с камеры закрепленной на одежде:
Но это лишь малая часть. Существуют задачи “Action Classification”, “Video Classifcation”, “Self-Supervised Action Recognition” (вот часть из задач, которые частично пересекаются внутри себя 1,2,3). Есть датасеты со скелетами, есть датасеты с процессом готовки:
Где-то это короткие видео, где-то длинные.
Что же такое действие? В моем представлении, которое я буду использовать тут - действие это некоторое событие которое можно отметить на видео обладая априорным знанием что оно может там произойти. Событие может быть произведено человеком, машиной, животным или чем-то другим. Почему мне комфортнее такое определение? Обычно, на практике (в 99% случаев), распознавание действий используется для какого-нибудь детерминистического процесса. Определить что произошло какое-то событие, которое надо посчитать/учесть/контролировать.
Такое определение сильно чаще корректно для реальных задач ComputerVision, но не очень хорошо для академических задач, где требуется “универсальное определение”. Так же оно не работает для всяких видео стримингов и система анализа контента.
Чем это отличается, что такое “реальные задачи”? Реальные задачи обычно имеют ограниченный набор данных/ракурсов, формата. Я ни разу не видел задачи где надо было бы найти 400 разных действий с любого ракурса. Реальные задачки могут быть например такими:
Контроль выполнения действий на производстве
Контроль покупателей/сотрудников магазинов
Контроль выполнения правильного порядка действий на кухне
Контроль поведения с камеры висящей на голове/на теле (спортсмены, полиция, и.т.д.)
Детектор аварий
Распознавание процессов в животноводстве
и.т.д.
Это очень/очень малая часть. Но все же:
Камеры скорее всего зафиксированы/хотя бы прикручены к человеку
Реальных действий на камеру 1-10. И очень очень редко 10-100
Схемы которые я буду описывать в целом годятся для многих действий. Начнем с подходов, которые сильно проще академических. А закончим более экспериментальные и академические.
Для наглядности, в большинстве примеров, в качестве референса я буду использовать людей, вид откуда-то сбоку.
О чем я не буду тут писать. Те же самые алгоритмы используются и для задач анализа видео. Я уверен что полно Action Recognition и Video Classification и у Youtube и у Netflix. Там постановка ближе к классической: есть рандомное видео, надо понять что происходит.
Я ни разу не занимался указанными задачами с этой стороны. Так что для кого-то мое описание может выглядеть однобоко.
Позиция
Хорошо, начнем с базовой идеи. Предположим вы хотите распознать когда человек звонит в дверной звонок. Как вы это будете делать?
Самое последнее что можно делать в такой ситуации - начать запускать обучение из топовых подборок Papers With Code. Ведь сильно проще задетектировать что-то из следующего:
Рука человека около дверного звонка
Человек стоит у двери некоторое время
Для этого не нужен Rocket Science. Достаточно одного хорошо обученного детектора и плюс-минус адекватно стоящей камеры. Результат работы будет гарантированный и трактуемый. Например если не детектируется рука, то можно посмотреть почему - и попробовать переобучить (появились перчатки / странный свет, и.т.д.).
Итого, схема следующая: Детекция объекта->Проверка области работы->Проверка сопутствующих условий
По сути идея в том что вам не нужно действие, а вам нужно понимание происходящего
Объект
Примерно тем же самым является подход где описанием действия является объект. Конечно, “в общем случае” сковородка в руках - не значит ничего. Но, зная контекст где установлена камера, это может быть “готовка” на кухне, “продажа” в магазине или “драка” в PUBG’е.
Комбинируя логику между “Позицией” или “Объектом” - можно собрать длинные действия или последовательности действий.
Объектом может быть что угодно. Одежда/товары/машины в кадре, и.т.д.
Временные Action
Переходим к методам которые работают на куске видео. И тут я бы сразу разбил понятие “ кусок видео” на два с половиной метода:
Работа с скелетной моделью объекта
Работа напрямую с видео
Работа с видео целиком
Работа с выделенным объектом (человек, машина, и.т.д.)
Комбинированные методы
Использование регионов интереса
Комбинирование с детекторами объектов
Работа с каким-нибудь препроцессингом (Optical flow… e.t.c., про это писать не буду даже)
В чем разница? Нейронные сети, когда нужно работать с видео, - достаточно неудобны. Нужно больше производительности, сложнее датасеты, сложнее обучать. Один из подходов уйти от работы с видео - предварительно детектировать скелет и работать с ним. Причем это может быть:
Скелет человека
Скелет животного
Скелет руки
Точечная модель лица
Скелетная модель объекта (машины, диваны, и.т.д.). Интереснее, конечно, те которые могут быть динамичны, например экскаватор/робот/и.т.д.
При этом скелетная анимация явно теряет текстурную информацию, которая может быть критична: одежда, предметы с которыми происходит взаимодействие, мимика, ....
Кроме того, можно комбинировать что-то из двух областей. Например для части действий которые можно распознать по скелету - использовать скелет. А для части методов которые нельзя - текстурную информацию.
Классификаций, классический подход
Вот тут неплохая подборка методов которые реализуют классическую классификацию:
MMAction - развивающийся, но сырой фреймворк поверх MMCV поверх PyTorch. С куском документации на китайском.
PyTorchVideo - попытка фейсбука сделать аналог, но пока слабоватая. Зато нaтивный PyTorch.
А вот тут хорошая подборка статей - Action Classification,Action recognition c Papers with code
Глобально, задача как ставилась, так и ставиться. “на вход пачка кадров” (или скелетов), на выход действие. Начиналось все с 2д сверток:
Потом развитие соответствовало классическому “бекбоны, аттеншн”:
Перешло все к TimesFormer (трансформеры во всех осях):
А сейчас даже с RL поверх лепят:
n.b. , а ещё все бенчмаркаются зачастую по разным датасетам, так что сравнить нельзя
Можно отметить что все методы страдают от одного и того же:
Датасет. Его сложно собрать и сложно разметить. Нормальные датасеты - это тысячи примеров. Нужно разнообразие людей, разнообразие поз, ракурсов (если такова задача). Никто не любит собирать такие датасеты.
Сходимость. Многие из action recognition моделей сложно заставить сходиться. Иногда можно собрать небольшой датасет и по нему не будет сходиться. Но заранее оценить это сложно. У нас были ситуации когда работающая на трех датасетах Action Recognition модель не работала на аналогичном четвертом. Очень сложно понять причину почему не работает.
Одно и то же действие в разных частях кадра - одно и то же? А в разных позах? А действия которые похожи, где проходит граница? А сложносоставные действия? Неопределенность задачи очень хорошо проявляется в задачах классификации действий
Про работу "с видео целиком" vs "с кропом". Важно не забывать это при выборе алгоритма и правильно его выбирать. Можно распознавать сразу по всему видео, либо можно распознавать по области человека (предварительно задетектированной и затреканной). В первом случае есть проблема с тем когда в кадре много людей. Зато неплохо работает когда в кадре много информации помогающей распознать действий.
Так же отдельно надо сказать про классическую классификацию по скелетной анимации. Особой магии там никакой нет. Статей не особо много. Лучше всего работает PoseC3D, который есть в упомянутом MMAction. Основное отличие работы - использование именно сверточной сети, а не классических подходов которые работали на массивах точек:
Но, как видно, модель достаточно простая для 2021 года. При этом много где используется и много кто на неё ссылается:
Существует множество сеток работающих по массивам точек. Если честно, то чаще использовал их - из за скорости.
Unsupervised /кластеризация / Embedding
Zero-shot на Papers With Code. Self Supervised там же.
Можно ли попробовать убрать часть проблем? Да. Можно попробовать уйти от сбора датасета, и частично от обучения. Конечно же в пользу точности:)
В целом, большинство подходов работают на том что создается некоторый “embedding” вектор характеризующий действие. А дальше есть вариации. Для скелетных моделей это скорее честный Embedding.
Для видео это скорее файнтьюнинг или какая-то перебалансировка/автовычисление классов/хитрый автолейблинг.
Но в последние полтора года начали появляться варианты и для видео. Многие из них либо привязываются к текстовым описаниям видео/текстовым эмбедингам. Например, интереснее всего по открытым бенчмаркам на сегодняшний день выглядит “Elaborative Rehearsal for Zero-shot Action Recognition:
Но репозиторий имеет всего 16 звезд, опыта использования нигде не находил, а у самого пока не дойдут руки. Тут в качестве базы используется энкодер имени из текста через BERT. Но, если честно, их сравнение с Supervised подходами не впечатляет:
Примерно так же во второй по рейтингу статье:
Кто-то вообще делает текстовое описание каждого кадра из которых суммирует тектовое описание/эмбединг для всего видео.
А кто-то просто сделал CLIP для видео, и использует эмбединги оттуда.
Хотя мне странно предствить как тот же kinetics-400 может создать достаточно универсальную репрезентацию для всех действий.
Ещё популярные подходы - Self Supervised. Это когда мы обучаем по датасету A, делаем этой сеткой разметку датасета B, и обучаем по этим "размеченным" данным. Мне кажется что такие подходы иногда можно использовать (когда есть большой датасет но сложно размечать).
Вообще про каждый подход придется очень долго рассказывать. Так что краткий обзор/сравнение. Полностью zero-shot подходы для сложного датасета дают 35%. Подходы для transfer learning/self supervised имеют точность порядка 75%. Тогда как полностью supervised подходы (которые мы обсуждали выше.) дают примерно 90%. Это же неплохо видно на изображениях того как прогрессирует точность в последние годы:
Ошибка отличается в 5 раз, но про это мы поговорим позже.
Если честно, я ни разу не видел чтобы кто-то на практике по реальным задачам в небольших/средних фирмах использовать Unsupervised/Zero-shot подходы по видео. Да, какой-нибудь fine-tuning по своему датасету все используют. Но именно unsupervised с чистыми эмбедингами или хитрой стратегией тренировки по псевдо лейблам….Возможно, если задача не очень сложна - получится натренировать стабильные Embedding по видео. Но пока такого не видел.
А вот с скелетной анимацией и Embedding там все иначе!
Приведу несколько примеров. Первый - фирма в которой я работаю последние 5 лет. В CherryLabs по скелетам успешно распознаются многие действия.
Для каких-то действий достаточно 1-2 примера для обучения. Но нужно очень аккуратно выбирать места внедрения.
Я не буду подробно рассказывать про наш подход, но вот несколько академических статей и сорсов на эту тему, которые помогут структурировать логику: (1,2,3). А вот Papers with Code.
Естественно, все делают через embedding, но магия в том как его формировать.
В прошлом году на ODS Data Fest ребята из Yandex говорили похожие слова (скелетные embedding) про модель лица (68 точек), формирования эмбеддингов и их использования для набора датасета/классификации действий:
Есть два видео с какими-то подробностями (1,2). Математику они не светят, каких-то хороших статей по теме не видел. Но, глобально, не думаю что оно отличается сильно от тел.
Есть пара проектов где Embedding генерируется для рук. Один из них такой:
Мне кажется, что кто-то обязательно должен использовать это в проде для распознавания/запоминания жестов. Лично мы аналогичные подходы использовали только для временной фильтрации рук (чтобы стабилизировать тряску от детекции).
Так что, если обобщить - статей мало, зато в проде вижу часто. Ведь плюсы очевидны:
Вычислительно просто, просто обучить (не обязательно нужно обучать на другом датасете), простая логика. Если же сравнить с другими подходами:
Ошибка отличается в 20 раз почти. Подробнее про ошибку мы поговорим позже. Иногда, One Shot спасает:)
Скелеты vs Видео
Давайте начинать суммировать!
А что вообще лучше использовать для распознавания? Оригинальное видео или скелетную анимацию, построенную по видео? Тут надо давать себе отчет что это разные методы, применимые в разных ситуациях.
Скелеты требуют дополнительного обучения. Вы сначала обучаете распознавать скелет в кадре. И, если вы хотите хорошего качества, то вы не используете OpenSource обученные модели, а создаете домен под ваш датасет. А лишь потом обучаете Action. Это дольше по времени в любом случае.
Скелеты не дают возможность использовать текстуры. В примере про водителей, которых распознавал Yandex выше - они используют вырезанные области с текстурной информацией (например рот) для улучшения качества. Но это не всегда сработает. Особенно если интересное в кадре вокруг скелета - инструменты и машины с которыми он работает.
Скелеты плохо работают если в кадре только часть человека
Готовых датасетов с действиями в скелетах мало/нет. Их надо генерить из обычных датасетов или набирать.
При этом:
Скелеты - быстрее инферить. Сетка распознавания действий не ест ничего почти. Сетки детекции скелетов достаточно легковесные и хорошо оптимизированные. Например вот тут можно посмотреть что можно в браузере на базе медиапайпа:
Скелеты проще хранить
С скелетами проще генерировать синтетику для обучения
По сути эта плюсы и минусы и разделяют применения обоих методов.
Unsuperviser Vs Supervised
И все же, я описал Supervised и Unbsupervised подходы. Какой из них проще/быстрее/удобнее? Кто из них где применяется?
И опять же, нет однозначного ответа на этот вопрос:
Если у вас есть всего несколько действий, и можно собрать датасет - лучше использовать Supervised. Он точнее, стабильнее, предсказуемее.
В проде чаще именно такие подходы. Unsupervised часто используется для майнинга данных. Иногда для какой-то предварительной аналитики.
Unsupervised сильно сложнее натянуть на чистое видео и проще на скелеты. Это, опять же, ограничение.
Так что в теории можно использовать оба из них. Сначала запускается Unsupervised, а потихоньку он переходит в Supervised.
Как ни странно, есть некоторые классы действий/примеров где Unsupervised справляется плохо. Обычно это действия с высокой вариативностью. Грубо говоря если для действия нельзя сделать стабильный Embedding. Хороший пример - танцы. Их существуют сотни. И нет стабильного эмбеддинга. А вот обычное обучение неплохо справляется.
Если вы помните, на датасете с видео OneShot ошибка отличалась в 5 раз (75% ошибки против 13%). А на датасете с скелетами между скелетным OneShot и скелетами в 5 раз (50% ошибки против 11) и при сравнении с видео в 20 раз (50% против 2%).
Но тут нужно понимать, что ошибка не равномерна. Есть действия которые распознаются OneShot практически идеально. Это в первую очередь короткие действия, в которых нет взаимодействия с текстурой. Желательно действия которые не имеют вариативности. Например "упасть" можно сотней способов. А вот "поднять коробку" можно одним правильным способом и 2-3 неправильными. Для каких-то алгоритмов важен ракурс.
Умея корректно поставить задачу можно сильно срезать углы.
Вместо заключения
Закончу, пожалуй, с того, с чего начал. Как мне кажется, для не академической задачи распознавания действий обычно достаточно сильно более простых методов описанных в начале. И лишь несколько процентов задач требуют хорошего ActionRecognition.
Решая задачу вы должны ответить на несколько вопросов:
Нужен ли мне настоящий Action Recognition, или я обойдусь понятной логикой?
Нужны ли мне скелеты или буду ли я работать с видео?
Важна ли мне гибкость которую предоставляют One-Shot подходы, или важна точность и возможность работы с сложными действиями?
Ответы на эти вопросы позволят очень сильно упростить и ускорить решение вашей задачи.
Так как тема продуктового применения Action Recognition не сказать что очень популярна, будет классно если люди имевшие с ним дело расскажут где смогли его успешно внедрить, а где он не работал в упор :)