[PYTHON] So erstellen Sie mit AWS Lambda eine serverlose API für maschinelles Lernen

Dieser Artikel ist der 14. Tagesartikel des Python-Adventskalenders 2016.

Überblick

NewsDigest klassifiziert die Kategorien von Nachrichtenartikeln, die von Algorithmen für maschinelles Lernen geliefert werden sollen. Insbesondere werden täglich etwa 1000 Artikel in 10 Kategorien wie "Unterhaltung", "Politik" und "Sport" eingeteilt.

NewsDigest bietet eine ** Allzweck-API ** für die interne Klassifizierung, anstatt eine solche Kategorieklassifizierung eng mit Servermodulen zu verknüpfen.

Um diese universelle API zu realisieren, haben wir eine API für maschinelles Lernen ohne Server (AWS Lambda) in Betracht gezogen, um sie skalierbarer zu machen. Daher handelt es sich um eine Einführung oder ein Lernprogramm zum Erstellen einer API ohne Server.

Die API, die tatsächlich funktioniert, ist https://3lxb3g0cx5.execute-api.us-east-1.amazonaws.com/prod/classify Das Repository lautet https://github.com/yamitzky/serverless-machine-learning.

Annahme

Die diesmal zu implementierende API wird basierend auf den folgenden Annahmen erstellt.

** Ich werde die Erklärung über maschinelles Lernen, die Methode der morphologischen Analyse, die Verwendung von Scikit-Lernen usw. weglassen. **

In diesem Tutorial werden Sie mit den folgenden Schritten fortfahren

1. Mindestimplementierung für die Klassifizierung durch maschinelles Lernen

Lassen Sie uns zunächst eine Mindestimplementierung erstellen, ohne über die API-Konvertierung nachzudenken. Als Voraussetzung werde ich den folgenden Korpus vorbereiten (ich habe einen Korpus aus Reuters-Korpus erstellt und generiert).

Kategorie\t Morphologisch analysierte Sätze
money-fx\tu.k. money market given 120 mln stg late help london, march 17 - the bank of england said it provided the money market with late assistance of around 120 mln stg. this brings the bank's total help today to some 136 mln stg and compares with its forecast of a 400 mln stg shortage in the system.
grain\tu.s. export inspections, in thous bushels soybeans 20,349 wheat 14,070 corn 21,989 blah blah blah. 
earn\tsanford corp <sanf> 1st qtr feb 28 net bellwood, ill., march 23 - shr 28 cts vs 13 cts net 1,898,000 vs 892,000 sales 16.8 mln vs 15.3 mln
...

Wie sieht die minimale Implementierung der Kategorisierung durch Naive Bayes aus?

from gensim.corpora.dictionary import Dictionary
from gensim.matutils import corpus2csc
from sklearn.naive_bayes import MultinomialNB


def load_corpus(path):
    """Korpus aus Datei holen"""
    categories = []
    docs = []
    with open(path) as f:
        for line in f:
            category, line = line.split('\t')
            doc = line.strip().split(' ')
            categories.append(category)
            docs.append(doc)
    return categories, docs


def train_model(documents, categories):
    """Lerne das Modell"""
    dictionary = Dictionary(documents)
    X = corpus2csc([dictionary.doc2bow(doc) for doc in documents]).T
    return MultinomialNB().fit(X, categories), dictionary


def predict(classifier, dictionary, document):
    """Schätzen Sie unbekannte Satzkategorien aus dem trainierten Modell"""
    X = corpus2csc([dictionary.doc2bow(document)], num_terms=len(dictionary)).T
    return classifier.predict(X)[0]


#Lerne das Modell
categories, documents = load_corpus('corpus.txt')
classifier, dictionary = train_model(documents, categories)

#Kategorisieren Sie mit dem trainierten Modell
predict_sentence = 'a dollar of 115 yen or more at the market price of the trump market 4% growth after the latter half of next year'.split()  # NOQA
predict(classifier, dictionary, predict_sentence)  # money-fx

Diese Mindestimplementierung

In dieser Hinsicht hat es die Mindestfunktionen des überwachten Lernens. Lassen Sie uns dies in eine API verwandeln.

2. Implementieren Sie eine einfache API mit der Flasche

Bevor wir es serverlos machen, machen wir einfach eine Kategorisierung in eine API mithilfe von Flasche, einem einfachen Webframework.

from bottle import route, run, request

def load_corpus(path):
    """Korpus aus Datei holen"""
