Каждый должен делать свою работу качественно и в срок. Допустим, вам нужно сделать веб-сервис классификации картинок на базе обученной нейронной сети с помощью библиотеки caffe. В наши дни качество — это асинхронные неблокирующие вызовы, возможность параллельного исполнения нескольких заданий при наличии свободных процессорных ядер, мониторинг очередей заданий… Библиотека RQ позволяет реализовать все это в сжатые сроки без изучения тонны документации.
Сделаем веб-сервис на одном сервере, ориентированный на несильно нагруженные проекты и сравнительно длительные задания. Естественно, его применение не ограничивается этими вашими нейронными сетями.
Постановка задачи
Входными данными является файл (например, картинка в формате JPEG). Для простоты считаем, что ее уже разместили в выделенную директорию. Выходными данными является строка в формате JSON. Для солидности будем пользоваться стандартными кодами результатов HTTP.
Веб-сервис будет реализовывать два HTTP-вызова (назовём это API):
- /process/[имя файла] — обработать файл (предварительно загружаем входной файл в выделенную директорию, возвращаем идентификатор задания)
- /result/[идентификатор задания] — получить результат (если результат не готов, возвращаем код 202 «Not ready», если результат готов — возвращаем json, если идентификатор задания не существует, возвращаем код 404 «Not found»)
Инсталлируем компоненты в Ubuntu
В качестве HTTP-сервера будем использовать Flask. Установка:
Если не установлен pip:
sudo apt-get install python-pip
sudo apt-get install --upgrade pipСобственно, установка Flask:
sudo pip install flaskТеперь нужно установить Redis — хранилище данных и брокер сообщений:
wget http://download.redis.io/redis-stable.tar.gz
tar xvzf redis-stable.tar.gz
cd redis-stable
makeУстановка библиотеки RQ (Redis Queue):
sudo pip install rqДля автоматического запуска и конфигурации всех компонентов будем использовать Supervisor:
sudo apt-get install supervisorПишем наш сервис
Это легко в Flask. Создадим файл deep_service.py:
#Путь к директории, выделенной под хранение входных файлов
BASEDIR = '/home/sergey/verysecure'
#Импортируем служебные библиотеки
import argparse
import os
import json
#Импортируем только что установленные компоненты нашего сервиса
from flask import Flask
app = Flask(__name__)
from redis import Redis
from rq import Queue
#Импортируем функцию, реализующую наш вычислительный процесс, который будет выполняться асинхронно
#classify.py - модуль, поставляемый с библиотекой машинного обучения caffe
#Естественно, вместо него можно импортировать собственные разработки
from classify import main
#Подключаемся к базе данных Redis
q = Queue(connection=Redis(), default_timeout=3600)
#Реализуем первый вызов нашего API
@app.route('/process/<path:file_path>')
def process(file_path):
full_path = os.path.join(BASEDIR, file_path) #входной файл лежит в директории BASEDIR
argv = {'input_file': full_path,
'gpu': True}
args = argparse.Namespace(**argv)
r = q.enqueue_call(main, args=(args,), result_ttl=86400)
return r.id
#В порядке обмена опытом: ограничим 4-мя цифрами после запятой вещественные числа,
#при сериализации в JSON из массива numpy
def decimal_default(obj):
if isinstance(obj, float32):
return round(float(obj), 4)
else:
raise TypeError()
#Реализуем второй вызов нашего API
@app.route('/result/<id>')
def result(id):
try:
job = q.fetch_job(id)
if job.is_finished:
return json.dumps(job.result, ensure_ascii=False, default=decimal_default)
else:
return 'Not ready', 202
except:
return "Not found", 404
if __name__ == '__main__':
app.run()
#app.run(debug=False, host='0.0.0.0')Запуск вручную — проверяем как работает
На этом этапе можно проверить, работает ли наш веб-сервис. Запускаем Redis:
redis-serverЗапускаем один рабочий процесс (их можно запускать несколько, например по количеству процессорных ядер или по наличию нескольких видеокарт, если они требуются для обработки данных). Процесс лучше запускать из той директории, в которой будут запускаться вычислительные функции, в нашем случае это там, где лежит classif.py:
rq workerЗапускаем http-сервер:
python deep_service.pyЗаписываем в директорию для входных данных картинку cat.jpg и выполняем запрос к сервису:
wget 127.0.0.1/process/cat.jpgВ ответ получаем идентификатор задания. Копируем идентификатор и выполняем второй запрос к сервису:
wget 127.0.0.1/result/[идентификатор]В ответ получаем строку JSON с весовыми коэффициентами принадлежности картинки категориям IMAGENET.
Теперь осталось сконфигурировать автоматический запуск компонентов нашего сервера.
Автозапуск
Настройка supervisor — возможно, самая сложная часть этого пути. Хороший обучающий материал по настройке supervisor тут.
Прежде всего нужно понять, что supervisor запускает каждый процесс в собственном окружении. В большинстве случаев сложных вычислений программа, их реализующая, зависит от ряда настроек, например путей. Эти настройки обычно хранятся в файле /home/usersname/.bashrc
Например, библиотека нейросетевых вычислений caffe и питоновские модули к ней потребовали дописать в этот файл следующие строки:
export PATH=/usr/local/cuda-7.5/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-7.5/lib64:$LD_LIBRARY_PATH
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH
LD_LIBRARY_PATH=/home/username/caffe/build/lib:$LD_LIBRARY_PATH
export PYTHONPATH="${PYTHONPATH}:/home/username/caffe/python"Скопируйте эти строки в буфер обмена!
В директории /usr/local/bin создайте файл deep_worker.sh
#!/bin/bash
cd /home/username/caffe/python
export PATH=/usr/local/cuda-7.5/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-7.5/lib64:$LD_LIBRARY_PATH
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH
LD_LIBRARY_PATH=/home/username/caffe/build/lib:$LD_LIBRARY_PATH
export PYTHONPATH="${PYTHONPATH}:/home/username/caffe/python"
rq workerНу вы поняли — в первой строчке мы переходим в рабочую директорию, затем вставляем переменные окружения, скопированные из .bashrc, затем запускаем процесс.
В директории /usr/local/bin создайте файл deep_flask.sh
#!/bin/bash
cd /home/username/caffe/python
export PATH=/usr/local/cuda-7.5/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-7.5/lib64:$LD_LIBRARY_PATH
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH
LD_LIBRARY_PATH=/home/username/caffe/build/lib:$LD_LIBRARY_PATH
export PYTHONPATH="${PYTHONPATH}:/home/username/caffe/python"
python deep_service.pyОпять — в первой строчке мы переходим в рабочую директорию, затем вставляем переменные окружения, скопированные из .bashrc, затем запускаем наш Flask-сервер.
Немного системного администрирования:
sudo chmod +x /usr/local/bin/deep_flask.sh
sudo chmod +x /usr/local/bin/deep_worker.sh
mkdir /var/log/deepserviceВ директории /etc/supervisor/conf.d создайте файл deepservice.conf:
[program:redis]
command=/usr/local/bin/redis-server
autostart=true
autorestart=true
stderr_logfile=/var/log/deepservice/redis.err.log
stdout_logfile=/var/log/deepservice/redis.out.log
[program:worker1]
command=/usr/local/bin/deep_worker.sh
autostart=true
autorestart=true
stderr_logfile=/var/log/deepservice/worker1.err.log
stdout_logfile=/var/log/deepservice/worker1.out.log
user=username
directory=/home/username/caffe/python
[program:flask]
command=/usr/local/bin/deep_flask.sh
autostart=true
autorestart=true
stderr_logfile=/var/log/deepservice/flask.err.log
stdout_logfile=/var/log/deepservice/flask.out.log
user=username
directory=/home/username/caffe/pythonНаконец, запустим всю эту конструкцию:
sudo supervisorctl reread
sudo supervisorctl updateВсё!
Комментарии (17)

