Я люблю скелетные детекторы из Mediapipe. Чтобы запустить их нужно всего несколько минут. Работает на разных платформах (мобильные, pc, embedded, и.т.д.). И выдает достаточное качество для многих применений. 

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

Для начала разберем общую логику работы скелетных детекторов
Пайплайн с скелетами в MediaPipe выглядит следующим образом (подробнее можно посмотреть тут - 1,2,3,4,5):

Общая логика
Общая логика
Детектор кейпоинтов на руках
Детектор кейпоинтов на руках

Если в двух словах, на примере руки:

  1. Начало работы

    • Детектируем область руки. Когда рука задетектирована переходим к 2

  2. Для области руки :

    • Находим ключевые точки + оцениваем присутствует ли рука

  3. Если рука присутствует - корректируем область детекции и переходим к п.2

  4. Если рука не присутствует, то переходим к п.1

Давайте теперь поговорим о проблемах алгоритма, и тому как надо их лечить.

Говоря о алгоритме на базе нейронных сетей важно помнить что его качество определяется:

  • Актуальностью (давно или недавно вышла работа)

  • Качество датасета

  • Тяжестью Backbone. (На MobileNet все будет летать, на трансформерах будет медленно.)

В MediaPipe хороший и актуальный алгоритм. Он учитывает физику руки, немножко физику процесса, современные статьи.

В MediaPipe качественный датасет. Они не просто собрали хороший датасет (30к), но и создали синтетический датасет неограниченного размера.

Но, датасет собран исходя из того что использоваться будет на маломощных устройствах, и рука будет около камеры. 

А вот Backbone в MediaPipe достаточно прост. Это сделано для быстрой работы. 

Если говорить про подробности (тут код, тут статья). 

Для детекции используется очень легкая версия FPN где зарезали много якорей

В статьях другая картинка, но реально сетка детекции какая-то такая
В статьях другая картинка, но реально сетка детекции какая-то такая
  1. Детекции квадратные, это позволяет уменьшить число якорей

  2. Энкодер-декодер позволяют работать с большими разрешениями.

  3. Для оптимизации используется Focal loss

Для особых точек рук используется вот эта работа. Практически идентичные пайплайны и по рукам и по телам. Только чуть разные методы обучения используются.

В чем же проблемы? Да они в целом стандартны:

  1. Не работает в нужных ракурсах

  2. Неправильные условия освещения

  3. Слишком мелкие/слишком крупные руки

Вот несколько примеров с проблемами:

Проблемы начинаются как только появляется нетипичный домен данных. А их много.
Проблемы начинаются как только появляется нетипичный домен данных. А их много.

А теперь я расскажу про 5-6 простых способов как улучшить качество:

Переобучение / Замена модели

Начнем с наиболее очевидных подходов, которые структурируем по сложности имплементации.

Самый простой

Проще всего улучшить качество (для большинства задач) - переобучить детектор по вашим данным. Ни один другой подход нельзя реализовать так быстро и получить такой прирост качества. Конкретно для MediaPipe нет готового пайплайна обучения. Но можно взять аналогичный FPN детектор отсюда с пайплайном.

И произвести аналогичную настройку якорей. Либо, взять любой другой детектор (yolov5 yolox, и.т.д.).

Самая сложная такого подхода — получить набор данных. Разметка набора данных для обнаружения можно получить очень быстро. Человек может разметить около тысячи изображений в час. А для обучения детектор, который на некоторых выбранных доменах превзойдет MediaPipe, будет достаточно 5–10 тысяч изображений. Так что, как правило, со всей инфраструктурой вам понадобится около недели на процесс переобучения.

Такая разметка в любом cvat или supervisely делается очень быстро
Такая разметка в любом cvat или supervisely делается очень быстро

Если у вас плохо работает детектор - то ошибка будет влиять на все процессы дальше.
И его фикс улучшает все. Например в одном из проектов где мы использовали MediaPipe на старте - переобучение по актуальному датасету (ракурсы/оптика) - число ошибок уменьшилось примерно в 5 раз. По другому проекту, где детектировали лица и оценивали ориентацию взгляда и мимику - получили уменьшение числа ошибок в 2 раза (но там был не MediaPipe, а предобученные сети OpenVino). По третьему проекту, где мы делали детекцию скелетов - полученный прирост вложили в скорость, и это позволило ускорить в несколько раз.

Чуть сложнее

Вариант сложнее - переобучить алгоритм детекции ключевых точек по вашему датасету.

Это особенно важно когда вы хотите производить какую-то точную оценку действий. Но смысл это имеет не всегда. Из тех трех приведенных выше проектов - мы лишь один раз делали переобучение скелетной модели

