DIY-Webservice mit asynchronen Warteschlangen und paralleler Ausführung

  • Tutorial

rqJeder muss seine Arbeit effizient und pünktlich erledigen. Angenommen, Sie müssen mithilfe der caffe- Bibliothek einen webbasierten Bildklassifizierungsdienst auf der Grundlage eines trainierten neuronalen Netzwerks erstellen . Heutzutage bedeutet Qualität asynchrone, nicht blockierende Aufrufe, die Möglichkeit der parallelen Ausführung mehrerer Tasks mit freien Prozessorkernen, die Überwachung von Jobwarteschlangen ... Mit der RQ- Bibliothek können Sie all dies in kurzer Zeit implementieren, ohne jede Menge Dokumentation zu studieren.


Wir werden einen Webservice auf einem Server erstellen, der sich auf leicht ausgelastete Projekte und relativ lange Aufgaben konzentriert. Natürlich ist seine Verwendung nicht auf diese neuronalen Netze beschränkt.




Erklärung des Problems


Die Eingabe ist eine Datei (z. B. ein JPEG-Bild). Der Einfachheit halber glauben wir, dass es bereits in einem dedizierten Verzeichnis abgelegt wurde. Die Ausgabe ist eine Zeichenfolge im JSON-Format. Aus Gründen der Solidität werden Standard-HTTP-Ergebniscodes verwendet.


Der Webdienst implementiert zwei HTTP-Aufrufe (nennen wir diese API):


  • / process / [Dateiname] - Verarbeitet die Datei (lädt die Eingabedatei im ausgewählten Verzeichnis vor, gibt die Job-ID zurück)
  • / result / [Task-ID] - Ermittelt das Ergebnis (wenn das Ergebnis nicht bereit ist, gibt es den Code 202 "Nicht bereit" zurück, wenn das Ergebnis bereit ist - gibt json zurück, wenn die Task-ID nicht vorhanden ist, gibt es den Code 404 "Nicht gefunden" zurück)

Installieren Sie Komponenten in Ubuntu


Wir werden Flask als HTTP-Server verwenden . Installation:


Wenn pip nicht installiert ist:


sudo apt-get install python-pip
sudo apt-get install --upgrade pip

Installieren von Flask:


pip install flask

Jetzt müssen Sie Redis - Data Warehouse und Message Broker installieren :


wget http://download.redis.io/redis-stable.tar.gz
tar xvzf redis-stable.tar.gz
cd redis-stable
make
sudo make install

Installieren Sie die RQ- Bibliothek (Redis Queue):


pip install rq

Um alle Komponenten automatisch zu starten und zu konfigurieren, verwenden wir Supervisor :


sudo apt-get install supervisor

Wir schreiben unseren Service


In Flask ist es einfach. Erstellen Sie eine deep_service.py- Datei :


#Путь к директории, выделенной под хранение входных файлов
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/')
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/')
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')

Manueller Start - überprüfen Sie, wie es funktioniert


An dieser Stelle können Sie überprüfen, ob unser Webservice funktioniert. Starten Sie Redis:


redis-server

Wir starten einen Workflow (Sie können mehrere davon ausführen, z. B. nach Anzahl der Prozessorkerne oder nach Vorhandensein mehrerer Grafikkarten, wenn diese für die Datenverarbeitung benötigt werden). Es ist besser, den Prozess von dem Verzeichnis aus zu starten, in dem die Rechenfunktionen gestartet werden. In unserem Fall befindet sich hier classif.py :


rq worker

Starten Sie den http-Server:


python deep_service.py

Wir schreiben das Bild cat.jpg in das Verzeichnis für die Eingabedaten und führen die Serviceanforderung aus:


wget 127.0.0.1/process/cat.jpg

Als Antwort erhalten wir die Job-ID. Kopieren Sie die Kennung und führen Sie die zweite Anforderung an den Service aus:


wget 127.0.0.1/result/[идентификатор]

Als Antwort erhalten wir eine JSON-Zeichenfolge mit Gewichten des Bildes, das zu IMAGENET-Kategorien gehört.
Jetzt muss noch der automatische Start unserer Serverkomponenten konfiguriert werden.


Autostart


Die Einrichtung eines Supervisors ist wahrscheinlich der schwierigste Teil dieser Reise. Gutes Tutorial zum Einrichten des Supervisors hier .


Zunächst müssen Sie verstehen, dass der Supervisor jeden Prozess in seiner eigenen Umgebung ausführt. In den meisten Fällen komplexer Berechnungen hängt das Programm, das sie implementiert, von einer Reihe von Einstellungen ab, z. B. von Pfaden. Diese Einstellungen werden normalerweise in /home/usersname/.bashrc gespeichert


Beispielsweise mussten für die caffe-Bibliothek für neuronales Netzwerk-Computing und die Python-Module dazu die folgenden Zeilen zu dieser Datei hinzugefügt werden:


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"

Kopieren Sie diese Zeilen in die Zwischenablage!


Erstellen Sie im Verzeichnis / usr / local / bin die Datei 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

Nun, verstehen Sie - in der ersten Zeile gehen wir in das Arbeitsverzeichnis, fügen dann die Umgebungsvariablen ein, die aus .bashrc kopiert wurden, und starten dann den Prozess.


Erstellen Sie im Verzeichnis / usr / local / bin die Datei 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

Nochmals - in der ersten Zeile wechseln wir in das Arbeitsverzeichnis, fügen die Umgebungsvariablen ein, die aus .bashrc kopiert wurden, und starten dann unseren Flask-Server.


Ein bisschen Systemadministration:


sudo chmod +x /usr/local/bin/deep_flask.sh
sudo chmod +x /usr/local/bin/deep_worker.sh
mkdir /var/log/deepservice

Erstellen Sie im Verzeichnis /etc/supervisor/conf.d die Datei 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

Führen Sie zum Schluss das gesamte Konstrukt aus:


sudo supervisorctl reread
sudo supervisorctl update

Das war's


Jetzt auch beliebt: