Сервим всё

Не так чтобы очень давно, в довольно недалекой галактике, на одной провинциальной планетке жили известные потомки обезьян, которые настолько обленились, что решили изобрести искусственный интеллект. «Ну а что?» — подумали они. Хорошо же иметь в советчиках Сверхразум «надмозг», который будет думать за тебя, когда надо, проблемы твои оперативненько решать, да еще и лучше чем это когда-либо сможет сделать живое существо… И, не долго думая о последствиях, начали они свои обезьяньи мозги реверсить и когнитивный процесс на строительные кирпичики разбирать. Думали они, думали и придумали, не поверите — модель нейрона, математический алгоритм обучения, а затем и нейронные сети с разной топологией подтянулись. Конечно, работало это не сказать чтобы очень хорошо. Была масса недостатков, по сравнению с естественным интеллектом, но определенный круг задач данные модели позволяли решать с приемлемой точностью. И начали потихонечку появляться оцифрованные и сериализованные навыки в виде моделей сетей нейронных. Сегодня, дорогие любители истории вселенной, мы коснемся темы организации и внедрения различных навыков интеллекта искусственного.


Про создание и обучение моделей нейронных сетей (навыков) на Хабре написано не мало, поэтому не будем об этом сегодня. Обучив или получив сериализованные навыки ИИ, мы рассчитываем использовать их в наших целевых информационных системах, и тут возникает проблема. То что работает на стенде в лаборатории не перенести в производство в исходном виде, необходимо внедрение всего сопряженного стека технологий и даже существенная доработка под целевую платформу (есть, конечно, исключения в виде CoreML, но это частный случай и только для техники Apple). К тому же, инструментов разработки и сериализации моделей великое множество, неужели для каждого придется разрабатывать отдельное решение для интеграции? Кроме того, даже в лаборатории часто возникает необходимость получить быстрый вывод от модели, не ожидая прогрузки всего связанного девелоперского стека.
В качестве предложения по решению данных проблем я хотел бы рассказать про сравнительно новый opensource инструмент, который, возможно, будет вам полезен при разработке проектов, связанных с ИИ.

0Mind (читай ZeroMind) — свободный сервер навыков. Решение представляет собой модульный, универсальный, легко расширяемый сервер приложений с элементами фреймворка для сервинга (высокодоступного вывода) разнородных моделей машинного обучения. Сервер напиасн на Python 3 и для асинхронной обработки запросов использует Tornado. Вне зависимости от того, с помощью какого фреймворка машинного обучения была подготовлена и сериализована модель, 0Mind позволяет легко использовать навык или группу навыков при помощи универсального REST API. Фактически решение представляет собой асинхронный web-сервер с REST API, унифицированным для работы с моделями навыков ИИ, и набор адаптеров к различным фреймворкам машинного обучения. Вы, возможно, работали с сервингом tensorflow — это похожее решение, но 0Mind не привязан к стеку tf и может сервить несколько моделей разных фреймворков на одном порту. Таким образом, вместо внедрения всего стека технологий для вывода моделей ИИ в целевой информационной системе можно использовать простой и привычный REST API к интересующему навыку, к тому же, подготовленная модель остается на сервере и не попадает в дистрибутив ПО. Чтобы не путать лишний раз сложными терминами, перейдем к примерам использования и начнем кастовать консольные заклинания.

Установка


Тут все просто:

git clone git@github.com:MisteryX/0Mind.git 0Mind

Теперь у нас есть рабочий экземпляр сервера. Установим зависимости:

cd 0Mind
pip3 install -r requirements.txt

Или, если Вы используете Conda:

conda install --yes --file requirements.txt

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

Настройка


Точкой входа или главным исполняемым файлом сервера является model_pool.py.
Возможные параметры запуска или --config_file с указанием пути к файлу конфигурации. По умолчанию 0Mind использует файл configs/model_pool_config.json в качестве конфигурационного. Сервер также использует файл сonfigs/logger.json для управления стандартным логированием модуля logging Python.

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

Главными настроечными параметрами сервера являются: id, host, port, tasks.

id — (число) уникальный идентификатор пула моделей (используется для балансировки и адресации в распределенной сети пулов)
host — (строка) сетевой адрес или доменное имя данного хоста
port — (число) на каком порту Вы желаете разместить сервис 0Mind (должен быть свободен на данном хосте)
tasks — (список объектов) список задач, загружаемых вместе с сервисом (может быть пустым). В дефолтном конфиге загружается демонстрационная модель CNN_MNIST, подготовленная в Keras, ею мы и воспользуемся для демонстрации возможностей.