Полная замена модели

Так же надо окончательно закрыть варианты переобучить и закрыть модель. Можно зайти на papers with code:

  1. https://paperswithcode.com/task/hand-pose-estimation

  2. https://paperswithcode.com/task/3d-hand-pose-estimation

  3. https://paperswithcode.com/task/pose-estimation

  4. https://paperswithcode.com/task/3d-human-pose-estimation

  5. https://paperswithcode.com/task/facial-landmark-detection

И взять любую понравившуюся модель/подход. По качеству будет сильно лучше чем MediaPipe, по времени сильно больше. И садиться оптимизировать.

Использование временной компоненты

Если вы работаете с видео - у вас есть временная компонента. Вы можете взять набор детекций с разных кадров и вторичной сетью “вылечить его”.

Временная компонента может значительно повысить качество - ведь рука не может летать произвольно по кадру, да и действия в рамках одной задачи обычно похожие.
И нет никаких “Но есть же фильтр Калмана!”. Но его настройка для сложного объекта будет сложнее чем обучение нейронной сети. Да и для нелинейных процессов он будет хуже. 

Не для любой задачи временная компонента может улучшить качество. Например если вы распознаете по одному кадру. Или для быстрых действиях.

Несколько способов как можно использовать временную компоненту

Уменьшить объемы шумов 

Для этого достаточно реализовать схему с каким-нибудь понижающим размерность эмбеддингом и восстановлением данных. Берем последовательность кадров, разворачиваем её назад. Высокочастотные компоненты обычно уходят. Полученный embedding можно использовать для OneShot Learning или других быстрых  распознаваний.

Landmarks слева зашумлены, справа стабилизированные
Landmarks слева зашумлены, справа стабилизированные

“Вылечить” выбитые точки

Если у вас пропадает детекция на части кадров - такие точки не сложно предсказать. Можно обучить сетку восстанавливать все точки с какого-то временного интервала (или предсказать детекцию на текущем кадре, если её нет).

Слева есть выбитые элементы, справа мы их восстановили
Слева есть выбитые элементы, справа мы их восстановили

Классификация действий

Если у вас есть всего несколько целевых действий - то даже по зашумленным данным можно предсказать их, и уйти от точного восстановления скелета.

Восстановить действия можно через One shot action recognition
Восстановить действия можно через One shot action recognition

Небольшой пример

Чтобы показать что работа с временной компонентой это просто - я сделал небольшой пример. Не используйте его в проде! Он очень простой и сделан только для демонстрации принципа и эффекта.

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

Итак, для простейшего примера мы можем использовать полносвязную сеть:

И в ходе обучения нужно удалить случайные элементы трека:

Добавим немного кода для визуализации и, как-то начинает работать:

Надеюсь это как-то поможет;)

P.S.

Если вам понравилось - подписывайтесь на мой каналы где я рассказываю про похожие проблемы сильно больше. Telegramm, VK, Linkedin, Youtube
А вот тут есть эта статья в формате видео:

