[PYTHON] Verfahren zum Generieren und Speichern eines Lernmodells durch maschinelles Lernen, Erstellen eines API-Servers und Kommunizieren mit JSON über einen Browser

Einführung

Ich habe das durch maschinelles Lernen generierte Lernmodell als API-Server verwendet, Daten vom Browser über JSON-Kommunikation gesendet und den vorhergesagten Wert zurückgegeben. Dieser maschinell erlernte API-Server wird von drei Hauptprogrammen implementiert. Führen Sie zunächst ein Maschinentraining auf XGBoost durch, um das Trainingsmodell zu generieren und zu speichern. Implementieren Sie als Nächstes den Lernmodell-API-Server in Flask. Schreiben Sie abschließend das Formular-Tag in die HTML-Datei, damit die vom Formular-Tag erhaltenen Daten von Ajax aus Javascript mit JSON kommuniziert werden können. Mit diesen drei Programmen können Sie etwas erstellen, das Daten vom Browser an den API-Server sendet und den vorhergesagten Wert zurückgibt.

Umgebung erforderlich, um dieses Programm auszuführen

Bibliotheken wie Anaconda, XGBoost, joblib, Flask und flask-cors sind installiert.

Hauptprozess

Diese API-Kommunikation durch maschinelles Lernen kann wie folgt implementiert werden.

--Erstellen Sie ein Lernmodell mit maschinellem Lernen --Erstellen Sie einen API-Server mit Flask --API-Kommunikation vom Browser

Erstellen Sie ein Lernmodell mit maschinellem Lernen

Hier wird XGBoost verwendet, um ein Trainingsmodell zu generieren. Die Trainingsdaten verwenden den Titanic-Datensatz von Kaggle.

Datensatzvorverarbeitung

Bevor wir mit XGBoost maschinelles Lernen durchführen, führen wir einige Vorverarbeitungen durch. Der Titanic-Datensatz von Kaggle ist in Zug- und Testdaten unterteilt, sodass sie mit concat verkettet werden, um gemeinsam eine Vorverarbeitung durchzuführen. Die Vorverarbeitung umfasst die Verarbeitung fehlender Werte, das Ersetzen kategorialer Daten durch numerische Werte und das Löschen unnötiger Funktionen.

Laden von Bibliotheken und Datensätzen

Laden Sie die für die Vorverarbeitung erforderliche Bibliothek. Wir laden den Datensatz auch als Pandas-Datenrahmen.

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
train_df = pd.read_csv('titanic/train.csv')
test_df = pd.read_csv('titanic/test.csv')
train_df.head()
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
test_df.head()
PassengerId Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 892 3 Kelly, Mr. James male 34.5 0 0 330911 7.8292 NaN Q
1 893 3 Wilkes, Mrs. James (Ellen Needs) female 47.0 1 0 363272 7.0000 NaN S
2 894 2 Myles, Mr. Thomas Francis male 62.0 0 0 240276 9.6875 NaN Q
3 895 3 Wirz, Mr. Albert male 27.0 0 0 315154 8.6625 NaN S
4 896 3 Hirvonen, Mrs. Alexander (Helga E Lindqvist) female 22.0 1 1 3101298 12.2875 NaN S

Dataset-Verkettung

Da ich die Vorverarbeitung gemeinsam durchführen möchte, verkette ich Zugdaten und Testdaten mit concat.

all_df = pd.concat((train_df.loc[:, 'Pclass' : 'Embarked'], test_df.loc[:, 'Pclass' : 'Embarked']))
all_df.info()
<class 'pandas.core.frame.DataFrame'>  
Int64Index: 1309 entries, 0 to 417  
Data columns (total 10 columns):  
Pclass      1309 non-null int64  
Name        1309 non-null object  
Sex         1309 non-null object  
Age         1046 non-null float64  
SibSp       1309 non-null int64  
Parch       1309 non-null int64  
Ticket      1309 non-null object  
Fare        1308 non-null float64  
Cabin       295 non-null object  
Embarked    1307 non-null object  
dtypes: float64(2), int64(3), object(5)  
memory usage: 112.5+ KB  

Umgang mit fehlenden Werten

Da die Werte für Alter, Tarif und Einschiffung fehlen, werden sie mit den durchschnittlichen und häufigsten Werten gefüllt.

