В последние годы появляется всё больше технологий с использованием Computer Vision: это и беспилотные автомобили, и Face ID в телефоне, и умные камеры, способные фиксировать утечку теплоизоляции крыши. Кто-то прогресс приветствует, кто-то нет, но неизменно одно – процесс этот неостановим. Особенно активно развивается технология распознавания лиц, которую мы разберем в этой статье. Только в этот раз вас ожидает не классический пайплайн системы, но разбор технологии на микрокмопьютерах. Подготовил ее я, Саша Шувалов – аналитик-разработчик компании Кросстех Солюшнс Групп. 

Почему именно микрокомпьютеры? 

Несмотря на активное увеличение моделей крупными компаниями, одновременно с этим развивается тренд на real-time решения и/или для конечных устройств. Также, большая часть русскоязычных материалов по данной тематике использует устаревшие подходы. К этому можно добавить использование готовых библиотек, что, конечно, сильно ускоряет процесс разработки, но и добавляет определенные ограничения для развития функционала.

Для начала рассмотрим классический вариант системы распознавания, который зарекомендовал себя в различных областях.

Рис. 1. Классическая система распознавания.
Рис. 1. Классическая система распознавания.

Как видно из рисунка 1, классическая система распознавания состоит из 4 блоков:

  • получить кадр для анализа;

  • детектировать лица;

  • извлечь дескрипторы лиц;

  • поиск лиц в БД.

Далее мы рассмотрим каждый из этих пунктов подробнее. Пока можно отметить, что основная задача системы распознавания – идентифицировать пользователей, дополнительный функционал может быть самым разным. Начиная от запрещенных зон (например, распознавание только в определенной части кадра) заканчивая различными вариантами информирования об инциденте. 

Также к плюсам развертывания распознавания на микрокомпьютерах можно отнести мобильность данного устройства. Оно может быть изолированно от внешней сети или взаимодействовать со сторонними сервисами, при этом снижая нагрузку на них из-за предварительной обработки кадров. 

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

  1. Оборудование

В нашем распоряжении был микрокомпьютер Khadas VIM4. Это достаточно производительный микрокомпьютер с 8 Gb RAM. Кроме того, у него есть NPU, которые оптимизированы под работу с нейронками. Но будьте осторожны: у данного решения есть два варианта, которые можно отличить только по CPU ID [doc] (один с NPU, другой без).

Особо не будем вдаваться в разбор характеристик, так как это немного выходит за тему данного материала, да и на Хабре уже есть сравнение с тем же RPI 4. Отметим только, что плюс такого решения заключается в том, что он по характеристикам сопоставим с слабыми ноутбуками, что позволит тестировать на нем различные программы для ограниченного по ресурсам железа.

  1. Как выбираем модели

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

Для системы распознавания на микрокомпьютерах мы сформировали такие критерии (они могут отличаться в зависимости от платы, но мы стремимся к уменьшению потребляемых ресурсов, чтобы увеличить возможность выбора платы и сэкономить):

  1. Чем производительнее система тем лучше, так как позволит дополнять новым функционалом без необходимости увеличивать аппаратные ресурсы;;

  2. Чем меньше размер модели тем лучше;

  3. Чем выше качество на выбранном бенчмарке тем лучше;

  4. Open-source решение.

Благодаря критериям выше мы сможем ограничить возможные модели, но остается вопрос – где их искать?

Отличным ресурсом для первичного поиска моделей будет [PapersWithCode]. Тут собрано большое число статей, моделей, датасетов под различные задачи. Также, очень удобно, что отмечаются статьи с кодом и даны ссылки на GitHub репозитории. Все это упрощает и ускоряет выбор моделей.

Еще одним моментом, который явно не включен в критерии, ML фреймворк, в нашем случае – PyTorch версии 2.x. Но вы можете использовать ONNX, TF или другие варианты, конверторов достаточно много на просторах GitHub.

