Vorhersage für maschinelles Lernen in Python mit einer Flask-REST-API
Veröffentlicht: 2022-03-11In diesem Artikel geht es um die Verwendung von Python im Kontext eines Systems für maschinelles Lernen oder künstliche Intelligenz (KI) zum Erstellen von Echtzeitvorhersagen mit einer Flask-REST-API. Die hier vorgestellte Architektur kann als Weg vom Proof of Concept (PoC) zum Minimal Viable Product (MVP) für maschinelle Lernanwendungen angesehen werden.
Python ist nicht die erste Wahl, an die man denken kann, wenn man eine Echtzeitlösung entwirft. Da Tensorflow und Scikit-Learn jedoch einige der am häufigsten verwendeten Bibliotheken für maschinelles Lernen sind, die von Python unterstützt werden, wird es bequem in vielen Jupyter-Notebook-PoCs verwendet.
Was diese Lösung praktikabel macht, ist die Tatsache, dass das Training im Vergleich zur Vorhersage viel Zeit in Anspruch nimmt. Wenn Sie sich Training als den Prozess vorstellen, einen Film anzusehen und die Antworten auf Fragen dazu vorherzusagen, dann scheint es ziemlich effizient zu sein, den Film nicht nach jeder neuen Frage erneut ansehen zu müssen.
Das Training ist eine Art komprimierte Ansicht dieses „Films“, und die Vorhersage ist das Abrufen von Informationen aus der komprimierten Ansicht. Es sollte wirklich schnell gehen, egal ob der Film komplex oder lang war.
Lassen Sie uns das mit einem schnellen [Flask]-Beispiel in Python implementieren!
Generische Architektur für maschinelles Lernen
Beginnen wir mit der Skizzierung eines generischen Ablaufs einer Trainings- und Vorhersagearchitektur:
Zunächst wird eine Trainingspipeline erstellt, um anhand einer objektiven Funktion etwas über die vergangenen Daten zu lernen.
Dies sollte zwei Schlüsselelemente ausgeben:
- Feature-Engineering-Funktionen : Die zur Trainingszeit verwendeten Transformationen sollten zur Vorhersagezeit wiederverwendet werden.
- Modellparameter : Der schließlich ausgewählte Algorithmus und die Hyperparameter sollten gespeichert werden, damit sie zum Zeitpunkt der Vorhersage wiederverwendet werden können
Beachten Sie, dass während der Trainingszeit durchgeführtes Feature-Engineering sorgfältig gespeichert werden sollte, um für die Vorhersage anwendbar zu sein. Ein übliches Problem unter vielen anderen, das dabei auftreten kann, ist die Merkmalsskalierung, die für viele Algorithmen notwendig ist.
Wenn Merkmal X1 von Wert 1 auf 1000 skaliert und mit einer Funktion f(x) = x/max(X1)
auf den Bereich [0,1] neu skaliert wird, was würde passieren, wenn der Vorhersagesatz einen Wert von 2000 hat?
Einige sorgfältige Anpassungen sollten im Voraus bedacht werden, damit die Zuordnungsfunktion konsistente Ausgaben zurückgibt, die zum Zeitpunkt der Vorhersage korrekt berechnet werden.
Training für maschinelles Lernen vs. Vorhersage
Hier ist eine wichtige Frage zu klären. Warum trennen wir Training und Vorhersage von Anfang an?
Es ist absolut richtig, dass im Zusammenhang mit Beispielen und Kursen zum maschinellen Lernen, bei denen alle Daten im Voraus bekannt sind (einschließlich der vorherzusagenden Daten), eine sehr einfache Möglichkeit zum Erstellen des Prädiktors darin besteht, Trainings- und Vorhersagedaten (normalerweise als ein Testset).
Dann ist es notwendig, auf dem „Trainingsset“ zu trainieren und auf dem „Testset“ Vorhersagen zu treffen, um die Ergebnisse zu erhalten, während gleichzeitig Feature-Engineering sowohl auf Trainings- als auch auf Testdaten, Training und Vorhersage in derselben und einzigartigen Pipeline durchgeführt wird .
In realen Systemen haben Sie jedoch normalerweise Trainingsdaten, und die vorherzusagenden Daten kommen genau dann herein, wenn sie verarbeitet werden. Mit anderen Worten, Sie sehen sich den Film einmal an und haben später einige Fragen dazu, was bedeutet, dass die Antworten einfach und schnell sein sollten.
Darüber hinaus ist es normalerweise nicht erforderlich, das gesamte Modell jedes Mal neu zu trainieren, wenn neue Daten eingehen, da das Training einige Zeit in Anspruch nimmt (kann bei einigen Bildsätzen Wochen dauern) und im Laufe der Zeit stabil genug sein sollte.
Aus diesem Grund können oder sollten Training und Vorhersage auf vielen Systemen klar getrennt werden, und dies spiegelt auch besser wider, wie ein intelligentes System (künstlich oder nicht) lernt.
Der Zusammenhang mit Overfitting
Die Trennung von Training und Vorhersage ist auch eine gute Möglichkeit, das Overfitting-Problem anzugehen.
In der Statistik ist Überanpassung „die Erstellung einer Analyse, die zu genau oder zu genau einem bestimmten Datensatz entspricht und daher möglicherweise keine zusätzlichen Daten anpasst oder zukünftige Beobachtungen nicht zuverlässig vorhersagt“.
Überanpassung tritt besonders bei Datensätzen mit vielen Merkmalen oder bei Datensätzen mit begrenzten Trainingsdaten auf. In beiden Fällen enthalten die Daten im Vergleich zu dem, was durch den Prädiktor validiert werden kann, zu viele Informationen, und einige von ihnen sind möglicherweise nicht einmal mit der vorhergesagten Variablen verknüpft. In diesem Fall könnte das Rauschen selbst als Signal interpretiert werden.
Eine gute Möglichkeit, Overfitting zu kontrollieren, besteht darin, auf einem Teil der Daten zu trainieren und auf einem anderen Teil Vorhersagen zu treffen, zu denen wir die Grundwahrheit haben. Daher ist der erwartete Fehler bei neuen Daten ungefähr der gemessene Fehler bei diesem Datensatz, vorausgesetzt, die Daten, mit denen wir trainieren, sind repräsentativ für die Realität des Systems und seine zukünftigen Zustände.
Wenn wir also eine geeignete Trainings- und Vorhersagepipeline zusammen mit einer korrekten Aufteilung der Daten entwerfen, gehen wir nicht nur das Overfitting-Problem an, sondern wir können diese Architektur auch für die Vorhersage neuer Daten wiederverwenden.
Der letzte Schritt wäre die Kontrolle, dass der Fehler bei neuen Daten derselbe wie erwartet ist. Es gibt immer eine Verschiebung (der tatsächliche Fehler liegt immer unter dem erwarteten), und man sollte bestimmen, was eine akzeptable Verschiebung ist – aber das ist nicht das Thema dieses Artikels.
Eine REST-API für Vorhersagen
Hier hilft die klare Trennung von Training und Vorhersage. Wenn wir unsere Feature-Engineering-Methoden und unsere Modellparameter gespeichert haben, können wir mit diesen Elementen eine einfache REST-API erstellen.

