En utilisant le modèle d'apprentissage généré par l'apprentissage automatique en tant que serveur API, j'ai envoyé des données du navigateur via une communication JSON et renvoyé la valeur prédite. Ce serveur API appris par machine est implémenté par trois programmes principaux. Tout d'abord, effectuez un entraînement machine sur XGBoost pour générer et enregistrer le modèle d'entraînement. Ensuite, implémentez le serveur d'API du modèle d'apprentissage dans Flask. Enfin, écrivez la balise form dans le fichier HTML afin que les données obtenues à partir de la balise form puissent être communiquées avec JSON par Ajax de javascript. Avec ces trois programmes, vous pouvez créer quelque chose qui envoie des données du navigateur au serveur API et renvoie la valeur prévue.
Des bibliothèques telles que Anaconda, XGBoost, joblib, Flask et flask-cors sont installées.
Cette communication API par machine learning peut être implémentée en suivant le processus suivant.
--Créez un modèle d'apprentissage avec l'apprentissage automatique --Créer un serveur API avec flask
Ici, XGBoost est utilisé pour générer un modèle d'entraînement. Les données d'entraînement utilisent l'ensemble de données Titanic de Kaggle.
Avant de faire du machine learning avec XGBoost, nous effectuons un pré-traitement. L'ensemble de données Titanic de Kaggle est divisé en données de train et de test, de sorte qu'ils sont concaténés avec concat pour effectuer le prétraitement ensemble. Le prétraitement comprend le traitement des valeurs manquantes, le remplacement des données catégorielles par des valeurs numériques et la suppression des fonctionnalités inutiles.
Chargez la bibliothèque requise pour le prétraitement. Nous chargeons également l'ensemble de données en tant que dataframe pandas.
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 |
Puisque je souhaite effectuer le prétraitement collectivement, je concatène les données de train et les données de test avec 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
Étant donné que les valeurs Âge, Tarif et Embarqué sont manquantes, elles sont remplies avec les valeurs moyennes et les plus fréquentes.
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 |
Sex et Embarked sont des données catégoriques, donc LabelEncoder les remplace par des nombres.
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 |
Le nom et le ticket sont des valeurs catégorielles et uniques, supprimez-les. En outre, Cabin a de nombreuses valeurs manquantes, supprimez-le.
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 |
Puisque le train et le test ont été connectés, le train et le test sont séparés pour devenir des données d'entraînement. Vous pouvez séparer le train et le test en utilisant la valeur de forme de train_df.
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
Maintenant que le prétraitement est terminé, nous continuerons à effectuer un apprentissage automatique avec XGBoost. Cette fois, plutôt que d'améliorer la précision du modèle d'apprentissage, le but est de créer un serveur API à l'aide du modèle d'apprentissage, de sorte que les paramètres, etc., sont appris avec des valeurs presque par défaut.
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
Il existe plusieurs façons d'enregistrer un modèle d'entraînement entraîné par machine, mais ici, nous utilisons joblib pour l'enregistrer en tant que fichier pkl. Étant donné que le fichier pkl enregistré est enregistré à l'emplacement spécifié, copiez-le dans le dossier du serveur API après cela et utilisez-le.
from sklearn.externals import joblib
joblib.dump(model, 'titanic_model.pkl')
['titanic_model.pkl']
Ici, nous essayons d'utiliser le modèle d'apprentissage généré par l'apprentissage automatique en tant que serveur API. Flask, un framework de microservices Python, est utilisé pour le développement de serveurs API. Le flux de développement consiste à créer un environnement virtuel avec conda, à tester un serveur API simple et à y placer le modèle d'apprentissage créé avec XGBoost.
L'environnement virtuel utilise la conda d'Anaconda. Créez un dossier pour le développement d'applications (titanic_api dans ce cas) dans le terminal et déplacez-le vers ce dossier. Ensuite, conda create crée l'environnement virtuel et conda activate active l'environnement virtuel.
mkdir titanic_api
cd titanic_api
conda create -n titanictenv
conda activate titanictenv
Pour développer un serveur API avec Flask, commencez par créer et tester un serveur API simple. Créez les dossiers et fichiers suivants dans le dossier que vous avez créé précédemment. Si vous pouvez écrire le code suivant dans chaque fichier, démarrer le serveur API et communiquer à partir de curl, le test simple du serveur API réussit.
Créez des dossiers et des fichiers afin qu'ils aient la hiérarchie suivante. Si vous souhaitez créer un fichier vide, il est pratique d'utiliser la commande tactile.
titanic_api
├── api
│ ├── __init__.py
│ └── views
│ └── user.py
├── titanic_app.py
└── titanic_model.pkl
Écrivez le code suivant dans le fichier que vous avez créé précédemment. Trois fichiers sont nécessaires pour tester un serveur API simple: api / views / user.py, api / __ init__.py et titanic_app.py. Il est pratique d'utiliser vim lors de l'écriture dans le terminal et Atom lors de l'écriture dans l'interface graphique.
api/views/user.py
from flask import Blueprint, request, make_response, jsonify
#Paramètres de routage
user_router = Blueprint('user_router', __name__)
#Spécifiez le chemin et la méthode HTTP
@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()
Après avoir écrit le code ci-dessus, démarrez le serveur avec python titanic_app.py. S'il démarre correctement, ouvrez un autre terminal et testez la communication avec la commande curl comme suit. Si la communication réussit, les données suivantes seront renvoyées.
curl http://127.0.0.1:5000/api/users
{
"users": [
{
"id": 1,
"name": "John"
}
]
}
Réécrivez titanic_app.py, qui est le fichier de démarrage du serveur API simple, comme suit. À ce stade, le modèle d'apprentissage doit être enregistré directement sous titanic_api.
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)
Après avoir réécrit le code, redémarrez le serveur API avec python titanic_app.py. Une fois le serveur API démarré, le test de communication est effectué avec la commande curl comme indiqué ci-dessous. Il réussit si une valeur avec un point décimal de 1 ou moins est renvoyée pour les données JSON envoyées. Vous avez maintenant transformé le modèle d'apprentissage généré par l'apprentissage automatique en serveur API.
curl http://localhost:5000/titanic -s -X POST -H "Content-Type: application/json" -d '{"data": "3, 1, 22.0, 1, 0, 7.2500, 2"}'
Enfin, en plus de la communication à l'aide de la commande curl depuis le terminal, nous allons créer quelque chose qui renvoie la valeur prédite lorsqu'une valeur est saisie depuis le navigateur. Ce que nous devons faire ici est d'activer la communication Ajax avec le serveur API créé précédemment et d'activer la communication du navigateur au serveur API avec un fichier HTML.
Ici, pour pouvoir communiquer depuis HTML avec javascript Ajax, il est nécessaire d'ajouter le fichier de démarrage du serveur API écrit en Flask comme suit. J'ajouterai une bibliothèque appelée flask_cors et le code associé. flask_cors doit être préinstallé.
titanic_app.py
import json
from flask import Flask
from flask import request
from flask import abort
from flask_cors import CORS #ajouter
import pandas as pd
from sklearn.externals import joblib
import xgboost as xgb
model = joblib.load("titanic_model.pkl")
app = Flask(__name__)
#ajouter à
@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
#↑ Ajouter ici
# 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)
Dans le fichier HTML, la partie interface est la balise d'entrée à l'intérieur de la balise
, etc., et crée un formulaire d'entrée de données. Les données d'entrée sont reçues par javascript, formatées, converties au format JSON et POSTées par la communication Ajax. Lorsque la communication est réussie, la valeur prédite du serveur API est reçue et affichée dans la zone de la balise textarea.index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Envoyer des données JSON par POST à partir d'un fichier HTML</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>Envoyer des données JSON par POST à partir d'un fichier HTML</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>
référence Construisez un environnement virtuel avec conda: https://code-graffiti.com/how-to-build-a-virtual-environment-with-conda/ Développer une API avec flask: https://swallow-incubate.com/archives/blog/20190819 Faites du modèle xgboost un serveur API: https://towardsdatascience.com/publishing-machine-learning-api-with-python-flask-98be46fb2440 Autoriser json à être POSTÉ sur le serveur API via la communication Ajax: https://www.hands-lab.com/tech/entry/3716.html Envoyer des données JSON par POST à partir d'un fichier HTML: https://qiita.com/kidatti/items/21cc5c5154dbbb1aa27f
Recommended Posts