def train_model(documents, categories):
    """API zum Lernen"""
def predict(classifier, dictionary, document):
    """Klassifizierungs-API"""

@route('/classify')
def classify():
    categories, documents = load_corpus('corpus.txt')
    classifier, dictionary = train_model(documents, categories)
    sentence = request.params.sentence.split()
    return predict(classifier, dictionary, sentence)

run(host='localhost', port=8080)

Wenn Sie in diesem Status den Befehl curl drücken, wird das Ergebnis der API zurückgegeben.

curl "http://localhost:8080/classify?sentence=a%20dollar%20of%20115%20yen%20or%20more%20at%20the%20market%20price%20of%20the%20trump%20market%204%%20growth%20after%20the%20latter%20half%20of%20next%20year"
# money-fx

Aber natürlich ** gibt es ein großes Problem mit dieser Implementierung **. Es ist langsam, weil es gleichzeitig lernt und klassifiziert, wenn Sie den Klassifizierungsendpunkt (/ classify) erreichen.

Im Allgemeinen nimmt das Lernen beim maschinellen Lernen Zeit in Anspruch und die Klassifizierung ist in kurzer Zeit abgeschlossen. Schneiden wir also den Trainingsendpunkt aus und machen das trainierte Modell dauerhaft.

3. Erstellen Sie einen Lernendpunkt und behalten Sie das Modell bei

Dieses Mal habe ich zwei APIs vorbereitet, / train und / classify. Ich habe versucht, die Modellpersistenz mit joblib zu speichern, wie in scikit learn 3.4. Modellpersistenz beschrieben. Der Trick besteht darin, die Joblib zu verwenden. Wenn Sie die Joblib zum Komprimieren des Modells verwenden, passen etwa 200 MB in 2 MB (da die Dateigröße bei der Konvertierung in Lambda eine Einschränkung darstellt).

from sklearn.externals import joblib
import os.path

from bottle import route, run, request

def load_corpus(path):
    """Korpus aus Datei holen"""
def train_model(documents, categories):
    """API zum Lernen"""
def predict(classifier, dictionary, document):
    """Klassifizierungs-API"""

@route('/train')
def train():
    categories, documents = load_corpus('corpus.txt')
    classifier, dictionary = train_model(documents, categories)
    joblib.dump((classifier, dictionary), 'model.pkl', compress=9)
    return "trained"

@route('/classify')
def classify():
    if os.path.exists('model.pkl'):
        classifier, dictionary = joblib.load('model.pkl')
        sentence = request.params.sentence.split()
        return predict(classifier, dictionary, sentence)
    else:
        #Ohne die Datei wird sie nicht gelernt
        return "model not trained. call `/train` endpoint"

run(host='localhost', port=8080)

Wenn mit dieser API ein Modell trainiert wird, bleibt das trainierte Modell als "model.pkl" erhalten. In der ersten Phase wird das Modell nicht trainiert, daher wird "Modell nicht trainiert" angezeigt.

curl "http://localhost:8080/?sentence=a%20dollar%20of%20115%20yen%20or%20more%20at%20the%20market%20price%20of%20the%20trump%20market%204%%20growth%20after%20the%20latter%20half%20of%20next%20year"
# model not trained

Wenn Sie erneut lernen und klassifizieren, können Sie sehen, dass die API normal klassifiziert.

curl http://localhost:8080/train
# trained
curl "http://localhost:8080/classify?sentence=a%20dollar%20of%20115%20yen%20or%20more%20at%20the%20market%20price%20of%20the%20trump%20market%204%%20growth%20after%20the%20latter%20half%20of%20next%20year"
# money-fx

4. Machen Sie es serverlos

Hier ist das Hauptproblem. Wir werden die mit der Flasche erstellte API für AWS Lambda bereitstellen.

Um die API für maschinelles Lernen serverlos zu machen, werden die Lernphase und die Klassifizierungsphase wie folgt definiert.

4-1. Lernphase: Erstellen Sie ein Modell mit Docker

Es ist ein bisschen anstößig, aber bereiten Sie das folgende Dockerfile vor.

#Einfach zu bauen maschinelles Lernen, Anakonda(miniconda)Als Basisbild
FROM continuumio/miniconda

RUN mkdir -p /usr/src/app

WORKDIR /usr/src/app

#Datensatz herunterladen
COPY download_corpus.sh /usr/src/app/
RUN sh download_corpus.sh