Дополнительные (не обязательные) параметры конфигурации:

model_types — (список строк) вы можете ограничить типы загружаемых моделей в данный пул, указав их в данном списке. Если список пуст, то ограничения отсутствуют.

debug — (Булевый тип) отвечает за включение или отключение режима отладки Tornado. В режиме отладки в случае возникновения ошибок в stdout возвращается расширенная информация об ошибке, что полезно при разработке расширений.

Возможности


Главное в 0Mind — это перечень поддерживаемых фреймворков и возможности REST API.

Запросы к REST API можно выполнять с помощью браузера или http утилит. В этом руководстве, как и в документации к серверу, будем использовать cURL, как наиболее простой и доступный инструмент открытых систем.

На данный момент API 0Mind насчитывает всего 10 запросов:

1. http://$HOST:$PORT/info — общая информация об экземпляре 0Mind
2. http://$HOST:$PORT/info/system — системная информация о хосте на котором запущен 0Mind
3. http://$HOST:$PORT/info/task — информация об указанной задаче
4. http://$HOST:$PORT/info/tasks — список задач экземпляра 0Mind
5. http://$HOST:$PORT/model/list — список идентификаторов моделей загруженных в пул
6. http://$HOST:$PORT/model/info — выводит интерфейсную информацию о модели
7. http://$HOST:$PORT/model/load — загружает новую модель в пул
8. http://$HOST:$PORT/model/drop — выгружает ранее загруженную модель из пула
9. http://$HOST:$PORT/model/predict — запрашивает вывод из модели
10.http://$HOST:$PORT/command/stop — останавливает сервис 0Mind и завершает его процесс

Информация


Запустить экземпляр сервера можно, например, так:

python3 model_pool.py

К примеру, получим общую информацию о запущенном экземпляре сервера:

curl http://127.0.0.1:5885/info

{"service": "ModelPool", "id": 1, "options": {"debug": false}, "version": [1, 1, 4]}

Отлично, теперь узнаем какие модели загружены в пул:

curl http://127.0.0.1:5885/model/list

{"id": 1, "check_sum": "4d8a15e3cc35750f016ce15a43937620", "models": ["1"]}

Теперь давайте уточним интерфейс загруженной модели с идентификатором «1»:

curl http://127.0.0.1:5885/model/info?id=1

{"inputs": {"0": {"name": "conv2d_1_input:0", "type": "float32", "shape": [null, 28, 28, 1]}}, "outputs": {"0": {"name": "dense_2/Softmax:0", "type": "float32", "shape": [null, 10]}}, "tool": "keras"}

Осталось выяснить, с какими фильтрами загружена модель. Для этого уточним детали задачи по загрузке модели с идентификатором «1»:

curl http://127.0.0.1:5885/info/task?id=1

{"id": "1", "model_file": "ML/models/mnist_cnn_model.keras", "model_type": "keras", "input_filters": {"conv2d_1_input:0": ["i_img_file_to_ns_arr.ImageFileToNormAndScaledNPArrayFilter"]}, "output_filters": {}}

Как Вы могли заметить, у нашей модели есть один входной фильтр — i_img_file_to_ns_arr.ImageFileToNormAndScaledNPArrayFilter и он фильтрует вход с именем — conv2d_1_input:0. Данный фильтр просто преобразует указанный файл картинки в тензор и масштабирует его в соответствии со входом модели. Фильтры — еще один замечательный обобщенный инструмент 0Mind. Так как препроцессинг и постпроцессинг данных для моделей одинаков, то можно просто накапливать данные фильтры для быстрого использования в дальнейшей работе с другими моделями, указывая нужный в качестве атрибута задачи по загрузке модели.

Вывод данных из модели (инференс)


Чтож, теперь у нас есть вся необходимая для инференса информация, можем получить вывод из модели. В качестве входных данных используем картинку из тестового набора, входящего в дистрибутив 0Mind samples/image5.png:



curl -d '{"conv2d_1_input:0": [{"image_file": "samples/image5.png"}]}' -H "Content-Type:application/json" -X POST http://127.0.0.1:5885/model/predict?id=1

На единственный вход модели «conv2d_1_input:0» с фильтром «i_img_file_to_ns_arr.ImageFileToNormAndScaledNPArrayFilter» подаем данные в формате, принимаемом фильтром — [{«image_file»: «samples/image5.png»}]. В ответ от 0Mind получаем вывод модели:

