root/public/: sdk-loop-0.0.10 metadata and description
Python sdk loop for estimation face attributes
author | visionlabs |
classifiers |
|
description_content_type | text/markdown |
requires_dist |
|
requires_python | >=3.12,<4.0 |
File | Tox results | History |
---|---|---|
sdk_loop-0.0.10-py3-none-any.whl
|
|
|
sdk_loop-0.0.10.tar.gz
|
|
Luna python SDK loop
Данный фреймворк предназначен для эффективного асинхронного эстимирования атрибутов лица и тела. Эффективность достигается за счёт батчинга запросов на эстимацию той или иной фичи. SDK Loop в первую очередь ориентирован на потребности сервиса luna-handlers и его логику.
Принципы работы
Батчинг запросов
В основе библиотеки принцип: если надо эстимировать некоторую фичу, то нужно батчить запросы
. Таким образом на самом
нижнем уровне лежит механизм батчинга запросов. Батчинг осуществляется путём складывания задач на эстимацию конкретной
фичи в отдельную очередь. К каждой очереди подключён один или несколько воркреров, которые производят эстимацию
соответствующего атрибута.
Чтобы добавить в библиотеку эстимацию нового атрибута, необходимо в первую очередь реализовать два абстрактных класса:
QueueEstimatorBase
и EstimationBrokerBase
.
Первый класс является непосредственно эстиматором, который берёт оптимальное количество данных из очереди для
формирования батча и последующей эстимации. Если на данный момент данных
меньше, чем оптимальное количество - воркер возьмёт что есть и извлечёт из этого, то есть не будет дожидаться
поступления новых данных для эстимации. Пока воркер извлекает, данные для следующей эстимации накапливаются.
Warning: так как fsdk и flower имеют свой пул потоков, который глобальный, то простое добавление воркеров не ускоряет выполнение той или иной эстимации. Ускорение происходит скорее за счёт того, что мы не ожидаем завершение очередной задачи на эстимирование. Таким образом задачи во flower идут более плотно, простой уменьшается. Кажется, что больше двух-трёх воркеров на эстиматор не имеет смысла ставить.
Второй класс (EstimationBrokerBase
) отвечает за то, чтобы инициализировать необходимое кол-во воркеров с общей
очередью и наполнением последней.
В силу того, что при аггрегации мы должны батчить только картинки, которые пользователь передал в одном запросе, то мы разделяем классы, которые эстимируют атрибут и соответствующий аггрегированный атрибут. Таким образом если из вне идут задачи на эстимацию как обычных, так и агрегированных дескрипторов (условно), то все эти задачи разделяются на разные потоки выполнения и не мешаются друг другу при накоплении батча. Аналогичная история с 68 точками лица. Данные эстимации могут отжирать большое количество памяти и времени, поэтому есть отдельный детектор лиц, который вычисляет 68 точек и детектор лиц, который не вычисляет их.
Инициализация глобального Runtime
Все инстансы FaceEngine
имеют один глобальный инстанс runtime flower-а. Он создаётся при первом создании инстанса
FaceEngine
и живёт, пока существует хотя бы один инстанс. Поэтому, чтобы избежать попыток двойной инициализации
runtime-а был добавлен синглтон initFE
, который должен позваться единажды перед началом пользования sdkloop.
Соответственно в нём устанавливается глобальный runtime и дефолтный конфиг для создания FaceEngine
, после этого
её звать нельзя. Для получения инстансов FaceEngine
необходимо использовать getFE
функцию.
Коллекция эстиматоров
В реальной жизни нам нужно сразу несколько эстиматоров. Поэтому был организован специальный контейнер, в котором лежат
интересующие нас эстиматоры EstimatorsCollection
. Он умеет только инициализировать и останавливать интересующие нас
SDK эстиматоры. Почти все эстиматоры хранятся в одном экземпляре. Исключение составляет экстракторы дескрипторов тел и
лиц. Так как luna-handlers предполагает работу сразу с несколькими версиями дескрипторов, то для данных эстиматоров
содержится словарь: ключ - версия дескриптора, значение - экстрактор данной версии. Изначально в данном словаре лежит
только экстрактор дефолтной версии (если вообще пользователя интересуют дескрипторы).
SDKEngine
SDKEngine - универсальный эстиматор, который хранит в себе коллекцию эстиматоров и работает с болеее высокоуровневыми сущностями как семплы. Сэмплы - это контейнер для хранения эстимаций. Есть 4 вида сэмплов:
- FaceSample - сэмпл лица, создаётся либо из задетектированного лица, либо из переданного варпа лица;
- AggregatedFaceSample - контейнер для агрегированных атрибутов лица. Предполагается, что все атрибуты агрегируются из одного и того же набора сэмплов лиц;
- BodySample - сэмпл тела, создаётся либо из задетектированного тела человека, либо из переданного варпа тела;
- AggregatedBodySample - контейнер для агрегированных атрибутов тела. Предполагается, что все атрибуты агрегируются из одного и того же набора сэмплов тел.
На вход эстимирующим функциям SDKEngine поступают соответствующие сэмплы, предполагается, что внутри них уже всё вычисленно для выполнения эстимации (например, если нужны 68 точек, то они вычисленны, проверок пока нет). Функция устанавливает соответствующий атрибут в сэмпл а так же возвращает то, что поэстимировала.
Отдельно в SDKEngine стоит детектирование тел и лиц. Детекторы отличаются от эстиматоров тем, что результат работы может быть пустым. А ещё мы детектируем людей, то есть лица и тела. Когда идёт редетект чего-то, под капотом запускаются детекторы тел и детекторы лиц, а потом происходит анализ на одном изображение, какие тела и лица принадлежат одному и тому же человеку.
Также SDKEngine отвечает за загрузку лиц в VLImage и поворот картинки, если мы выяснили, что она повёрнута. Загрузка картинки происходит в отдельном треде (pillow отпускает gil).
Task
Все предыдущие сущности не содержали пользовательской логики по типу фильтрации, ошибок на то, что два лица на
изображении и т.п. вещи. Для этого предназначен специальный абстрактный класс BaseTask
. Предполагается, что сценарий
поведения будет настраиваться при реализации данного класса. Для нужд Luna-handlers был создан класс HandlersTask
,
который отражает логику, зашитую в сервисе. Пользовательский класс нужно предварительно инициализировать, после чего он
готов выполнять все задачи. У таски есть контент и есть результат.
Предполагается, что первым шагом при обработке задачи будет загрузка картинок в формат SDK (метод prepare
). В
результате данного метода инициализируются структуры Image
из входящих изображений. Если картинка загрузилась с
ошибкой, то в атрибуте error
данного изображения можно будет узнать, что пошло не так. С остальными картинками можно
продолжать работу, после этого, до момента агрегации можно производить работу с каждым изображение из таски независимо и
параллельно.
Так же предполагается, что если в результате работы некоторого эстиматора произошла ошибка, то она поместится в
соответсвующее поле для изображения, на котором произошла ошибка, либо сразу общую ошибку для всей
задаче task.result.error
.
Мониторинг
Для обеспечения мониторинга эстимирования атрибутов в SDK loop реализован механизм сбора некоторых метрик. Все метрики
хранятся в глобальных объектах, которые определены в следующем sdk_loop/monitoring_utils/storages.py.
. Метрики
представляют собой временные ряды. Для каждой точки временного ряда указывается время, когда она была получена, набор
тэгов (индексируемые данные) и полей (неиндексируемые данные). Контейнеры с метриками представляют собой мапы имени
серии к самому временному ряду.
Выделено три вида данных для мониторинга:
- TASK_EXECUTION_MONITORING - общая информация о том, как выполнена задача (см TaskMonitoringPoint)
- количество переданных изображений
- время выполнения
- IMAGE_LOAD_MONITORING - информация о загруженных картинках (см ImageLoadPoint)
- врямя загрузки
- тип картинки
- размер картинки в байтах
- извлекали ли exif
- выполнялся ли автоповорот
- ширина картинки
- высота картинки
- ESTIMATION_MONITORING - информация о работе каждого отдельного эстиматора. Для разных эстиматоров могут быть интересны
разные вещи. общие характеристики (см EstimationPoint):
- размер батча, который был собран для эстимации
- время эстимации
Данные в мониторинге копятся до тех пор, пока за ними не придут и не заберут через метод popValues
. Сбор мониторинга
можно отключить, указав для соответствующего контейнера данных enable = False
, например
ESTIMATION_MONITORING.enable = False
.
Установка
Для установки потребуется FSDK. Актуальную версию можно посмотреть в .gitlab-ci.yml
(LUNA_SDK_TAG
). После этого
требуется установить переменную окружения FSDK_ROOT
, которая указывает на корень скаченной и разархивированной SDK. Из
внешних зависимостей python3.10
, poetry
. После клонирования проекта выполняем в корне проекта:
poetry install
Чтобы проверить, что всё работает, можно запустить демо
poetry shell python examples/demo.py
Warning: в силу специфики sdk, если есть видео карточка, но мы всё хотим запускать на cpu, необходимо устанавливать
переменную окружения CUDA_VISIBLE_DEVICES
перед инициализацией эстиматоров и создания инстансов FaceEngine
в значение -1, чтобы не аллоцировать память на карточке.
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
Тесты
Unittest
Есть набор юнит тестов, которые запускаются простой командой:
poetry shell
pytest
Тесты конфигурируются в файле tests/unittests/configuration.py
. Девайс (cpu/gpu) можно так же конфигурировать через
переменную окружения
Benchmark
Так же реализован некоторый бенчмарк, который позволяет посмотреть насколько быстро мы можем эстимировать различные атрибуты под нагрузкой. Суть бенчмарка состоит в том, что заранее определённая таска (то, что собираемся эстимировать) начинает выполнятся с заданной конкурентностью заданное количество раз. Таким образом мы иммитируем конкурентные запросы в сервис. Измеряется всё время теста и среднее время выполнения задачи.
Запуск
Можно использовать дефолтные настройки и запустить
poetry shell cd tests/test_benchmark python test_benchmark.py
Так же можно поменять некоторые параметры
--settings_path
- путь до конфиг файла бенчмарка--concurrency
- уровень конкрурентности, сколько одновременно задач будет выполняться--tasks_num
- общее количество тасок--log_file
- имя файла с логами
Пример:
poetry shell cd tests/test_benchmark python test_benchmark.py --setting_path high_load_settings.json --concurrency 10 --tasks_num 1000 --log_file logs/output.log