all_df['Age'] = all_df['Age'].fillna(all_df['Age'].mean())
all_df['Fare'] = all_df['Fare'].fillna(all_df['Fare'].mean())
all_df['Embarked'] = all_df['Embarked'].fillna(all_df['Embarked'].mode()[0])
all_df.info()
<class 'pandas.core.frame.DataFrame'>  
Int64Index: 1309 entries, 0 to 417  
Data columns (total 10 columns):  
Pclass      1309 non-null int64  
Name        1309 non-null object  
Sex         1309 non-null object  
Age         1309 non-null float64  
SibSp       1309 non-null int64  
Parch       1309 non-null int64  
Ticket      1309 non-null object  
Fare        1309 non-null float64  
Cabin       295 non-null object  
Embarked    1309 non-null object  
dtypes: float64(2), int64(3), object(5)  
memory usage: 112.5+ KB
all_df.head()
Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S

Ersetzen Sie kategoriale Daten durch Zahlen

Geschlecht und Eingeschifft sind kategoriale Daten, daher ersetzt LabelEncoder sie durch Zahlen.

cat_features = ['Sex', 'Embarked']

for col in cat_features:
    lbl = LabelEncoder()
    all_df[col] = lbl.fit_transform(list(all_df[col].values))
all_df.head()
Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 3 Braund, Mr. Owen Harris 1 22.0 1 0 A/5 21171 7.2500 NaN 2
1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... 0 38.0 1 0 PC 17599 71.2833 C85 0
2 3 Heikkinen, Miss. Laina 0 26.0 0 0 STON/O2. 3101282 7.9250 NaN 2
3 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) 0 35.0 1 0 113803 53.1000 C123 2
4 3 Allen, Mr. William Henry 1 35.0 0 0 373450 8.0500 NaN 2

Löschen Sie unnötige Funktionen

Name und Ticket sind kategoriale und eindeutige Werte. Löschen Sie sie daher. Außerdem fehlen in Cabin viele Werte. Löschen Sie sie daher.

all_df = all_df.drop(columns = ['Name', 'Ticket', 'Cabin'])
all_df.head()
Pclass Sex Age SibSp Parch Fare Embarked
0 3 1 22.0 1 0 7.2500 2
1 1 0 38.0 1 0 71.2833 0
2 3 0 26.0 0 0 7.9250 2
3 1 0 35.0 1 0 53.1000 2
4 3 1 35.0 0 0 8.0500 2

Zug und Test wie zuvor trennen

Da Zug und Test verbunden waren, werden Zug und Test getrennt, so dass sie zu Trainingsdaten werden. Sie können Zug und Test trennen, indem Sie den Formwert von train_df verwenden.

train = all_df[:train_df.shape[0]]
test = all_df[train_df.shape[0]:]
train.info()
<class 'pandas.core.frame.DataFrame'>  
Int64Index: 891 entries, 0 to 890  
Data columns (total 7 columns):  
Pclass      891 non-null int64  
Sex         891 non-null int64  
Age         891 non-null float64  
SibSp       891 non-null int64  
Parch       891 non-null int64  
Fare        891 non-null float64  
Embarked    891 non-null int64  
dtypes: float64(2), int64(5)  
memory usage: 55.7 KB  

Generieren Sie mit XGBoost ein Trainingsmodell

Nachdem die Vorverarbeitung abgeschlossen ist, werden wir weiterhin maschinelles Lernen mit XGBoost durchführen. Anstatt die Genauigkeit des Lernmodells zu verbessern, besteht diesmal der Zweck darin, einen API-Server unter Verwendung des Lernmodells zu erstellen, sodass Parameter usw. mit fast Standardwerten gelernt werden.

y = train_df['Survived']
X_train, X_test, y_train, y_test = train_test_split(train, y, random_state = 0)
import xgboost as xgb
params = {
    "objective": "binary:logistic",
    "eval_metric": "auc",
    "eta": 0.1,
    "max_depth": 6,
    "subsample": 1,
    "colsample_bytree": 1,
    "silent": 1
}

dtrain = xgb.DMatrix(X_train, label = y_train)
dtest = xgb.DMatrix(X_test, label = y_test)

model = xgb.train(params = params,
                 dtrain = dtrain,
                 num_boost_round = 100,
                 early_stopping_rounds = 10,
                 evals = [(dtest, 'test')])
[0]	test-auc:0.886905  
Will train until test-auc hasn't improved in 10 rounds.  
[1]	test-auc:0.89624  
[2]	test-auc:0.893243  
[3]	test-auc:0.889603  
[4]	test-auc:0.892857  
[5]	test-auc:0.886005  
[6]	test-auc:0.890673  
[7]	test-auc:0.894741  
[8]	test-auc:0.889603  
[9]	test-auc:0.888832  
[10]	test-auc:0.889431  
[11]	test-auc:0.89153  
Stopping. Best iteration:  
[1]	test-auc:0.89624  

