Chers amis, fin mars, nous lançons un nouveau volet sur le cours
«Data Scientist» . Et maintenant, nous commençons à partager avec vous des informations utiles sur le cours.
PrésentationRappelant les premières expériences de ma passion pour l'apprentissage automatique (ML), je peux dire que beaucoup d'efforts ont été consacrés à la construction d'un très bon modèle. J'ai consulté des experts dans ce domaine pour comprendre comment améliorer mon modèle, pensé aux fonctions nécessaires, essayé de m'assurer que tous les conseils qu'ils proposaient étaient pris en compte. Mais j'ai quand même rencontré un problème.
Comment implémenter le modèle dans un vrai projet? Je n'avais aucune idée sur ce point. Toute la littérature que j'ai étudiée jusqu'à présent ne portait que sur l'amélioration des modèles. Je n'ai pas vu la prochaine étape de leur développement.

C'est pourquoi j'écris ce guide maintenant. Je veux que vous affrontiez le problème que j'ai rencontré à mon époque, mais je pourrais le résoudre rapidement. Vers la fin de cet article, je vais vous montrer comment implémenter un modèle d'apprentissage automatique en utilisant le framework Flask en Python.
Table des matières- Options de mise en œuvre pour les modèles d'apprentissage automatique.
- Qu'est-ce qu'une API?
- Installation de l'environnement Python et des informations de base sur Flask.
- Création d'un modèle d'apprentissage automatique.
- Enregistrement de modèles d'apprentissage automatique: sérialisation et désérialisation.
- Création d'une API à l'aide de Flask.
Options de mise en œuvre pour les modèles d'apprentissage automatique.
Dans la plupart des cas, l'utilisation réelle des modèles d'apprentissage automatique est un élément central du développement, même s'il ne s'agit que d'un petit composant d'un système de distribution de courrier électronique automatisé ou d'un chatbot. Il arrive parfois que les obstacles à la mise en œuvre semblent insurmontables.
Par exemple, la plupart des spécialistes ML utilisent R ou Python pour leurs recherches scientifiques. Cependant, les ingénieurs logiciels qui utilisent une pile technologique complètement différente seront les consommateurs de ces modèles. Deux options peuvent résoudre ce problème:
Option 1: réécrire tout le code dans le langage avec lequel les ingénieurs de développement travaillent. Cela semble dans une certaine mesure logique, mais il faut beaucoup de temps et d'efforts pour reproduire les modèles développés. En fin de compte, cela s'avère juste une perte de temps. La plupart des langages, tels que JavaScript, ne disposent pas de bibliothèques pratiques pour travailler avec ML. Par conséquent, ce sera une solution rationnelle de ne pas utiliser cette option.
Option 2: utilisez l'API. Les API réseau ont résolu le problème de travailler avec des applications dans différentes langues. Si le développeur front-end doit utiliser votre modèle d'apprentissage automatique pour créer une application Web sur sa base, il n'a qu'à obtenir l'URL du serveur de destination discutant de l'API.
Qu'est-ce qu'une API?En termes simples, l'API (Application Programming Interface) est une sorte de contrat entre deux programmes, qui dit que si un programme utilisateur fournit des données d'entrée dans un format spécifique, le programme développeur (API) les transmet et fournit à l'utilisateur des données de sortie.
Vous pourrez lire vous-même quelques articles, qui décrivent bien pourquoi l'API est un choix assez populaire parmi les développeurs.
La plupart des grands fournisseurs de services cloud et les petites entreprises axées sur l'apprentissage automatique fournissent des API prêtes à l'emploi. Ils répondent aux besoins des développeurs qui ne comprennent pas le machine learning, mais souhaitent intégrer cette technologie dans leurs solutions.
Par exemple, l'un de ces fournisseurs d'API est Google avec son
API Google Vision .
Tout ce que le développeur doit faire est simplement d'appeler l'API REST (Representational State Transfer) à l'aide du SDK fourni par Google. Découvrez ce que vous pouvez faire en utilisant l'
API Google Vision .
Sonne bien, non? Dans cet article, nous découvrirons comment créer votre propre API à l'aide de Flask, un framework Python.
Remarque : Flask n'est pas la seule infrastructure réseau à cet effet. Il existe également Django, Falcon, Hug et bien d'autres qui ne sont pas mentionnés dans cet article. Par exemple, pour R, il existe un package appelé
plombierInstallation de l'environnement Python et des informations de base sur Flask.1) Création d'un environnement virtuel à l'aide d'Anaconda. Si vous devez créer votre propre environnement virtuel pour Python et maintenir l'état nécessaire des dépendances, Anaconda propose de bonnes solutions pour cela. Next fonctionnera avec la ligne de commande.
- Vous trouverez ici le programme d' installation de miniconda pour Python;
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh
- Suivez la séquence de questions.
source .bashrc
- Si vous tapez:
conda
, vous pouvez voir une liste des commandes et de l'aide disponibles. - Pour créer un nouvel environnement, tapez:
conda create --name <environment-name> python=3.6
- Suivez les étapes qui vous seront demandées et à la fin entrez:
source activate <environment-name>
- Installez les packages Python requis. Les plus importants sont le flacon et le gunicorn.
2) Nous allons essayer de créer notre application Flask «Hello world» simple en utilisant gunicorn .- Ouvrez votre éditeur de texte préféré et créez le fichier
hello-world.py
dans le dossier - Écrivez le code suivant:
"""Filename: hello-world.py """ from flask import Flask app = Flask(__name__) @app.route('/users/<string:username>') def hello_world(username=None): return("Hello {}!".format(username))
- Enregistrez le fichier et revenez au terminal.
- Pour lancer l'API, exécutez dans le terminal:
gunicorn --bind 0.0.0.0:8000 hello-world:app
- Si vous obtenez ce qui suit, alors vous ĂŞtes sur la bonne voie:

- Dans le navigateur, entrez les informations suivantes:
https://localhost:8000/users/any-name

Hourra! Vous avez écrit votre premier programme Flask! Puisque vous avez déjà une certaine expérience de ces étapes simples, nous pouvons créer des points de terminaison réseau accessibles localement.
En utilisant Flask, nous pouvons envelopper nos modèles et les utiliser comme API Web. Si nous voulons créer des applications réseau plus complexes (par exemple, en JavaScript), nous devons ajouter quelques modifications.
Création d'un modèle d'apprentissage automatique.- Pour commencer, jetons un coup d'œil au concours d' apprentissage automatique Loan Prediction Competition . L'objectif principal est de mettre en place un pipeline de prétraitement et de créer des modèles ML pour faciliter la tâche de prédiction lors du déploiement.
import os import json import numpy as np import pandas as pd from sklearn.externals import joblib from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.base import BaseEstimator, TransformerMixin from sklearn.ensemble import RandomForestClassifier from sklearn.pipeline import make_pipeline import warnings warnings.filterwarnings("ignore")
- Enregistrez l'ensemble de données dans le dossier:
!ls /home/pratos/Side-Project/av_articles/flask_api/data/
test.csv training.csv
data = pd.read_csv('../data/training.csv')
list(data.columns)
['Loan_ID', 'Gender', 'Married', 'Dependents', 'Education', 'Self_Employed', 'ApplicantIncome', 'CoapplicantIncome', 'LoanAmount', 'Loan_Amount_Term', 'Credit_History', 'Property_Area', 'Loan_Status']
data.shape
(614, 13)
ul>
Trouvez les valeurs null / Nan dans les colonnes:
for _ in data.columns: print("The number of null values in:{} == {}".format(_, data[_].isnull().sum()))
The number of null values in:Loan_ID == 0 The number of null values in:Gender == 13 The number of null values in:Married == 3 The number of null values in:Dependents == 15 The number of null values in:Education == 0 The number of null values in:Self_Employed == 32 The number of null values in:ApplicantIncome == 0 The number of null values in:CoapplicantIncome == 0 The number of null values in:LoanAmount == 22 The number of null values in:Loan_Amount_Term == 14 The number of null values in:Credit_History == 50 The number of null values in:Property_Area == 0 The number of null values in:Loan_Status == 0
- L'étape suivante consiste à créer des ensembles de données pour la formation et les tests:
red_var = ['Gender','Married','Dependents','Education','Self_Employed','ApplicantIncome','CoapplicantIncome',\ 'LoanAmount','Loan_Amount_Term','Credit_History','Property_Area'] X_train, X_test, y_train, y_test = train_test_split(data[pred_var], data['Loan_Status'], \ test_size=0.25, random_state=42)
- Pour nous assurer que toutes les étapes de pré-traitement sont terminées correctement même après avoir expérimenté, et que nous n'avons rien manqué pendant la prédiction, nous allons créer notre propre évaluateur Scikit-learn pour le pré-traitement (pré-traitement de l'estimateur Scikit-learn) .
Pour comprendre comment nous l'avons créé, lisez ce qui
suit .
from sklearn.base import BaseEstimator, TransformerMixin class PreProcessing(BaseEstimator, TransformerMixin): """Custom Pre-Processing estimator for our use-case """ def __init__(self): pass def transform(self, df): """Regular transform() that is a help for training, validation & testing datasets (NOTE: The operations performed here are the ones that we did prior to this cell) """ pred_var = ['Gender','Married','Dependents','Education','Self_Employed','ApplicantIncome',\ 'CoapplicantIncome','LoanAmount','Loan_Amount_Term','Credit_History','Property_Area'] df = df[pred_var] df['Dependents'] = df['Dependents'].fillna(0) df['Self_Employed'] = df['Self_Employed'].fillna('No') df['Loan_Amount_Term'] = df['Loan_Amount_Term'].fillna(self.term_mean_) df['Credit_History'] = df['Credit_History'].fillna(1) df['Married'] = df['Married'].fillna('No') df['Gender'] = df['Gender'].fillna('Male') df['LoanAmount'] = df['LoanAmount'].fillna(self.amt_mean_) gender_values = {'Female' : 0, 'Male' : 1} married_values = {'No' : 0, 'Yes' : 1} education_values = {'Graduate' : 0, 'Not Graduate' : 1} employed_values = {'No' : 0, 'Yes' : 1} property_values = {'Rural' : 0, 'Urban' : 1, 'Semiurban' : 2} dependent_values = {'3+': 3, '0': 0, '2': 2, '1': 1} df.replace({'Gender': gender_values, 'Married': married_values, 'Education': education_values, \ 'Self_Employed': employed_values, 'Property_Area': property_values, \ 'Dependents': dependent_values}, inplace=True) return df.as_matrix() def fit(self, df, y=None, **fit_params): """Fitting the Training dataset & calculating the required values from train eg: We will need the mean of X_train['Loan_Amount_Term'] that will be used in transformation of X_test """ self.term_mean_ = df['Loan_Amount_Term'].mean() self.amt_mean_ = df['LoanAmount'].mean() return self
- Convertissez
y_train
et y_test
en np.array
:
y_train = y_train.replace({'Y':1, 'N':0}).as_matrix() y_test = y_test.replace({'Y':1, 'N':0}).as_matrix()
Créons un pipeline pour nous assurer que toutes les étapes de prétraitement que nous effectuons sont le travail de l'évaluateur scikit-learn.
pipe = make_pipeline(PreProcessing(), RandomForestClassifier())
pipe
Pipeline(memory=None, steps=[('preprocessing', PreProcessing()), ('randomforestclassifier', RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini', max_depth=None, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1, oob_score=False, random_state=None, verbose=0, warm_start=False))])
Pour rechercher des hyper paramètres appropriés (degré pour les objets polynomiaux et alpha pour une arête), nous allons faire une recherche de grille (Grid Search):
param_grid = {"randomforestclassifier__n_estimators" : [10, 20, 30], "randomforestclassifier__max_depth" : [None, 6, 8, 10], "randomforestclassifier__max_leaf_nodes": [None, 5, 10, 20], "randomforestclassifier__min_impurity_split": [0.1, 0.2, 0.3]}
- Lance la recherche dans la grille:
grid = GridSearchCV(pipe, param_grid=param_grid, cv=3)
- Nous ajustons les données de formation pour l'estimateur de pipeline:
grid.fit(X_train, y_train)
GridSearchCV(cv=3, error_score='raise', estimator=Pipeline(memory=None, steps=[('preprocessing', PreProcessing()), ('randomforestclassifier', RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini', max_depth=None, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impu..._jobs=1, oob_score=False, random_state=None, verbose=0, warm_start=False))]), fit_params=None, iid=True, n_jobs=1, param_grid={'randomforestclassifier__n_estimators': [10, 20, 30], 'randomforestclassifier__max_leaf_nodes': [None, 5, 10, 20], 'randomforestclassifier__min_impurity_split': [0.1, 0.2, 0.3], 'randomforestclassifier__max_depth': [None, 6, 8, 10]}, pre_dispatch='2*n_jobs', refit=True, return_train_score=True, scoring=None, verbose=0)
- Voyons quel paramètre la recherche sur la grille a choisi:
print("Best parameters: {}".format(grid.best_params_))
Best parameters: {'randomforestclassifier__n_estimators': 30, 'randomforestclassifier__max_leaf_nodes': 20, 'randomforestclassifier__min_impurity_split': 0.2, 'randomforestclassifier__max_depth': 8}
print("Validation set score: {:.2f}".format(grid.score(X_test, y_test)))
Validation set score: 0.79
- Téléchargez la suite de tests:
test_df = pd.read_csv('../data/test.csv', encoding="utf-8-sig") test_df = test_df.head()
grid.predict(test_df)
array([1, 1, 1, 1, 1])
Notre pipeline semble assez bon pour passer à la prochaine étape importante: la sérialisation du modèle d'apprentissage automatique.
Enregistrement d'un modèle d'apprentissage automatique: sérialisation et désérialisation.«En informatique, dans le contexte du stockage de données, la sérialisation est le processus de traduction des structures de données ou des états d'objet dans un format stocké (par exemple, un fichier ou un tampon de mémoire) et plus tard de le reconstruire dans le même ou un autre environnement informatique.»
En Python, le décapage est le moyen standard de stocker des objets et de les récupérer plus tard dans leur état d'origine. Pour le rendre plus clair, je vais donner un exemple simple:
list_to_pickle = [1, 'here', 123, 'walker']
list_pickle
b'\x80\x03]q\x00(K\x01X\x04\x00\x00\x00hereq\x01K{X\x06\x00\x00\x00walkerq\x02e.'
Ensuite, nous déchargeons à nouveau l'objet en conserve:
loaded_pickle = pickle.loads(list_pickle)
loaded_pickle
[1, 'here', 123, 'walker']
Nous pouvons enregistrer des objets en conserve dans un fichier et les utiliser. Cette méthode est similaire à la création de fichiers
.rda
, comme dans la programmation R, par exemple.
Remarque: Certains peuvent ne pas aimer cette méthode de conservation pour la sérialisation. Une alternative pourrait être
h5py
.
Nous avons une classe personnalisée (Class) que nous devons importer pendant que la formation est en cours, nous allons donc utiliser le module
dill
pour emballer l'évaluateur de classe avec l'objet grille.
Il est conseillé de créer un fichier
training.py
séparé contenant tout le code pour l'apprentissage du modèle. (Un exemple peut être vu
ici ).
!pip install dill
Requirement already satisfied: dill in /home/pratos/miniconda3/envs/ordermanagement/lib/python3.5/site-packages
import dill as pickle filename = 'model_v1.pk'
with open('../flask_api/models/'+filename, 'wb') as file: pickle.dump(grid, file)
Le modèle sera enregistré dans le répertoire sélectionné ci-dessus. Une fois qu'un modèle est mis en veilleuse, il peut être emballé dans un emballage de flacon. Cependant, avant cela, vous devez vous assurer que le fichier en conserve fonctionne. Rechargons-le et faisons une prédiction:
with open('../flask_api/models/'+filename ,'rb') as f: loaded_model = pickle.load(f)
loaded_model.predict(test_df)
array([1, 1, 1, 1, 1])
Puisque nous avons suivi les étapes de prétraitement afin que les données nouvellement arrivées fassent partie du pipeline, nous avons juste besoin d'exécuter Predict (). En utilisant la bibliothèque scikit-learn, il est assez simple de travailler avec des pipelines. Les évaluateurs et les pipelines prennent soin de votre temps et de vos nerfs, même si la mise en œuvre initiale semble sauvage.
Création d'une API à l'aide de FlaskGardons la structure des dossiers aussi simple que possible:

La création d'un wrapper pour la fonction
apicall()
comprend trois parties importantes:
- Réception des données de
request
(pour lesquelles une prévision sera faite); - Chargement d'un évaluateur en conserve;
- Traduction de nos prévisions au format JSON et réception d'un
status code: 200
réponse status code: 200
;
Les messages HTTP sont créés à partir de l'en-tête et du corps. En général, le contenu du corps principal est transmis au format JSON. Nous enverrons (
POST url-endpoint/
) les données entrantes sous forme de package pour la réception des prévisions.
Remarque: Vous pouvez envoyer du texte brut, XML, cvs ou une image directement pour l'interchangeabilité du format, cependant il est préférable d'utiliser JSON dans notre cas.
"""Filename: server.py """ import os import pandas as pd from sklearn.externals import joblib from flask import Flask, jsonify, request app = Flask(__name__) @app.route('/predict', methods=['POST']) def apicall(): """API Call Pandas dataframe (sent as a payload) from API Call """ try: test_json = request.get_json() test = pd.read_json(test_json, orient='records')
Après l'exécution, entrez:
gunicorn --bind 0.0.0.0:8000 server:app
GĂ©nĂ©rons les donnĂ©es pour les prĂ©visions et la file d'attente pour le lancement local de l'API Ă
https:0.0.0.0:8000/predict
import json import requests
"""Setting the headers to send and accept json responses """ header = {'Content-Type': 'application/json', \ 'Accept': 'application/json'} """Reading test batch """ df = pd.read_csv('../data/test.csv', encoding="utf-8-sig") df = df.head() """Converting Pandas Dataframe to json """ data = df.to_json(orient='records')
data
'[{"Loan_ID":"LP001015","Gender":"Male","Married":"Yes","Dependents":"0","Education":"Graduate","Self_Employed":"No","ApplicantIncome":5720,"CoapplicantIncome":0,"LoanAmount":110.0,"Loan_Amount_Term":360.0,"Credit_History":1.0,"Property_Area":"Urban"},{"Loan_ID":"LP001022","Gender":"Male","Married":"Yes","Dependents":"1","Education":"Graduate","Self_Employed":"No","ApplicantIncome":3076,"CoapplicantIncome":1500,"LoanAmount":126.0,"Loan_Amount_Term":360.0,"Credit_History":1.0,"Property_Area":"Urban"},{"Loan_ID":"LP001031","Gender":"Male","Married":"Yes","Dependents":"2","Education":"Graduate","Self_Employed":"No","ApplicantIncome":5000,"CoapplicantIncome":1800,"LoanAmount":208.0,"Loan_Amount_Term":360.0,"Credit_History":1.0,"Property_Area":"Urban"},{"Loan_ID":"LP001035","Gender":"Male","Married":"Yes","Dependents":"2","Education":"Graduate","Self_Employed":"No","ApplicantIncome":2340,"CoapplicantIncome":2546,"LoanAmount":100.0,"Loan_Amount_Term":360.0,"Credit_History":null,"Property_Area":"Urban"},{"Loan_ID":"LP001051","Gender":"Male","Married":"No","Dependents":"0","Education":"Not Graduate","Self_Employed":"No","ApplicantIncome":3276,"CoapplicantIncome":0,"LoanAmount":78.0,"Loan_Amount_Term":360.0,"Credit_History":1.0,"Property_Area":"Urban"}]'
"""POST <url>/predict """ resp = requests.post("http://0.0.0.0:8000/predict", \ data = json.dumps(data),\ headers= header)
resp.status_code
200
"""The final response we get is as follows: """ resp.json()
{'predictions': '[{"0":"LP001015","1":1},{...
ConclusionDans cet article, nous n'avons fait que la moitié du chemin, créant une API fonctionnelle qui donne des prévisions, et nous sommes devenus un pas de plus vers l'intégration de solutions ML directement dans les applications développées. Nous avons créé une API assez simple qui aidera à prototyper le produit et à le rendre vraiment fonctionnel, mais pour l'envoyer en production, vous devez faire quelques ajustements qui ne sont plus dans le domaine du machine learning.
Il y a quelques points à garder à l'esprit lors de la création de l'API:
- La création d'une API de qualité à partir d'un code spaghetti est presque impossible, alors utilisez vos connaissances en apprentissage automatique pour créer une API utile et pratique.
- Essayez d'utiliser le contrôle de version pour les modèles et le code API. Gardez à l'esprit que Flask ne prend pas en charge les outils de contrôle de version. L'enregistrement et le suivi des modèles ML est une tâche difficile, trouvez un moyen qui vous convient. Il y a un article ici qui explique comment procéder.
- En raison des spécificités des modèles scikit-learn, vous devez vous assurer que l'évaluateur et le code de formation sont côte à côte (si vous utilisez un évaluateur personnalisé pour le prétraitement ou d'autres tâches similaires). Ainsi, le modèle en conserve aura un évaluateur de classe à côté de lui.
La prochaine étape logique consiste à créer des mécanismes pour déployer une telle API sur une petite machine virtuelle. Il existe différentes façons de procéder, mais nous les aborderons dans le prochain article.
Code et explication de cet articleSources utiles:[1]
Ne décapez pas vos données.[2]
Construction de transformateurs compatibles Scikit Learn .
[3]
Utilisation de jsonify dans Flask .
[4]
Flask-QuickStart.Voici un tel matériau. Abonnez-vous à nous si vous avez aimé la publication et inscrivez-vous à un
webinaire ouvert gratuit sur le sujet: «Algorithmes de classification métrique», qui sera organisé le 12 mars par le développeur et scientifique des données avec 5 ans d'expérience -
Alexander Nikitin .