- PVSM.RU - https://www.pvsm.ru -
Здравствуйте, уважаемыее!
Последние два года моей работы в компании Synesis [1] были тесно связаны с процессом создания и развития Synet [2] — открытой библиотеки для запуска предварительно обученных сверточных нейронных сетей на CPU. В процессе этой работы мне пришлось столкнуться с рядом интересных моментов, которые касаются вопросов оптимизации алгоритмов прямого распространения сигнала в нейронных сетях. Как мне кажется, описание этих моментов было бы весьма интересным для читателей Хабрахабра. Чему я и хочу посвятить цикл своих статей. Продолжительность цикла будет зависеть от вашего интереса к данной теме ну и конечно же от моей способности побороть лень. Начать цикл хочется с описания самого велосипеда фреймворка. Вопросы алгоритмов, которые лежат в его основе будут раскрыты в последующих статьях.
Прежде, чем начинать подробное описание фреймворка, постараюсь сразу ответить на ряд вопросов, которые наверняка возникнут у читателей. Опыт подсказывает, что лучше это сделать заранее, так как многие сразу начинают писать гневные комментарии, не дочитав до конца.
Первый вопрос, который обычно возникает в таких случаях: Да кто сейчас запускает сети на обычных процессорах, когда есть графические ускорители и тензорные (матричные) ускорители?
Отвечу, что да — обучение нейросетей действительно не целесообразно выполнять на CPU, но вот запускать уже готовые нейросети — вполне себе востребованная задача, особенно если сеть достаточно небольшого размера. Причины для этого могут быть разные, но основные:
Следующий возможный вопрос: A зачем использовать для запуска специализированное решение, когда есть Tensorflow [3], Caffe [4] или MXNet [5]?
Ответить на это можно следующее:
Тут сразу логично возникает вопрос про изобретение велосипеда: Зачем использовать свою поделку, когда есть вполне профессиональное решение от признанного мирового лидера?
Отвечу так:
Вероятно, у читателей возникнут и другие вопросы или возражения — но их я пока предугадать не могу и потому отвечу в комментариях к статье. А пока приступим к непосредственному описанию Synet.
Synet написан на С++ и содержит только заголовочные файлы [7]. Низкоуровневые платформозависимые оптимизации реализованы в Simd [8] — другом open-source проекте, посвященном ускорению обработки изображений на CPU. И это единственная внешняя зависимость Synet (такая схема выбрана с целью облегчения интеграции библиотеки в сторонние проекты). Для запуска нейросетей используются модели собственного внутреннего формата.
Конвертация предварительно обученных моделей во внутренний формат осуществляется по двухшаговой схеме: 1) Сначала конвертируем модель в формат Inference Engine (благо
в OpenVINO есть для этого все необходимые инструменты [9]). 2) Затем из этого промежуточного представления конвертируем непосредственно во внутренний формат Synet.
Модель Synet содержит два файла: 1) *.XML — файл с описанием структуры модели. 2) *.BIN — файл с обученными весами.
Ниже приведен пример, использования Synet для детектирования лиц. Оригинальная модель Inference Engine взята здесь [10].
#define SYNET_SIMD_LIBRARY_ENABLE
#include "Synet/Network.h"
#include "Synet/Converters/InferenceEngine.h"
#include "Simd/SimdDrawing.hpp"
typedef Synet::Network<float> Net;
typedef Synet::View View;
typedef Synet::Shape Shape;
typedef Synet::Region<float> Region;
typedef std::vector<Region> Regions;
int main(int argc, char* argv[])
{
Synet::ConvertInferenceEngineToSynet("ie_fd.xml", "ie_fd.bin",
true, "synet.xml", "synet.bin");
Net net;
net.Load("synet.xml", "synet.bin");
net.Reshape(256, 256, 1);
Shape shape = net.NchwShape();
View original;
original.Load("faces_0.ppm");
View resized(shape[3], shape[2], original.format);
Simd::Resize(original, resized, ::SimdResizeMethodArea);
net.SetInput(resized, 0.0f, 255.0f);
net.Forward();
Regions faces = net.GetRegions(original.width, original.height, 0.5f, 0.5f);
uint32_t white = 0xFFFFFFFF;
for (size_t i = 0; i < faces.size(); ++i)
{
const Region & face = faces[i];
ptrdiff_t l = ptrdiff_t(face.x - face.w / 2);
ptrdiff_t t = ptrdiff_t(face.y - face.h / 2);
ptrdiff_t r = ptrdiff_t(face.x + face.w / 2);
ptrdiff_t b = ptrdiff_t(face.y + face.h / 2);
Simd::DrawRectangle(original, l, t, r, b, white);
}
original.Save("annotated_faces_0.ppm");
return 0;
}
В результате работы примера должна появится картинка с аннотированными лицами:
Теперь давайте разберем пример по шагам:
Synet::ConvertInferenceEngineToSynet("ie_fd.xml", "ie_fd.bin", true, "synet.xml", "synet.bin");
В реальности это шаг делается один раз, а потом везде используется уже сконвертированная модель.
Net net;
net.Load("synet.xml", "synet.bin");
net.Reshape(256, 256, 1);
View original;
original.Load("faces_0.ppm");
View resized(net.NchwShape()[3], net.NchwShape()[2], original.format);
Simd::Resize(original, resized, ::SimdResizeMethodArea);
net.SetInput(resized, 0.0f, 255.0f);
net.Forward();
Regions faces = net.GetRegions(original.width, original.height, 0.5f, 0.5f);
Наверное было бы не совсем корректно сравнивать Synet с классическими фреймворками для машинного обучения, например Inference Engine на ряде тестов их обходит в разы [11].
Потому ниже приведен пример сравнения однопоточной производительности Inference Engine (продукта схожей функциональности) и Synet на выборке из набора открытых моделей [12]:
Test | Description | i7-6700 3.4GHz 4c/8t FMA/AVX-2 | i9-7900X 3.3GHz 10c/20t AVX-512 |
---|---|---|---|
test_000 [13] | Vehicle attributes recognition (2.4 MB) | 1.520 / 1.597 ms (-5%) | 0.772 / 0.690 ms (+12%) |
test_001 [14] | Age gender recognition (8.2 MB) | 1.659 / 1.418 ms (+17%) | 0.988 / 0.804 ms (+23%) |
test_002 [15] | Face detection (4.0 MB) | 34.26 / 43.17 ms (-21%) | 26.72 / 24.57 ms (+9%) |
test_003f [10] | Face detection (2.2 MB) | 12.63 / 14.87 ms (-15%) | 8.680 / 9.326 ms (-7%) |
test_004 [16] | Licence plate recognition (4.6 MB) | 4.350 / 4.871 ms (-11%) | 2.838 / 2.432 ms (+17%) |
test_005 [17] | Licence plate recognition (0.7 MB) | 0.339 / 0.260 ms (+30%) | 0.200 / 0.142 ms (+41%) |
test_006 [18] | Face reidentification (4.2 MB) | 11.82 / 9.052 ms (+31%) | 8.200 / 4.559 ms (+80%) |
test_007 [19] | Person reidentification (3.1 MB) | 3.567 / 3.402 ms (+5%) | 2.471 / 1.679 ms (+47%) |
Average | +2% | +25% |
Как видно из таблицы, на данных тестах на машине с поддержкой AVX2 (i7-6700) производительность Synet в целом соответствует производительности Inference Engine (хотя и сильно варьируется от модели к модели). На машине с поддержкой AVX-512 (i9-7900X) производительность Synet в среднем на 25% превышает таковую у Inference Engine.
Все измерения проводились тестовым приложением, которое есть в Synet. Так что при желании, читатели смогут воспроизвести тесты у себя:
git clone -b master --recurse-submodules -v https://github.com/ermig1979/Synet.git synet
cd synet
./build.sh inference_engine
./test.sh
Начну с плюсов:
Ну и минусы, куда же без них:
В настоящее время Synet используется в рамках проекта Kipod [20] — облачной платформы для видеоаналитики. Возможно у него есть и другие пользователи, но это не точно :). В дальнейшем, по мере развития проекта, в него хотелось бы добавить следующие вещи:
Этот список далеко не полный, и дополнять его хотелось бы с учетом мнения сообщества — потому жду ваших отзывов! Чтобы инструмент был полезным не только нашей компании, но и широкому кругу пользователей. Также автор не отказался бы от помощи сообщества в процессе разработки.
При описании Synet, которое я сделал в этой статье, я намеренно не углублялся в детали ее внутренней реализации — под капотом много вкусных алгоритмов, но детали их реализации хотелось бы раскрыть в следующих статьях цикла.
Автор: Ермолаев Игорь
Источник [21]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/open-source/333314
Ссылки в тексте:
[1] Synesis: https://synesis.ru/
[2] Synet: https://github.com/ermig1979/Synet
[3] Tensorflow: https://github.com/tensorflow/tensorflow
[4] Caffe: https://github.com/BVLC/caffe
[5] MXNet: https://mxnet.apache.org/
[6] OpenVINO: https://github.com/opencv/dldt
[7] заголовочные файлы: https://github.com/ermig1979/Synet/tree/master/src/Synet
[8] Simd: https://github.com/ermig1979/Simd
[9] инструменты: https://docs.openvinotoolkit.org/latest/_docs_MO_DG_Deep_Learning_Model_Optimizer_DevGuide.html
[10] здесь: https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/face-detection-retail-0004/FP32
[11] на ряде тестов их обходит в разы: https://github.com/IntelAI/OpenVINO-model-server/blob/master/docs/benchmark.md
[12] набора открытых моделей: https://download.01.org/opencv/2019/open_model_zoo/
[13] test_000: https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/vehicle-attributes-recognition-barrier-0039/FP32
[14] test_001: https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/age-gender-recognition-retail-0013/FP32
[15] test_002: https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/face-detection-adas-0001/FP32
[16] test_004: https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/license-plate-recognition-barrier-0001/FP32
[17] test_005: https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/landmarks-regression-retail-0009/FP32
[18] test_006: https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/face-reidentification-retail-0095/FP32
[19] test_007: https://download.01.org/opencv/2019/open_model_zoo/R1/2019/person-reidentification-retail-0079/FP32
[20] Kipod: https://kipod.ru
[21] Источник: https://habr.com/ru/post/471074/?utm_source=habrahabr&utm_medium=rss&utm_campaign=471074
Нажмите здесь для печати.