Speichern Sie das Trainingsmodell mit joblib

Es gibt verschiedene Möglichkeiten, ein maschinell geschultes Trainingsmodell zu speichern. Hier verwenden wir jedoch joblib, um es als pkl-Datei zu speichern. Da die gespeicherte pkl-Datei am angegebenen Speicherort gespeichert ist, kopieren Sie sie anschließend in den Ordner des API-Servers und verwenden Sie sie.

from sklearn.externals import joblib
joblib.dump(model, 'titanic_model.pkl')

['titanic_model.pkl']

Erstellen Sie einen API-Server mit Flask

Hier versuchen wir, das durch maschinelles Lernen erzeugte Lernmodell als API-Server zu verwenden. Flask, ein Python-Microservice-Framework, wird für die API-Serverentwicklung verwendet. Der Entwicklungsfluss besteht darin, eine virtuelle Umgebung mit conda zu erstellen, einen einfachen API-Server zu testen und das mit XGBoost erstellte Lernmodell darauf zu setzen.

Erstellen Sie eine virtuelle Umgebung mit conda

Die virtuelle Umgebung verwendet Anacondas Conda. Erstellen Sie im Terminal einen Ordner für die App-Entwicklung (in diesem Fall titanic_api) und verschieben Sie ihn in diesen Ordner. Dann erstellt conda create die virtuelle Umgebung und conda enable aktiviert die virtuelle Umgebung.

mkdir titanic_api
cd titanic_api
conda create -n titanictenv
conda activate titanictenv

API mit Flask entwickeln

Um einen API-Server mit Flask zu entwickeln, erstellen und testen Sie zunächst einen einfachen API-Server. Erstellen Sie die folgenden Ordner und Dateien in dem zuvor erstellten Ordner. Wenn Sie den folgenden Code in jede Datei schreiben, den API-Server starten und über Curl kommunizieren können, ist der einfache API-Servertest erfolgreich.

Generieren Sie die erforderlichen Ordner und Dateien im Terminal.

Erstellen Sie Ordner und Dateien so, dass sie die folgende Hierarchie haben. Wenn Sie eine leere Datei erstellen möchten, können Sie bequem den Befehl touch verwenden.

titanic_api
├── api
│   ├── __init__.py
│   └── views
│       └── user.py
├── titanic_app.py
└── titanic_model.pkl

Schreiben Sie Code in die erstellte Datei

Schreiben Sie den folgenden Code in die zuvor erstellte Datei. Zum Testen eines einfachen API-Servers sind drei Dateien erforderlich: api / views / user.py, api / __ init__.py und titanic_app.py. Es ist praktisch, beim Schreiben im Terminal vim und beim Schreiben in der GUI Atom zu verwenden.

api/views/user.py


from flask import Blueprint, request, make_response, jsonify

#Routing-Einstellungen
user_router = Blueprint('user_router', __name__)

#Geben Sie den Pfad und die HTTP-Methode an
@user_router.route('/users', methods=['GET'])
def get_user_list():

  return make_response(jsonify({
    'users': [
       {
         'id': 1,
         'name': 'John'
       }
     ]
  }))

api/__init__.py


from flask import Flask, make_response, jsonify
from .views.user import user_router

def create_app():

  app = Flask(__name__)
  app.register_blueprint(user_router, url_prefix='/api')

  return app

app = create_app()

titanic_app.py


from api import app

if __name__ == '__main__':
  app.run()

Greifen Sie mit Curl auf den API-Server zu.

Starten Sie den Server nach dem Schreiben des obigen Codes mit python titanic_app.py. Wenn es erfolgreich gestartet wurde, öffnen Sie ein anderes Terminal und testen Sie die Kommunikation mit dem Befehl curl wie folgt. Wenn die Kommunikation erfolgreich ist, werden die folgenden Daten zurückgegeben.

curl http://127.0.0.1:5000/api/users
{
  "users": [
    {
      "id": 1, 
      "name": "John"
    }
  ]
}

Machen Sie das xgboost-Modell zu einem API-Server

Schreiben Sie titanic_app.py, die Startdatei des einfachen API-Servers, wie folgt neu. Zu diesem Zeitpunkt muss das Lernmodell direkt unter titanic_api gespeichert werden.