Комментарии (14)


  1. wadik69
    10.05.2022 16:32
    +4

    Человек может разметить около тысячи изображений в час

    Сотку бы за час разметить - уже было бы хорошо


    1. rnj2000
      10.05.2022 17:19

      Тут же предлагается bounding box для первичной детекции руки разметить, без самих ключевых точек. Это делается максимально быстро в простом VGG Image Annotator или грузится на толоку.

      За статью респект, применю ваш в опыт в поиске ключевых точек на рентгенах костей


      1. ZlodeiBaal Автор
        10.05.2022 17:45

        Спасибо! Да, вы все правильно описали.

        Если человек в кадре один/два, если нет высоких требований на точность детекции то это 500-1500 в час. В зависимости от анотатора и датасета.

        При разметке скелетов там конечно уже все очень медленно становится.


        1. wadik69
          10.05.2022 18:01
          +3

          Да, я понимаю, что это ограничительные рамки для первичной детекции, но всё равно выглядит как оптимистичный сценарий, как по мне. Хотя, если прям не отрываться от компьютера и нет высоких требований к разметке, то 500 фотографий, наверное, вполне реально. В любом случае, это мелочи, а статья действительно классная - спасибо большое автору!


          1. ZlodeiBaal Автор
            10.05.2022 19:34

            Я сам не специалист в оценке скорости такой разметки. Но когда мы привлекаем наших разметчиков то я обычно закладываю где-то 500 картинок в час на такой тип (10 в минуту). Сам я конечно за минуту штук 20-30 прокликиваю, но долго в таком режиме наверное нельзя (я максимум минут 20-30 обычно так делаю чтобы оценить что за задача вообще).
            Вообще на Хабре много кто специализируется именно на лейблинге, можно позвать например kucev, думаю что он может примерно оценить какие у них стандарты на такие таски.


  1. le2
    11.05.2022 02:27
    +1

    я не знаю как в новых версиях, но на состояние полгода-год назад они значительно улучшили детектор скелета просто перейдя от картинок 128x128 к 256х256.

    Второе, промахи детектора в медиапайп не бесит, потому что... детектор вызывается очень редко) В первый раз скелет (или рука или лицо) действительно детектится детектором, а дальше рамка детектора уже расчитывается из точек ландмарка скелета (или ладони или лица).


    1. ZlodeiBaal Автор
      11.05.2022 02:35

      1) там была ещё пачка улучшений при обучении, судя по их статьям. Не только повышение размера

      2) зависит от задачи и от ракурсов. Посмотрите на примеры проблем которые я привожу (в видео чуть более полные примеры). Для большинства задач с которыми работали мы просто за счёт переобучения детектора число ошибок падало в несколько раз. Но да, я согласен что могут быть задачи где это не критично. Там не должно быть сложных условий наблюдения где объект теряется, постоянного входа и выхода из кадров новых объектов.

      И кстати, для рук там по дефолту, если в кадре нет двух рук, детектор достаточно часто проверяет наличие.


  1. Sergechug
    11.05.2022 07:29

    А yolov5 не используете? Вроде SOTA.


    1. ZlodeiBaal Автор
      11.05.2022 07:30

      1) в тексте есть прямое упоминание

      2) Про sota я бы поспорил...)


      1. Kwent
        11.05.2022 17:19

        Можно без спора мне рассказать что sota, а то в моем мире тоже пока yolov5)


        1. ZlodeiBaal Автор
          11.05.2022 17:28
          +1

          Надо определиться что такое SOTA.
          paperswithcode.com/sota/object-detection-on-coco
          paperswithcode.com/task/real-time-object-detection

          1) Максимальное качество? Там много претендентов, но все Трансформеры.
          2) Максимальное качество на свертках? Там вроде Yolov4-p7
          3) Максимальное качество при каких-то скоростях? Ну, там есть и yolop и yolox
          github.com/hustvl/YOLOP
          github.com/Megvii-BaseDetection/YOLOX
          Но вообще там ооочень много вариантов если лезть внутрь.
          4) Максимальное удобство конвертации на разные платформы? Но если разобраться то оказывается что даже в TensorRT yolov5 конвертируется не оптимально. Есть кастомные конвертаторы которые ускоряют примерно в 2 раза итоговые модели…

          Это не отмменяет что Yolov5 очень удобный и быстрый для использования. Но говорить что он «SOTA». Ну, такое…


          1. OShapovalov
            11.05.2022 17:47

            Есть кастомные конвертаторы которые ускоряют примерно в 2 раза итоговые модели…

            А вот про это можно подробнее?

            На наших задачах трансформеры хуже по точности (и хуже по соотношению точность/скорость), yolov4-p7 тоже ощутимо хуже, yolop и yolox тоже не фонтан, но мы маловато их копали. Пока продолжаем считать, что yolov5 сота. Кстати ее нет на paperswithcode, так как нет статьи


            1. ZlodeiBaal Автор
              11.05.2022 18:24
              +1

              Это не называется «SOTA». Это называется «пайплайн обучения в yolov5 + yolov5 работает лучше по нашему датасету»:) Это нормально, так бывает.

              «Кстати ее нет на paperswithcode, так как нет статьи»
              Иногда AlexeyAB интересные картинки у себя в твиттере (https://twitter.com/alexeyab84) постит с реальным сравнением разных yolo
              Например — twitter.com/alexeyab84/status/1481982576818630662/photo/1

              Где-то я ещё видел сравнения детекторов по классическим задачам/датасетам, yolov5 было не впереди.

              А вот про это можно подробнее?

              Говорят вот эта имплементация ускоряет на tensorrt ощутимо — github.com/enazoe/yolo-tensorrt
              Но сам не пробовал, все хочу. Говорят там NMS и какие-то операции вокруг него перенесены тоже на TensorRT.


              1. OShapovalov
                11.05.2022 18:36

                «пайплайн обучения в yolov5 + yolov5 работает лучше по нашему датасету»

                Так можно и про любой бенчмарк сказать. Yolov5 на многих дасатетах прекрасно работает, см kaggle

                За ссылку по конвертации спасибо, изучим