Здесь же отметим, что сейчас мы не рассматриваем варианты модели с квантованием и прореживанием. Это отдельная большая тема, которая может быть рассмотрена дальше. Отметим лишь то, что это способ уменьшить размер модели без сильной потери качества и различные его варианты представлены во многих популярных ML фреймворках, так что с ними всегда можно поиграться, так как для них есть достаточно подробные документации.

  1. Выбор моделей и БД

Модель детектирования лиц.

Если вам интересно узнать подробнее про этапы развития технологии детектирования объектов, то вот хорошая и подробная статья об этом [papper].

Набор шагов для выбора модели детектирования лиц:

  1. Выбрать бенчмарк;

  2. Составить критерии выбора модели;

  3. Выбрать модели по составленным критериям;

  4. Дополнительно протестировать на новых данных и собрать метрики качества на них;

  5. Переаранжировать список моделей согласно результатам пункта 4;

  6. Выбрать лучшую модель из отсортированного списка подходящих.

В качестве бенчмарка был выбран WIDER Face (Easy/Medium/Hard). Из-за удобного разбиения по категориям сложности детектирования лица.

Исходя из критериев и пайплайна в пункте 4, было выделено несколько моделей:

Таблица. Список моделей детектирования лиц по критериям и лицензии.

Модель

Метрики AP по WIDER Face

Open-source

Размер, Мб

Лицензия

Easy

Medium

Hard

YOLOv5n

93.6

91.5

80.5

+

14

GPL-3.0

YOLOv5s

94.3

92.6

83.2

+

54

GPL-3.0

SCRFD-10G

95.2

93.9

83.1

+

15

Apache 2.0

SCRFD-34G

96.1

94.9

85.3

+

38

Apache 2.0

CenterFace

93.2

92.1

87.3

+

8

MIT

YOLOv7-tiny

94.7

92.6

82.1

+

12

GPL-3.0

YOLOv7s

94.8

93.1

85.2

+

8

GPL-3.0

Ряд моделей из таблицы были выделены для дальнейшего тестирования на подготовленных отдельно данных:

  • SCRFD-10G;

  • SCRFD-34G;

  • CenterFace;

  • YOLOv7-tiny;

  • YOLOv7s.

В результате тестирования были получены такие результаты:

Таблица. Результаты тестов на собранном датастете.

Модель

Время среднее, сек.

Доля верных предсказаний, %

SCRFD-10G

0.096

100

SCRFD-34G

0.528

100

CenterFace

0.063

100

YOLOv7-tiny

0.165

100

YOLOv7s

0.240

99

Исходя из анализа результатов можно сделать вывод, что лучшим вариантом в данном случае будет модель CenterFace.

C:\Users\shuvalov.a\Desktop\ORKEY-876-V9\ORKEY-876-V8\Важное\Лицо\19.jpg
Рис. 2. Примеры фотографий для тестов.
C:\Users\shuvalov.a\Desktop\ORKEY-876-V9\ORKEY-876-V8\Важное\Лицо\21.jpg
Рис. 2. Примеры фотографий для тестов.

Подробнее про модель можно почитать тут [paper].

Получение дескрипторов лиц.

Сам по себе дескриптор лица – вектор, который характеризует признаки лица. Чаще всего, чтобы получить такие представления, используют модели, которые учились для решения задачи классификации. После обучения обрезают слои классификации и добавляют нормализацию выхода. В итоге мы получаем векторное представление лица, которое далее можно использовать для поиска похожих.

Можно задаться вопросом: а почему тогда мы хотим получать векторное представление, а не оставлять классификацию, так как мы и так получим нужного пользователя при тестах?

Такой вариант действительно возможен, и он не уступает, а иногда и превосходит решение через дескрипторы. Однако добавление/удаление лица в классификатор приведет к тому, что его нужно будет переобучать. Если лиц мало, то это не проблема, но если их много или большое число фото на одно лицо, то процесс может затянуться, что не очень хорошо. Плюс добавить дескриптор в БД быстро и можно делать через запросы, а переобучить классификатор на микрокомпьютере возможно далеко не всегда.

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