titanic_app.py


import json

from flask import Flask
from flask import request
from flask import abort

import pandas as pd
from sklearn.externals import joblib
import xgboost as xgb

model = joblib.load("titanic_model.pkl")

app = Flask(__name__)

# Get headers for payload
headers = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']

@app.route('/titanic', methods=['POST'])
def titanic():
    if not request.json:
        abort(400)
    payload = request.json['data']
    values = [float(i) for i in payload.split(',')]
    data1 = pd.DataFrame([values], columns=headers, dtype=float)
    predict = model.predict(xgb.DMatrix(data1))
    return json.dumps(str(predict[0]))


if __name__ == "__main__":
    app.run(debug=True, port=5000)

Führen Sie einen API-Kommunikationstest mit Curl durch

Starten Sie den API-Server nach dem Umschreiben des Codes erneut mit python titanic_app.py. Nach dem Start des API-Servers wird der Kommunikationstest mit dem Befehl curl wie unten gezeigt durchgeführt. Es ist erfolgreich, wenn für die gesendeten JSON-Daten ein Wert mit einem Dezimalpunkt von 1 oder weniger zurückgegeben wird. Sie haben das durch maschinelles Lernen generierte Lernmodell nun in einen API-Server umgewandelt.

curl http://localhost:5000/titanic -s -X POST -H "Content-Type: application/json" -d '{"data": "3, 1, 22.0, 1, 0, 7.2500, 2"}'

API-Kommunikation über den Browser

Zusätzlich zur Kommunikation mit dem Befehl curl vom Terminal erstellen wir etwas, das den vorhergesagten Wert zurückgibt, wenn ein Wert vom Browser eingegeben wird. Hier müssen wir die Ajax-Kommunikation mit dem zuvor erstellten API-Server aktivieren und die Kommunikation vom Browser zum API-Server mit einer HTML-Datei aktivieren.

Ermöglichen Sie, dass json über Ajax-Kommunikation an den API-Server gesendet wird

Um mit Javascript Ajax aus HTML kommunizieren zu können, muss die in Flask geschriebene API-Server-Startdatei wie folgt hinzugefügt werden. Ich werde eine Bibliothek namens flask_cors und verwandten Code hinzufügen. flask_cors muss vorinstalliert sein.

titanic_app.py


import json

from flask import Flask
from flask import request
from flask import abort
from flask_cors import CORS #hinzufügen

import pandas as pd
from sklearn.externals import joblib
import xgboost as xgb

model = joblib.load("titanic_model.pkl")

app = Flask(__name__)

#hinzufügen
@app.after_request
def after_request(response):
  response.headers.add('Access-Control-Allow-Origin', '*')
  response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
  response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
  return response
#↑ Hier addieren

# Get headers for payload
headers = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']

@app.route('/titanic', methods=['POST'])
def titanic():
    if not request.json:
        abort(400)
    payload = request.json['data']
    values = [float(i) for i in payload.split(',')]
    data1 = pd.DataFrame([values], columns=headers, dtype=float)
    predict = model.predict(xgb.DMatrix(data1))
    return json.dumps(str(predict[0]))


if __name__ == "__main__":
    app.run(debug=True, port=5000)

Senden Sie JSON-Daten per POST aus einer HTML-Datei

In der HTML-Datei ist der Schnittstellenteil das Eingabe-Tag innerhalb des -Tags usw. und erstellt ein Dateneingabeformular. Die Eingabedaten werden per Javascript empfangen, formatiert, in das JSON-Format konvertiert und per Ajax-Kommunikation POST. Wenn die Kommunikation erfolgreich ist, wird der vorhergesagte Wert vom API-Server empfangen und im Bereich des Textbereichs-Tags angezeigt.

index.html


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Senden Sie JSON-Daten per POST aus einer HTML-Datei</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>

<script type="text/javascript">
    $(function(){
        $("#response").html("Response Values");

        $("#button").click( function(){
            var url = $("#url_post").val();
            var feature1 =
                $("#value1").val() + "," +
                $("#value2").val() + "," +
                $("#value3").val() + "," +
                $("#value4").val() + "," +
                $("#value5").val() + "," +
                $("#value6").val() + "," +
                $("#value7").val();

            var JSONdata = {
                    data: feature1
                };

            alert(JSON.stringify(JSONdata));

            $.ajax({
                type: 'POST',
                url: url,
                data: JSON.stringify(JSONdata),
                contentType: 'application/JSON',
                dataType: 'JSON',
                scriptCharset: 'utf-8',
                success : function(data) {

                    // Success
                    alert("success");
                    alert(JSON.stringify(JSONdata));
                    $("#response").html(JSON.stringify(data));
                },
                error : function(data) {

                    // Error
                    alert("error");
                    alert(JSON.stringify(JSONdata));
                    $("#response").html(JSON.stringify(data));
                }
            });
        })
    })