#Installation von Bibliotheken für maschinelles Lernen
COPY conda-requirements.txt /usr/src/app/

RUN conda create -y -n deploy --file conda-requirements.txt
#Verwandte Bibliotheken sind/opt/conda/envs/deploy/lib/python2.7/site-Zu Paketen ausgeatmet

COPY . /usr/src/app/

#Lerne und spucke das Modell aus
RUN python gen_corpus.py \
      && /bin/bash -c "source activate deploy && python train.py"

#Bereiten Sie die Ergebnisse für die Bereitstellung vor
#Packcode, trainiertes Modell, also für die Ausführung benötigte Datei usw.
RUN mkdir -p build/lib \
      && cp main.py model.pkl build/ \
      && cp -r /opt/conda/envs/deploy/lib/python2.7/site-packages/* build/ \
      && cp /opt/conda/envs/deploy/lib/libopenblas* /opt/conda/envs/deploy/lib/libgfortran* build/lib/

Das Erstellen dieser Docker-Datei führt zu einem Docker-Image mit Code, einem trainierten Modell und den zum Ausführen erforderlichen Dateien. Mit anderen Worten: "Ich habe das Modell gebaut."

Führen Sie einen Befehl aus, der dem folgenden ähnelt, um das Artefakt aus dem Docker-Image zu extrahieren und ein Artefakt zum Hochladen auf Lambda zu erstellen:

docker build -t serverless-ml .
#Abrufen von Informationen aus einem Docker-Image
id=$(docker create serverless-ml)
docker cp $id:/usr/src/app/build ./build
docker rm -v $id
#Größenreduzierung rm bauen/**/*.pyc
rm -rf build/**/test
rm -rf build/**/tests
#Artefakte mit Reißverschluss
cd build/ && zip -q -r -9 ../build.zip ./

Sie haben jetzt eine Zip-Datei mit Code und Modellen.

4-2. Bereitstellen von Lambda

Dies ist eine Verwendung von AWS Lambda, daher werde ich sie weglassen.

