Einführung in eine typische Konfiguration der Inferenz-Web-API für maschinelles Lernen. Ich denke, dass der Inhalt gelesen werden kann, ohne unbedingt Kenntnisse über das WEB oder maschinelles Lernen zu haben. (Ohne Implementierungsbeispiele) Die einzuführende Komposition basiert auf der Erfahrung mit der Erstellung von Inferenz-Web-APIs für einige Modelle des maschinellen Lernens in Unternehmen. Da es jedoch meine persönliche Meinung ist, lassen Sie es mich in den Kommentaren wissen, wenn es etwas Besseres gibt Ich bin glücklich. Im Implementierungsbeispiel verwendet das Webframework die Fast-API unter dem Gesichtspunkt der einfachen Handhabung der asynchronen Verarbeitung und der Einfachheit der Implementierung.
In diesem Artikel werde ich zwei Muster vorstellen.
Hinweis) Zunächst werde ich die gemeinsamen Teile erläutern. Kenntnisse über maschinelles Lernen sind grundsätzlich nur für die gemeinsamen Teile erforderlich. Wenn Sie mit maschinellem Lernen oder dem Web nicht vertraut sind, können Sie die Rollen zwischen dem gemeinsamen Teil und dem später beschriebenen Teil aufteilen, damit Sie ihn fließen lassen können.
Wenn das trainierte Modell abgeleitet werden soll, erstellen Sie im Allgemeinen die folgende Inferenz-API für maschinelles Lernmodell. Selbst wenn Sie nur auf einem lokalen PC oder Jupyter Notebook entwickeln, werden Sie wahrscheinlich eine solche API (Pipeline) erstellen.
Ich werde die Details weglassen, aber zur Vereinfachung der Lastverteilung und des Modellmanagements denke ich, dass Sie nur die API ausschneiden können, die das maschinelle Lernmodell für den Server in der Cloud verwendet (Referenz: [GCP AI Platform Prediction](https: /) /cloud.google.com/ai-platform/prediction/docs)). Bei einem schweren Modell, bei dem Leistungsprobleme auftreten, wenn die GPU nicht nur zum Laden, sondern auch zum Ableiten verwendet wird, ist es nicht möglich, sie mit einem Server für gängige WEB-Anwendungen zu verarbeiten. Daher halte ich es für flexibler, sie isolieren zu können. Ich denke auch, dass dieselbe Konfiguration verwendet wird, wenn ein externer Dienst verwendet wird, der ein geschultes Modell verwendet.
Ich denke, dass es mit zunehmender Datenmenge erforderlich sein wird, Maßnahmen wie das Ersetzen der Vorverarbeitung durch eine umfangreiche Datenverarbeitungs-Engine wie Google Cloud Dataflow zu ergreifen.
Beim Erstellen einer Web-API basierend auf der Inferenz-API, die auf einem lokalen PC oder Jupyter Notebook wie oben beschrieben entwickelt wurde, können hauptsächlich zwei Arten von Mustern berücksichtigt werden. Diese behandeln Eingabe- und Ausgabedaten unterschiedlich.
--1.1. Online-Vorhersage (auch als HTTP-Vorhersage bezeichnet) --1.2 Chargenvorhersage
(Der in der AI-Plattform von GCP verwendete Name wird verwendet. Referenz: [Online-Vorhersage vs. Batch-Vorhersage](https://cloud.google.com/ml-engine/docs/tensorflow/online-vs-batch- Vorhersage? hl = ja))
Wenn eine http-Anforderung eintrifft, wird die ML-Funktion ausgeführt und die Ausgabe wird sofort von der http-Antwort zurückgegeben. Dies ist eine einfache Konfiguration. Laden Sie das Gewicht nur einmal, wenn der Server gestartet wird. Beim Laden von Gewichten ist es einfacher, das Modell zu ändern, wenn Sie die Gewichte aus dem Cloud-Speicher (Google Storage usw.) beziehen.
Wenn die Antwort nicht sofort zurückgegeben werden kann oder nicht zurückgegeben werden muss, wird das Inferenzergebnis der ML-API in einem Speicher gespeichert, ohne direkt zu antworten, wie unten gezeigt. Der Prozess kann wie unten gezeigt in drei Stufen unterteilt werden. (Es ist gut, wenn 2 und 3 getrennt sind. Die Upload-API kann in die ML-API integriert werden.)
Jede API kann lose gekoppelt werden. Daher ist die Implementierung der Upload-API und der Download-API sehr flexibel. Es gibt verschiedene Möglichkeiten, es wie folgt zu verwenden.
Außerdem ist die Implementierung der Upload- und Download-APIs in anderen Sprachen als Python in Ordnung, und die APIs können sich auf verschiedenen Servern befinden, solange sie in denselben Speicher lesen und schreiben können. Sie können direkt vom Front-End aus in den Speicher lesen und schreiben, ohne die API zu durchlaufen. Insbesondere wenn es sich bei der Eingabe / Ausgabe um ein Bild handelt, ist es einfacher, den Cloud-Speicher direkt zu verwalten.
――Es ist schwierig zu verwenden, da es komplizierter ist als die Online-Vorhersage.
Lassen Sie uns die Online-Vorhersage- und Batch-Vorhersage-APIs mit der Fast-API implementieren. Wenn Sie sich das folgende Beispiel ansehen, werden Sie der Meinung sein, dass die Hürde, eine Inferenz-Pipeline zu einer Web-API zu machen, recht gering ist, wenn Sie die Inferenz-Pipeline lokal ordnungsgemäß funktionieren.
Dieser Artikel behandelt Folgendes nicht:
Pythons Web-Framework, ein Mikroframework wie Flask. Zu seinen Stärken zählen hohe Leistung, einfache Schreibweise, ein Design mit starkem Fokus auf Produktionsabläufe und moderne Funktionen. Insbesondere die asynchrone Verarbeitung ist einfach zu handhaben.
Das Folgende basiert auf den Grundkenntnissen von Fast API. Wenn Sie die Details wissen möchten, lesen Sie bitte die folgenden Informationen.
Um vielseitig zu sein, definieren wir ein sehr grobes Modell. Es hat nichts zu bedeuten, ist aber einfach, daher nenne ich es eine Aufgabe der Emotionsanalyse für die Verarbeitung natürlicher Sprache.
Die erforderlichen Funktionen sind wie folgt. Wenn jedoch nur das Modell auf einen anderen Server ausgeschnitten ist, müssen Last und Modell nicht beibehalten werden.
Dieses Mal werden wir ein Modell verwenden, das zufällige Emotionen mit Vorhersage zurückgibt. Ich möchte die Verarbeitungszeit realisieren, also friere ich sie beim Laden für 20 Sekunden und bei der Vorhersage für 10 Sekunden ein.
ml.py
from random import choice
from time import sleep
class MockMLAPI:
def __init__(self):
# model instanse
self.model = None
def load(self, filepath=''):
"""
when server is activated, load weight or use joblib or pickle for performance improvement.
then, assign pretrained model instance to self.model.
"""
sleep(20)
pass
def predict(self, x):
"""implement followings
- Load data
- Preprocess
- Prediction using self.model
- Post-process
"""
sleep(10)
preds = [choice(['happy', 'sad', 'angry']) for i in range(len(x))]
out = [{'text': t.text, 'sentiment': s} for t, s in zip(x, preds)]
return out
Definiert das Format der Anforderungsdaten. Versuchen wir, mehrere Eingaben zu unterstützen, wie unten gezeigt.
{
"data": [
{"text": "hogehoge"},
{"text": "fugafuga"}
]
}
Die Antwortdaten sollten in einem Format vorliegen, das das Inferenzergebnis zur Eingabe hinzufügt und zurückgibt.
{
"prediction": [
{"text": "hogehoge", "sentiment": "angry"},
{"text": "fugafuga", "sentiment": "sad"}
]
}
Definieren Sie das Schema wie folgt.
schemas.py
from pydantic import BaseModel
from typing import List
# request
class Text(BaseModel):
text: str
class Data(BaseModel):
data: List[Text]
# response
class Output(Text):
sentiment: str
class Pred(BaseModel):
prediction: List[Output]
Implementieren Sie eine Web-API für die Online-Vorhersage unter Verwendung der oben genannten allgemeinen Teile. Alles was Sie brauchen ist
--Laden Sie das trainierte Modell für maschinelles Lernen, wenn der Server gestartet wird
ist. Die minimale API wird durch Implementierung wie folgt vervollständigt.
main.py
from fastapi import FastAPI
from ml_api import schemas
from ml_api.ml import MockMLAPI
app = FastAPI()
ml = MockMLAPI()
ml.load() # load weight or model instanse using joblib or pickle
@app.post('/prediction/online', response_model=schemas.Pred)
async def online_prediction(data: schemas.Data):
preds = ml.predict(data.data)
return {"prediction": preds}
Überprüfen Sie den Betrieb lokal. Veröffentlichen Sie die Probeneingabe in CuRL. Anschließend können Sie bestätigen, dass die erwartete Ausgabe zurückgegeben wird. Da es 10 Sekunden gedauert hat, bis die Antwort zurückgegeben wurde, können Sie sehen, dass fast nur die vorhergesagte Verarbeitungszeit benötigt wurde.
$ curl -X POST "http://localhost:8000/prediction/online" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"data\":[{\"text\":\"hogehoge\"},{\"text\":\"fugafuga\"}]}" -w "\nelapsed time: %{time_starttransfer} s\n"
{"prediction":[{"text":"hogehoge","sentiment":"angry"},{"text":"fugafuga","sentiment":"happy"}]}
elapsed time: 10.012029 s
Implementieren Sie eine Web-API für die Stapelvorhersage unter Verwendung der oben genannten allgemeinen Teile.
Input/Output Normalerweise sollten Sie die Daten im Cloud-Speicher oder in der Datenbank speichern. Der Einfachheit halber werden wir in diesem Artikel die Daten im CSV-Format im lokalen Speicher speichern. Definieren Sie zunächst eine Funktion zum Lesen und Schreiben. Beim Speichern der Eingabedaten wird ein Dateiname mit einer zufälligen Zeichenfolge erstellt, und eine Reihe von Stapelvorhersagen wird durchgeführt, indem die zufällige Zeichenfolge gegen eine API ausgetauscht wird. Die Implementierung mag lang erscheinen, aber in Wirklichkeit gibt es nur drei Dinge zu tun:
io.py
import os
import csv
from random import choice
import string
from typing import List
from ml_api import schemas
storage = os.path.join(os.path.dirname(__file__), 'local_storage')
def save_csv(data, filepath: str, fieldnames=None):
with open(filepath, 'w') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for f in data:
writer.writerow(f)
def load_csv(filepath: str):
with open(filepath, 'r') as f:
reader = csv.DictReader(f)
out = list(reader)
return out
def save_inputs(data: schemas.Data, length=8):
letters = string.ascii_lowercase
filename = ''.join(choice(letters) for i in range(length)) + '.csv'
filepath = os.path.join(storage, 'inputs', filename)
save_csv(data=data.dict()['data'], filepath=filepath, fieldnames=['text'])
return filename
def load_inputs(filename: str):
filepath = os.path.join(storage, 'inputs', filename)
texts = load_csv(filepath=filepath)
texts = [schemas.Text(**f) for f in texts]
return texts
def save_outputs(preds: List[str], filename):
filepath = os.path.join(storage, 'outputs', filename)
save_csv(data=preds, filepath=filepath, fieldnames=['text', 'sentiment'])
return filename
def load_outputs(filename: str):
filepath = os.path.join(storage, 'outputs', filename)
return load_csv(filepath=filepath)
def check_outputs(filename: str):
filepath = os.path.join(storage, 'outputs', filename)
return os.path.exists(filepath)
web API Erstellen Sie drei APIs: Upload, Inferenz und Download. Beachten Sie, dass die Stapelinferenz keine sofortige Antwort zurückgibt. Laden Sie das Modell daher jedes Mal, wenn die API aufgerufen wird.
Hier wird BackgourndTasks von FastAPI verwendet, um Modellinferenzen asynchron zu verarbeiten. Inferenz kann im Hintergrund verarbeitet werden und eine Antwort kann zuerst zurückgegeben werden, ohne auf das Ende zu warten.
main.py
from fastapi import FastAPI
from fastapi import BackgroundTasks
from fastapi import HTTPException
from ml_api import schemas, io
from ml_api.ml import MockBatchMLAPI
app = FastAPI()
@app.post('/upload')
async def upload(data: schemas.Data):
filename = io.save_inputs(data)
return {"filename": filename}
def batch_predict(filename: str):
"""batch predict method for background process"""
ml = MockMLAPI()
ml.load()
data = io.load_inputs(filename)
pred = ml.predict(data)
io.save_outputs(pred, filename)
print('finished prediction')
@app.get('/prediction/batch')
async def batch_prediction(filename: str, background_tasks: BackgroundTasks):
if io.check_outputs(filename):
raise HTTPException(status_code=404, detail="the result of prediction already exists")
background_tasks.add_task(ml.batch_predict, filename)
return {}
@app.get('/download', response_model=schemas.Pred)
async def download(filename: str):
if not io.check_outputs(filename):
raise HTTPException(status_code=404, detail="the result of prediction does not exist")
preds = io.load_outputs(filename)
return {"prediction": preds}
Überprüfen Sie den Vorgang auf die gleiche Weise wie bei der Online-Vorhersage. Veröffentlichen Sie die Probeneingabe in CuRL. Anschließend können Sie bestätigen, dass die erwartete Ausgabe zurückgegeben wird. Es wartet außerdem 30 Sekunden, bevor die Download-API aufgerufen wird. Sie können jedoch sehen, dass jede Antwort sehr schnell zurückgegeben wird.
$ curl -X POST "http://localhost:8000/upload" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"data\":[{\"text\":\"hogehoge\"},{\"text\":\"fugafuga\"}]}" -w "\nelapsed time: %{time_starttransfer} s\n"
{"filename":"fdlelteb.csv"}
elapsed time: 0.010242 s
$ curl -X GET "http://localhost:8000/prediction/batch?filename=fdlelteb.csv" -w "\nelapsed time: %{time_starttransfer} s\n"
{}
elapsed time: 0.007223 s
$ curl -X GET "http://localhost:8000/download?filename=fdlelteb.csv" -w "\nelapsed time: %{time_starttransfer} s\n" [12:58:27]
{"prediction":[{"text":"hogehoge","sentiment":"happy"},{"text":"fugafuga","sentiment":"sad"}]}
elapsed time: 0.008825 s
Wir haben zwei typische Konfigurationen von Inferenz-Web-APIs für maschinelles Lernen eingeführt: Online-Vorhersage und Batch-Vorhersage. Es erfordert eine kleine Änderung der allgemeinen Web-API-Konfiguration, aber ich habe auch ein Implementierungsbeispiel vorgestellt, das einfach mit der Fast-API erstellt wird. Es wäre großartig, wenn Sie das Gefühl hätten, dass die Hürde, eine Web-API daraus zu machen, gering ist, wenn die Inferenz-Pipeline lokal ordnungsgemäß funktionalisiert ist. Die Aufregung des maschinellen Lernens ist endlos, aber ich habe das Gefühl, dass es immer noch wenig Informationen wie die Konfiguration der Web-API gibt ~~ (Es scheint ziemlich wahrscheinlich. Ich habe eine Sammlung von Links hinzugefügt). Ich denke, die in diesem Artikel vorgestellte Konfiguration ist auch grob. Ich würde mich freuen, wenn Sie Verbesserungen kommentieren könnten!
Dies ist ein Link, der in diesem Artikel nicht behandelt werden konnte.