Разобравшись в причинах и устройстве получения дескрипторов, можно переходить к выбору модели. Правда, отдельной категории для конечных моделей распознавания нет на PaperWithCode, но была найдена недавняя статья, в которой приведена таблица метрик для таких моделей, что позволило сделать выбор по бенчмарку LFW и общим критериям:

Таблица. Первичный выбор моделей распознавания для промежуточного устройства.

Модель

Точность на LFW

Размер, Мб

EdgeFace

99.78

14

MixFaceNet-M

99.68

15

PocketNetM

99.65

7

Каждая из этих моделей подходит по критериям при анализе на бенчмарке, но ситуация изменилась при тестировании на тестовых данных. Для проверки были взяты данные [dataset]. В итоге были получены такие результаты:

Таблица. Результаты тестов на датастете.

Модель

Время получения дескриптора, мс

Доля верных предсказаний, % от общего числа фото

Без align

С align

Без align

С align

EdgeFace

39

41

90

98

MixFaceNet-M

138

140

24

26

PocketNetM

138

141

93

97

Из анализа таблицы можно сделать вывод, что лучше всего подходит использование EdgeFace + align лица через similarity transform.

Примеры лиц:

Без трансформации
Без трансформации
С трансформацией
С трансформацией

Выбор БД для хранения дескрипторов

Очевидно, что для идентификации пользователя его данные необходимо где-то хранить. Один из вариантов – использовать классификатор поверх модели извлечения дескрипторов, но проблемы данного подхода были описаны ранее (проблема с добавлением/удалением новых лиц, надо переобучать классификатор, а на плате это не всегда возможно). 

Что же нам тогда остается? Ответ прост – поиск расстояний между дескрипторами! 

Большинство из вас видели картинку, где показаны преобразования с эмбеддингами из текста. Ее пример на рисунке 4.

Ryan Heuser
Рис. 4. Эмбеддинги текста

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

Далее мы будем использовать метрику L2, хотя в некоторых работах отмечается, что косинусная близость работает чуть лучше, однако на тестовых данных разницы замечено не было.

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

Здесь есть несколько вариантов, подробнее разберем каждый из них:

  1. Использовать векторные БД;

  2. Писать расчет расстояний “руками” и полным перебором ходить по какой-то БД (например, SQLite);

  3. Использовать Postgres + PGVector или ClickHouse.

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

Одна из таких баз – Faiss. Очень удобное решение, которое обладает всем необходимым функционалом для решения поставленной задачи. На момент написания статьи, были реализованы основные варианты индексов HNSW, IVF и Flat. Подробнее о них можно почитать в прекрасной статье на Хабр [хабр]. Если чуть забежать вперед, то именно такую БД мы и будем использовать для нашей реализации, но, конечно, такой подход не лишен недостатков. 

С одной стороны, мы получаем быстрое и удобное решение для хранения, добавления, удаления и поиска похожих векторов, но при этом, у нас нет возможности в самой БД явно зафиксировать, например, ID пользователя и другую мета информацию. Справедливости ради скажем, что в Faiss есть возможность сохранения векторов по ID, пусть это и помогает решить проблему, но не избавляет от необходимости дополнительно прикручивать БД и/или использовать какие-то конфиг файлы с маппингом пользователей в ID дескрипторов Faiss. Также возникает вопрос атомарность, так как мы скорее всего захотим как-то менять дескрипторы, и данные должны будут обновляться совместно.

В итоге мы имеем решение, которое прекрасно выполняет задачи по работе с векторами, но на этом все, если хотите тянуть мета данные, делать обновления и тд, надо будет немного повозиться. Однако, плюсы здесь явно перекрывают минусы.

В дополнении хочется посоветовать репозиторий на GitHub [benchmark]. Это бенчмарк в котором собраны тесты различных ANN баз для хранения векторов, на разных датасетах с дескрипторами. Здесь можно прикинуть желаемое качество, потребляемые ресурсы, подобрать параметры для индексов и тд. В целом, очень полезная и удобная вещь.