[Schritt 2.3: Erstellen Sie eine Lambda-Funktion und testen Sie sie manuell](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-s3-example-upload-deployment-pkg.html# Walkthrough-S3-Events-Adminuser-Create-Test-Funktion-Upload-Zip-Test-Upload) kann hilfreich sein.

4-3. Erstellen Sie eine Klassifizierungs-API

Verwenden Sie Amazon API Gateway, um eine serverlose "API" zu erstellen.

Dies wird auch weggelassen, da hier das API-Gateway verwendet wird.

Erstellen einer API zum Anzeigen von Lambda-Funktionen kann hilfreich sein.

5. Abgeschlossen!

Als Arbeitsbeispiel habe ich die folgende API vorbereitet.

https://3lxb3g0cx5.execute-api.us-east-1.amazonaws.com/prod/classify

Lassen Sie uns die API tatsächlich mit Curl treffen.

curl -X POST https://3lxb3g0cx5.execute-api.us-east-1.amazonaws.com/prod/classify -H "Content-type: application/json" -d '{"sentence": "a dollar of 115 yen or more at the market price of the trump market 4% growth after the latter half of next year"}'

Sie können das Klassifizierungsergebnis "money-fx" sicher erhalten.

Kann ich die serverlose API für maschinelles Lernen verwenden?

Zusammenfassend ist es ** keine **.

Der Grund dafür ist, dass die API die Ergebnisse zu spät zurückgibt. Im vorherigen Beispiel dauert es ungefähr 5 Sekunden. Die API, die 5 Sekunden zurückgibt, ist, na ja, keine (bitteres Lächeln)

Der Grund für die langsame Reaktion liegt auf der Hand: Das Laden der auf der Festplatte gespeicherten pkl-Datei dauert lange. Wenn die Modelldatei sehr groß ist, kann daher gesagt werden, dass die serverlose API für maschinelles Lernen zu langsam ist, um zu reagieren **.

Im Gegenteil, wenn beispielsweise keine Modelldatei vorhanden ist, verwendet die API einfach "numpy", oder wenn die Modelldatei sehr leicht ist, kann sie meiner Meinung nach relativ verwendet werden.

Recommended Posts

So erstellen Sie mit AWS Lambda eine serverlose API für maschinelles Lernen
[AWS] API mit API Gateway + Lambda erstellen
So erstellen Sie schnell eine maschinelle Lernumgebung mit Jupyter Notebook mit UbuntuServer 16.04 LTS
So erstellen Sie schnell eine maschinelle Lernumgebung mit Jupyter Notebook mit UbuntuServer 16.04 LTS mit anaconda
[AWS SAM] Erstellen Sie eine API mit DynamoDB + Lambda + API Gateway
Verfahren zur Erstellung plattformübergreifender Apps mit kivy
So erstellen Sie eine Rest-API in Django
Schnelle Schritte zum Erstellen einer maschinellen Lernumgebung mit Jupyter Notebook unter macOS Sierra mit anaconda
So erstellen Sie ein Untermenü mit dem Plug-In [Blender]
Erstellen Sie in Docker eine Ebene für AWS Lambda Python
[Python] So erstellen Sie mit Matplotlib ein zweidimensionales Histogramm
Erstellen Sie mit Winsows 10 eine maschinelle Lernumgebung von Grund auf neu
So bereiten Sie die Umgebung mit Courseras fortgeschrittenem Kurs für maschinelles Lernen auf Google Colab vor
Erstellen Sie eine App für maschinelles Lernen mit ABEJA Platform + LINE Bot
So erstellen Sie mit snappyHexMesh ein Flussnetz um einen Zylinder
So erstellen Sie ein Conda-Paket
Wie erstelle ich eine Docker-Datei?
So erstellen Sie eine Konfigurationsdatei
Sammeln von Daten zum maschinellen Lernen
Ich habe ein Skript geschrieben, um mit AWS Lambda + Python 2.7 schnell eine Entwicklungsumgebung für Twitter Bot zu erstellen
Erstellen Sie mit der AWS-API einen Alias für Route53 zu CloudFront
[Python 3.8 ~] Wie man rekursive Funktionen mit Lambda-Ausdrücken intelligent definiert
So erstellen Sie eine Bezeichnung (Maske) für die Segmentierung mit labelme (semantische Segmentierungsmaske)
Regelmäßiges Serverless Scraping mit AWS Lambda + Scrapy Teil 1
Ich möchte einen maschinellen Lerndienst ohne Programmierung erstellen! Web-API
So schreiben Sie eine Dokumentzeichenfolge, um ein benanntes Tupeldokument mit Sphinx zu erstellen
So senden Sie eine Anfrage mit Python an die DMM (FANZA) -API
Versuchen Sie, einen Artikel von Qiita mit der REST-API [Umweltvorbereitung] zu erstellen.
So erstellen Sie einen Klon aus Github
Einführung in das maschinelle Lernen: Funktionsweise des Modells
scikit-learn Verwendung der Zusammenfassung (maschinelles Lernen)
So erstellen Sie einen Git-Klonordner
Eine Geschichte über maschinelles Lernen mit Kyasuket
Wie man Coursera / Maschinelles Lernen genießt (Woche 10)
So erstellen Sie ein Repository aus Medien
Stellen Sie mit AWS Lambda Python eine Verbindung zu s3 her
Erstellen Sie ein privates Repository mit AWS CodeArtifact
Ich habe versucht, schlechte Tweets regelmäßig mit der AWS Lambda + Twitter API zu löschen
[AWS] Erstellen Sie mit CodeStar eine Python Lambda-Umgebung und führen Sie Hello World aus
Erstellen wir eine Chat-Funktion mit Vue.js + AWS Lambda + Dynamo DB [AWS-Einstellungen]
Ich habe versucht, "Sakurai-san" LINE BOT mit API Gateway + Lambda zu erstellen
Ich möchte einen maschinellen Lerndienst ohne Programmierung erstellen! Textklassifizierung
Ich habe versucht, einen URL-Verkürzungsdienst mit AWS CDK serverlos zu machen
3. Verarbeitung natürlicher Sprache mit Python 1-2. So erstellen Sie einen Korpus: Aozora Bunko
Erstellen von CSV-Beispieldaten mit Hypothese
Lesen einer CSV-Datei mit Python 2/3
So senden Sie eine Nachricht mit Curl an LINE
So zeichnen Sie ein 2-Achsen-Diagramm mit Pyplot
Regelmäßiges Serverless Scraping mit AWS Lambda + Scrapy Teil 1.8
So erstellen Sie ein Funktionsobjekt aus einer Zeichenfolge
So entwickeln Sie eine Cart-App mit Django
So erstellen Sie eine JSON-Datei in Python
LINE BOT mit Python + AWS Lambda + API Gateway
Serverlose Anwendung mit AWS SAM! (APIGATEWAY + Lambda (Python))