Der Schlüssel hier ist, das Modell und die Parameter beim API-Start zu laden. Einmal gestartet und im Speicher gespeichert, löst jeder API-Aufruf die Feature-Engineering-Berechnung und die „Vorhersage“-Methode des ML-Algorithmus aus. Beide sind in der Regel schnell genug, um eine Reaktion in Echtzeit zu gewährleisten.
Die API kann so gestaltet werden, dass sie ein einzelnes vorherzusagendes Beispiel oder mehrere unterschiedliche (Batch-Vorhersagen) akzeptiert.
Hier ist der minimale Python/Flask-Code, der dieses Prinzip implementiert, mit JSON in und JSON out (Frage rein, Antwort raus):
app = Flask(__name__) @app.route('/api/makecalc/', methods=['POST']) def makecalc(): """ Function run at each API call No need to re-load the model """ # reads the received json jsonfile = request.get_json() res = dict() for key in jsonfile.keys(): # calculates and predicts res[key] = model.predict(doTheCalculation(key)) # returns a json file return jsonify(res) if __name__ == '__main__': # Model is loaded when the API is launched model = pickle.load(open('modelfile', 'rb')) app.run(debug=True)
Beachten Sie, dass die API für Vorhersagen aus neuen Daten verwendet werden kann, aber ich empfehle nicht, sie zum Trainieren des Modells zu verwenden. Es könnte verwendet werden, aber dies verkompliziert den Modelltrainingscode und könnte hinsichtlich der Speicherressourcen anspruchsvoller sein.
Umsetzungsbeispiel - Bike Sharing
Nehmen wir als Beispiel einen Kaggle-Datensatz, Bike-Sharing. Angenommen, wir sind ein Bike-Sharing-Unternehmen, das die Anzahl der Fahrradverleihe pro Tag prognostizieren möchte, um die Wartung, Logistik und andere geschäftliche Aspekte des Fahrrads besser zu verwalten.
Mieten hängen hauptsächlich von den Wetterbedingungen ab, so dass das Unternehmen mit der Wettervorhersage eine bessere Vorstellung davon bekommen könnte, wann die Mieten ihren Höhepunkt erreichen, und versuchen könnte, Wartungsarbeiten an diesen Tagen zu vermeiden.
Zuerst trainieren wir ein Modell und speichern es als Pickle-Objekt, das im Jupyter-Notebook angezeigt wird.
Modelltraining und -leistung werden hier nicht behandelt, dies ist nur ein Beispiel zum Verständnis des gesamten Prozesses.
Dann schreiben wir die Datentransformation, die bei jedem API-Aufruf durchgeführt wird:
import numpy as np import pandas as pd from datetime import date def doTheCalculation(data): data['dayofyear']=(data['dteday']- data['dteday'].apply(lambda x: date(x.year,1,1)) .astype('datetime64[ns]')).apply(lambda x: x.days) X = np.array(data[['instant','season','yr','holiday','weekday','workingday', 'weathersit','temp','atemp','hum','windspeed','dayofyear']]) return X
Dies ist nur eine Berechnung einer Variablen (Tag des Jahres), um sowohl den Monat als auch den genauen Tag einzubeziehen. Es gibt auch eine Auswahl von Spalten und deren jeweilige Reihenfolge, die eingehalten werden müssen.
Wir müssen also die REST-API mit Flask schreiben:
from flask import Flask, request, redirect, url_for, flash, jsonify from features_calculation import doTheCalculation import json, pickle import pandas as pd import numpy as np app = Flask(__name__) @app.route('/api/makecalc/', methods=['POST']) def makecalc(): """ Function run at each API call """ jsonfile = request.get_json() data = pd.read_json(json.dumps(jsonfile),orient='index',convert_dates=['dteday']) print(data) res = dict() ypred = model.predict(doTheCalculation(data)) for i in range(len(ypred)): res[i] = ypred[i] return jsonify(res) if __name__ == '__main__': modelfile = 'modelfile.pickle' model = pickle.load(open(modelfile, 'rb')) print("loaded OK") app.run(debug=True)
Führen Sie dieses Programm aus, es bedient die API standardmäßig auf Port 5000.
Wenn wir eine Anfrage lokal testen, immer noch mit Python:
import requests, json url = '[http://127.0.0.1:5000/api/makecalc/](http://127.0.0.1:5000/api/makecalc/)' text = json.dumps({"0":{"instant":1,"dteday":"2011-01-01T00:00:00.000Z","season":1,"yr":0,"mnth":1,"holiday":0,"weekday":6,"workingday":0,"weathersit":2,"temp":0.344167,"atemp":0.363625,"hum":0.805833,"windspeed":0.160446}, "1":{"instant":2,"dteday":"2011-01-02T00:00:00.000Z","season":1,"yr":0,"mnth":1,"holiday":0,"weekday":3,"workingday":0,"weathersit":2,"temp":0.363478,"atemp":0.353739,"hum":0.696087,"windspeed":0.248539}, "2":{"instant":3,"dteday":"2011-01-03T00:00:00.000Z","season":1,"yr":0,"mnth":1,"holiday":0,"weekday":1,"workingday":1,"weathersit":1,"temp":0.196364,"atemp":0.189405,"hum":0.437273,"windspeed":0.248309}})
Die Anfrage enthält alle Informationen, die dem Modell zugeführt wurden. Daher antwortet unser Modell mit einer Prognose von Fahrradverleihen für die angegebenen Daten (hier haben wir drei davon).
headers = {'content-type': 'application/json', 'Accept-Charset': 'UTF-8'} r = requests.post(url, data=text, headers=headers) print(r,r.text) <Response [200]> { "0": 1063, "1": 1028, "2": 1399 }
Das ist es! Dieser Service kann problemlos in jeder Unternehmensanwendung verwendet werden, für die Wartungsplanung oder für Benutzer, um den Fahrradverkehr, die Nachfrage und die Verfügbarkeit von Leihrädern zu kennen.
Alles zusammenfügen
Der Hauptfehler vieler maschineller Lernsysteme und insbesondere von PoCs besteht darin, Training und Vorhersage zu mischen.
Wenn sie sorgfältig getrennt werden, können Echtzeitvorhersagen für ein MVP recht einfach durchgeführt werden, und zwar mit recht geringen Entwicklungskosten und -aufwand mit Python/Flask, insbesondere wenn es für viele PoCs ursprünglich mit Scikit-learn, Tensorflow, oder jede andere Python-Bibliothek für maschinelles Lernen.
Dies ist jedoch möglicherweise nicht für alle Anwendungen machbar, insbesondere für Anwendungen, bei denen das Feature-Engineering umfangreich ist, oder für Anwendungen, die die engste Übereinstimmung abrufen und bei jedem Aufruf die neuesten Daten verfügbar haben müssen.
Müssen Sie sich auf jeden Fall immer wieder Filme ansehen, um Fragen dazu zu beantworten? Die gleiche Regel gilt für maschinelles Lernen!