Не так чтобы очень давно, в довольно недалекой галактике, на одной провинциальной планетке жили известные потомки обезьян, которые настолько обленились, что решили изобрести искусственный интеллект. «Ну а что?» — подумали они. Хорошо же иметь в советчиках Сверхразум «надмозг», который будет думать за тебя, когда надо, проблемы твои оперативненько решать, да еще и лучше чем это когда-либо сможет сделать живое существо… И, не долго думая о последствиях, начали они свои обезьяньи мозги реверсить и когнитивный процесс на строительные кирпичики разбирать. Думали они, думали и придумали, не поверите — модель нейрона, математический алгоритм обучения, а затем и нейронные сети с разной топологией подтянулись. Конечно, работало это не сказать чтобы очень хорошо. Была масса недостатков, по сравнению с естественным интеллектом, но определенный круг задач данные модели позволяли решать с приемлемой точностью. И начали потихонечку появляться оцифрованные и сериализованные навыки в виде моделей сетей нейронных. Сегодня, дорогие любители истории вселенной, мы коснемся темы организации и внедрения различных навыков интеллекта искусственного.
Про создание и обучение моделей нейронных сетей (навыков) на Хабре написано не мало, поэтому не будем об этом сегодня. Обучив или получив сериализованные навыки ИИ, мы рассчитываем использовать их в наших целевых информационных системах, и тут возникает проблема. То что работает на стенде в лаборатории не перенести в производство в исходном виде, необходимо внедрение всего сопряженного стека технологий и даже существенная доработка под целевую платформу (есть, конечно, исключения в виде CoreML, но это частный случай и только для техники Apple). К тому же, инструментов разработки и сериализации моделей великое множество, неужели для каждого придется разрабатывать отдельное решение для интеграции? Кроме того, даже в лаборатории часто возникает необходимость получить быстрый вывод от модели, не ожидая прогрузки всего связанного девелоперского стека.
В качестве предложения по решению данных проблем я хотел бы рассказать про сравнительно новый opensource инструмент, который, возможно, будет вам полезен при разработке проектов, связанных с ИИ.
0Mind (читай ZeroMind) — свободный сервер навыков. Решение представляет собой модульный, универсальный, легко расширяемый сервер приложений с элементами фреймворка для сервинга (высокодоступного вывода) разнородных моделей машинного обучения. Сервер напиасн на Python 3 и для асинхронной обработки запросов использует Tornado. Вне зависимости от того, с помощью какого фреймворка машинного обучения была подготовлена и сериализована модель, 0Mind позволяет легко использовать навык или группу навыков при помощи универсального REST API. Фактически решение представляет собой асинхронный web-сервер с REST API, унифицированным для работы с моделями навыков ИИ, и набор адаптеров к различным фреймворкам машинного обучения. Вы, возможно, работали с сервингом tensorflow — это похожее решение, но 0Mind не привязан к стеку tf и может сервить несколько моделей разных фреймворков на одном порту. Таким образом, вместо внедрения всего стека технологий для вывода моделей ИИ в целевой информационной системе можно использовать простой и привычный REST API к интересующему навыку, к тому же, подготовленная модель остается на сервере и не попадает в дистрибутив ПО. Чтобы не путать лишний раз сложными терминами, перейдем к примерам использования и начнем кастовать консольные заклинания.
Тут все просто:
Теперь у нас есть рабочий экземпляр сервера. Установим зависимости:
Или, если Вы используете Conda:
Важная оговорка — сервер поддерживает несколько фреймворков машинного обучения, и чтобы не добавлять их все в зависимости, и не устанавливать вместе с ним, Вы самостоятельно решаете модели каких фреймворков Вы будете загружать на хосте с экземпляром 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 и завершает его процесс
Запустить экземпляр сервера можно, например, так:
К примеру, получим общую информацию о запущенном экземпляре сервера:
Отлично, теперь узнаем какие модели загружены в пул:
Теперь давайте уточним интерфейс загруженной модели с идентификатором «1»:
Осталось выяснить, с какими фильтрами загружена модель. Для этого уточним детали задачи по загрузке модели с идентификатором «1»:
Как Вы могли заметить, у нашей модели есть один входной фильтр — i_img_file_to_ns_arr.ImageFileToNormAndScaledNPArrayFilter и он фильтрует вход с именем — conv2d_1_input:0. Данный фильтр просто преобразует указанный файл картинки в тензор и масштабирует его в соответствии со входом модели. Фильтры — еще один замечательный обобщенный инструмент 0Mind. Так как препроцессинг и постпроцессинг данных для моделей одинаков, то можно просто накапливать данные фильтры для быстрого использования в дальнейшей работе с другими моделями, указывая нужный в качестве атрибута задачи по загрузке модели.
Чтож, теперь у нас есть вся необходимая для инференса информация, можем получить вывод из модели. В качестве входных данных используем картинку из тестового набора, входящего в дистрибутив 0Mind samples/image5.png:
На единственный вход модели «conv2d_1_input:0» с фильтром «i_img_file_to_ns_arr.ImageFileToNormAndScaledNPArrayFilter» подаем данные в формате, принимаемом фильтром — [{«image_file»: «samples/image5.png»}]. В ответ от 0Mind получаем вывод модели:
Итак, единственный выход модели «dense_2/Softmax:0» (см. информацию о модели выше) выдал нам вектор уверенности модели в классификации данного изображения. Как видим, наиболее высокая вероятность 0.99 у класса с индексом 6 (классы это цифры 0-9), который соответствует цифре 5. Таким образом, модель успешно справилась с распознаванием рукописи и дала вывод с высокой уверенностью. Время инференса модели на хосте 0Mind составило 0.002135753631591797 секунды, т.к. вывод происходил на обычном x86 CPU.
Теперь выгрузим нашу модель из пула:
Снова загрузим эту же модель, но теперь с другим идентификатором («new») и выходным фильтром модели «io_argmax.ArgMaxFilter», который будет выводить индекс с наибольшей вероятностью из вектора уверенности модели. Нам придется изменить индексы входов и выходов модели — это связано с особенностями работы Keras:
А теперь попросим модель распознать для нас сразу два изображения в одном запросе samples/image5.png и samples/image1.png:
Демонстрационная модель снова не ошиблась.
Расширить возможности 0Mind не трудно, благодаря модульной архитектуре, использованию в проекте популярных инструментов и соглашений по хорошему коду. Главными векторами расширения могут быть:
Про создание и обучение моделей нейронных сетей (навыков) на Хабре написано не мало, поэтому не будем об этом сегодня. Обучив или получив сериализованные навыки ИИ, мы рассчитываем использовать их в наших целевых информационных системах, и тут возникает проблема. То что работает на стенде в лаборатории не перенести в производство в исходном виде, необходимо внедрение всего сопряженного стека технологий и даже существенная доработка под целевую платформу (есть, конечно, исключения в виде 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 не трудно, благодаря модульной архитектуре, использованию в проекте популярных инструментов и соглашений по хорошему коду. Главными векторами расширения могут быть:
- Адаптеры — классы прослойки для работы с новыми фреймворками машинного обучения и нейронных сетей.
- Фильтры — это обработчики данных на входе и выходе моделей навыков
- Обработчики запросов — позволяют добавить новый функционал в запросы и ответы API 0Mind.
Комментарии (11)
limassolsk
26.02.2019 21:41Мдя, такую картинку и до ката. Сейчас опять набегут пострадавшие родители, которые не могут спокойно почитать статьи на хабре рядом с детьми. Им только пару дней назад получилось преодолеть последствия прочтения «Статья про минет»: ученые обработали 109 часов орального секса, чтобы разработать ИИ, который сосет член, а теперь новый вызов — объяснять детям, почему у тёти три сиси.
thauquoo
Как называется болезнь на первой картинке?
rstepanov
Это не болезнь, а расовое многообразие, прекратите дискриминировать!
old_bear
Это не болезнь — это тест на возраст читающих.
Fragster
Картинка в начале — это косплей на римейк 2012 года. Какой уж тут тест на возраст?
old_bear
А откуда вы это знаете? :)
Fragster
Смотрел оба. Еще и оригинальную повесть читал.
old_bear
Так вот и я об этом. Или вы будете отрицать корреляцию между возрастом и фактом просмотра оригинального фильма, который вызывает реакцию вида «косплей на унылый ремейк»? Не говоря уже про чтение Филипа нашего Дика.
Mistx Автор
Хоминус троесисиус! А если серьезно, то было давно такое кино, с названием, созвучным с тайтлом статьи. Автор скорее предпочитает оригинальную версию, но увы картинки в приличном качестве не нашлось, поэтому была взята эта картинка из новодела.