Вернемся к пункту 2. С хранением в какой-то БД и перебором с вычислением руками. Что тут можно сказать, работать будет, но до определённого момента. Проблемы полного перебора, думаю, очевидны и акцентировать на них внимание не стоит. Помимо этого есть еще неоптимальное хранение самих векторов. В итоге, если у вас очень мало векторов и вы точно знаете, что больше их не станет, то такое решение вполне может подойти, так как вектора можно обогатить метаинформацией, да и просто убрать зависимость из ПО.

И последний вариант, использовать PGVector (расширение для Postgres) или ClickHouse. Плюсы тут налицо, использовать преимущества OLTP/OLAP, не расширять стек технологий, так как может вы уже использовать какую-то из этих БД. Но здесь очевидно, что это хороший вариант для серверного решения, либо для того, где можно спокойно поднять эти БД. Для микрокомпьютеров это пока слишком жирно по ресурсам.

К еще одному недостатку такого решения можно отнести только начальное их развитие. Для нас это значит, что стандартные приемы из того же Faiss здесь могут отсутствовать. Например, для ClickHouse, индексация для дескрипторов находится на стадии экспериментов, что налагает дополнительные ограничения на использование в проде. У PGVector дела получше, там уже реализована поддержка основных вариантов индексации, но скорость работы оставляет желать лучшего, к тому же есть очень интересные варианты бенчмарков, когда первая ссылка говорит, что PGVector – лучшее решение для векторов, а по следующей ссылке утверждается абсолютно противоположное. При анализе я ориентировался на бенчмарк выше (как минимум там есть код, который можно посмотреть и при желании запустить все у себя в docker) и там, полученные мной данные о скорости работы, подтверждаются.

Что же можно заключить по векторным БД:

  1. Если мало дескрипторов, больше их не будет и не хотим тянуть дополнительную зависимость – БД (например, SQLite) + “ручной” расчет расстояний;

  2. Если вы особо не ограничены по ресурсам и/или уже используете Postgres/ClickHouse, то посмотреть их решения для хранения векторов. Может, они уступают в некоторых моментах, но удобство использования, обогащение мета информацией и отсутствие необходимости добавлять новую технологию, точно являются важным преимуществами и как минимум подспорьем для тестов.

    Вывод

    В данной статье мы рассмотрели подход к построению baseline системы распознавания на микрокомпьютерах, определили пайплайн реализации такой системы и где можно найти подходящие нам по критериям модели. 

    Хочется отметить, что это базовый вариант, который может быть неплох для старта, так как используются достаточно актуальные модели и подходы. Естественно, результат можно улучшить, дообучив модели на своих данных и/или добавив новый функционал к существующему решению. К примеру, спуффинговые модели, re-identification по внешним признакам и это далеко не полный список возможных улучшений. 

    Пишите в комментариях свои вопросы, предложения и идеи!

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


  1. sgjurano
    11.04.2024 17:37
    +1

    Всё же Faiss — это не БД, это библиотека для построения ANN индексов.


  1. dmitrybelsky
    11.04.2024 17:37
    +1

    Ключевой вопрос - зачем? В рамках 572-ФЗ работа абсолютно бесполезна


  1. nulovkin
    11.04.2024 17:37

    Сам по себе дескриптор лица – вектор, который характеризует признаки лица. Чаще всего, чтобы получить такие представления, используют модели, которые учились для решения задачи классификации. После обучения обрезают слои классификации и добавляют нормализацию выхода. В итоге мы получаем векторное представление лица, которое далее можно использовать для поиска похожих.

    А какие признаки можно использовать для такого обучения?
    Я могу представить, что у меня перцептрон определяет цифры, написанные от руки, значит на последнем этапе должен в идеале зажечь один из десяти выходов. Но нам понятно, чем цифры отличаются друг от друга.
    А лица?