sergeypid
05.08.2016 06:10+1Celery больше функций, но она сложнее. Rq позволяет с минимальными затратами времени реализовать рабочее решение, Здесь очень хорошо описаны Про и Контра celery vs. rq, перевожу кратко:
- Документация RQ полная и простая. Документация Celery сложнее для восприятия, хотя тоже подробная.
- Средства мониторинга Celery и RQ легко устанавливаются и оба хороши.
- Поддержка брокеров очередей: у RQ только Redis, Celery выигрывает (Redis, RabbitMQ). Redis, а значит RQ не гарантирует доставку 100% сообщений.
- Приоритетные очереди. Подходы разные, но оба работают.
- Операционные системы. RQ только unix-подобные (fork), Celery побеждает.
- Языки программирования. RQ только Python, Celery позволяет слать сообщения из одного языка другому (сорри).
- API. Celery гибче, RQ проще.
- Celery поддерживает подзадания, RQ — неизвестно (мне тоже неизвестно).
- Сообщество. Celery активнее, но оба проекта вполне активны.
У всех нас ограничено место в голове, поэтому если организация асинхронных очередей заданий для вас не основная работа, то RQ позволяет легко и просто построить качественное решение, за которое не будет стыдно. Celery конечно круче.
Toshiro
05.08.2016 09:49-4Статья любопытная, не знал про RQ. За статью — 5!) Но надо было остановиться после краткого сравнения.
Вот не надо опять про какие то там мистические ограничения в голове и особенно про «у всех нас».
Ограничения в голове только у всех вас, а за всех нас говорить нехорошо. Была бы карма, влепил бы комменту минус((

kolyaflash
05.08.2016 10:01-3> sudo pip install flask
Дальше не читал.

zoonim116
05.08.2016 12:39+1Для большей гибкости деплоя проекта, лучше изпользовать virtual env, а не ставить пакеты глобально.

yamatoko
05.08.2016 13:05вы бы написали, что он вообще делает? то есть, как он именно классифицирует картинки.

Realmixer
05.08.2016 22:23+1При чём здесь классификация картинок? Это отдельная тема. Дядя же ясно написал:
Естественно, его применение не ограничивается этими вашими нейронными сетями.
Смысл статьи в построении системы выполнения сравнительно длительных заданий. Вместо классификации картинок сервис может их ресайзить, например.

yamatoko
06.08.2016 09:45а при том, что «вам нужно сделать веб-сервис классификации картинок на базе обученной нейронной сети „

r66qq3Ek
05.08.2016 22:23Это тянет на enterprise или все такие вариант прототипирования?
Формально такой функционал можно стандартными http.server и threading уложить строк в 30.
sergeypid
08.08.2016 15:02Enterprise конечно звучит гордо применительно к open-source но это конечно более устойчивое решение чем http.server и threading.
Пространство HTTPD полностью отделено от потоков «тяжелых» задач, есть средства контроля приоритета и мониторинга для админов.
AndersonDunai
А каково оно в сравнении, скажем, с Celery?