</script>

</head>
<body>
    <h1>Senden Sie JSON-Daten per POST aus einer HTML-Datei</h1>
    <p>URL: <input type="text" id="url_post" name="url" size="100" value="http://localhost:5000/titanic"></p>
    <p>Pclass: <input type="number" id="value1" size="30" value=3></p>
    <p>Sex: <input type="number" id="value2" size="30" value=1></p>
    <p>Age: <input type="number" id="value3" size="30" value="22.0"></p>
    <p>SibSp: <input type="number" id="value4" size="30" value="1"></p>
    <p>Parch: <input type="number" id="value5" size="30" value="0"></p>
    <p>Fare: <input type="number" id="value6" size="30" value="7.2500"></p>
    <p>Embarked: <input type="number" id="value7" size="30" value="2"></p>
    <p><button id="button" type="button">submit</button></p>
    <textarea id="response" cols=120 rows=10 disabled></textarea>
</body>
</html>

Referenz Erstellen Sie eine virtuelle Umgebung mit conda: https://code-graffiti.com/how-to-build-a-virtual-environment-with-conda/ Entwickeln Sie die API mit der Flasche: https://swallow-incubate.com/archives/blog/20190819 Machen Sie das xgboost-Modell zu einem API-Server: https://towardsdatascience.com/publishing-machine-learning-api-with-python-flask-98be46fb2440 Ermöglichen Sie, dass json über Ajax-Kommunikation an den API-Server gesendet wird: https://www.hands-lab.com/tech/entry/3716.html Senden Sie JSON-Daten per POST aus der HTML-Datei: https://qiita.com/kidatti/items/21cc5c5154dbbb1aa27f

Recommended Posts

Verfahren zum Generieren und Speichern eines Lernmodells durch maschinelles Lernen, Erstellen eines API-Servers und Kommunizieren mit JSON über einen Browser
Ein Beispiel für einen Mechanismus, der eine Vorhersage von HTTP aus dem Ergebnis des maschinellen Lernens zurückgibt
Ich habe einen Server mit Python-Socket und SSL erstellt und versucht, über den Browser darauf zuzugreifen
Ich habe mit Docker eine API erstellt, die den vorhergesagten Wert des maschinellen Lernmodells zurückgibt
(Deep Learning) Ich habe Bilder von der Flickr-API gesammelt und versucht, durch Transferlernen mit VGG16 zu unterscheiden
Ich habe versucht, die Vorhersage-API des maschinellen Lernmodells von WordPress aus aufzurufen
Machen Sie ein Thermometer mit Raspberry Pi und machen Sie es im Browser Teil 3 sichtbar
Implementierung eines Modells, das Wechselkurse (Dollar-Yen-Kurs) durch maschinelles Lernen vorhersagt
[Maschinelles Lernen] Erstellen Sie ein Modell für maschinelles Lernen, indem Sie Transferlernen mit Ihrem eigenen Datensatz durchführen
Von der Einführung von Flask unter CentOS bis zum Service unter Nginx und uWSGI
Bis Sie mit Python unter Windows 7 eine maschinelle Lernumgebung erstellen und ausführen
Ein Skript, das den registrierten Server anpingt und eine bestimmte Anzahl von E-Mails mit Google Mail sendet, wenn dies fehlschlägt
POST das Bild mit json und erhalte es mit der Flasche
Erstellen Sie mit Winsows 10 eine maschinelle Lernumgebung von Grund auf neu
Einführung in das maschinelle Lernen mit Simple Perceptron
Eine konkrete Methode zur Vorhersage von Pferderennen und zur Simulation der Wiederherstellungsrate durch maschinelles Lernen
So zeichnen Sie interaktiv eine Pipeline für maschinelles Lernen mit scikit-learn und speichern sie in HTML
[In-Database Python Analysis Tutorial mit SQL Server 2017] Schritt 5: Training und Speichern von Modellen mit T-SQL
Vorsichtsmaßnahmen bei der Eingabe von CSV mit Python und der Ausgabe an json, um exe zu erstellen