{"result": {"dense_2/Softmax:0": [[2.190017217283827e-21, 1.6761866200587505e-11, 2.2447325167271673e-14, 0.00011080023978138342, 1.881280855367115e-17, 0.9998891353607178, 1.6690393796396863e-16, 9.67975005705668e-12, 1.1265206161566871e-13, 2.086113400079359e-13]]}, "model_time": 0.002135753631591797}

Итак, единственный выход модели «dense_2/Softmax:0» (см. информацию о модели выше) выдал нам вектор уверенности модели в классификации данного изображения. Как видим, наиболее высокая вероятность 0.99 у класса с индексом 6 (классы это цифры 0-9), который соответствует цифре 5. Таким образом, модель успешно справилась с распознаванием рукописи и дала вывод с высокой уверенностью. Время инференса модели на хосте 0Mind составило 0.002135753631591797 секунды, т.к. вывод происходил на обычном x86 CPU.

Динамическая загрузка и выгрузка моделей


Теперь выгрузим нашу модель из пула:

curl http://127.0.0.1:5885/model/drop?id=1

{"result": true, "unload_time": 0.000152587890625, "memory_released": 0, "model_id": "1"}

Снова загрузим эту же модель, но теперь с другим идентификатором («new») и выходным фильтром модели «io_argmax.ArgMaxFilter», который будет выводить индекс с наибольшей вероятностью из вектора уверенности модели. Нам придется изменить индексы входов и выходов модели — это связано с особенностями работы Keras:

curl -d '{"id": "new", "output_filters": {"dense_2_1/Softmax:0": ["io_argmax.ArgMaxFilter"]}, "model_file": "ML/models/mnist_cnn_model.keras", "input_filters": {"conv2d_1_input_1:0": ["i_img_file_to_ns_arr.ImageFileToNormAndScaledNPArrayFilter"]}, "model_type": "keras"}' -H "Content-Type:application/json" -X POST http://127.0.0.1:5885/model/load

{"result": true, "load_time": 0.45618462562561035, "memory_consumed": 16183296, "model_id": "new"}

А теперь попросим модель распознать для нас сразу два изображения в одном запросе samples/image5.png и samples/image1.png:


curl -d '{"conv2d_1_input:0": [{"image_file": "samples/image5.png"}, {"image_file": "samples/image1.png"}]}' -H "Content-Type:application/json" -X POST http://127.0.0.1:5885/model/predict?id=new

{"result": {"dense_2_1/Softmax:0": [5, 1]}, "model_time": 0.003907206535339355}

Демонстрационная модель снова не ошиблась.

Расширение


Расширить возможности 0Mind не трудно, благодаря модульной архитектуре, использованию в проекте популярных инструментов и соглашений по хорошему коду. Главными векторами расширения могут быть:

  1. Адаптеры — классы прослойки для работы с новыми фреймворками машинного обучения и нейронных сетей.
  2. Фильтры — это обработчики данных на входе и выходе моделей навыков
  3. Обработчики запросов — позволяют добавить новый функционал в запросы и ответы API 0Mind.
Поделиться публикацией

Комментарии 11

    +1
    Как называется болезнь на первой картинке?
      +2
      Это не болезнь, а расовое многообразие, прекратите дискриминировать!
        +3
        Это не болезнь — это тест на возраст читающих.
          0
          Картинка в начале — это косплей на римейк 2012 года. Какой уж тут тест на возраст?
            0
            А откуда вы это знаете? :)
              0
              Смотрел оба. Еще и оригинальную повесть читал.
                0
                Так вот и я об этом. Или вы будете отрицать корреляцию между возрастом и фактом просмотра оригинального фильма, который вызывает реакцию вида «косплей на унылый ремейк»? Не говоря уже про чтение Филипа нашего Дика.
          +1
          Хоминус троесисиус! А если серьезно, то было давно такое кино, с названием, созвучным с тайтлом статьи. Автор скорее предпочитает оригинальную версию, но увы картинки в приличном качестве не нашлось, поэтому была взята эта картинка из новодела.
          0
          Можно человеческий про зависимости и остальные вещи. А то вдруг выясняется какой-нибудь питон-дев или питон-дев-алл. А то мы тоже порезвимсяя на Groovy и Даже VBA в нормальном MS Officce 2000 года.
            0
            Раздел Установка — requirements.txt
            +1
            Мдя, такую картинку и до ката. Сейчас опять набегут пострадавшие родители, которые не могут спокойно почитать статьи на хабре рядом с детьми. Им только пару дней назад получилось преодолеть последствия прочтения «Статья про минет»: ученые обработали 109 часов орального секса, чтобы разработать ИИ, который сосет член, а теперь новый вызов — объяснять детям, почему у тёти три сиси.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое