Déployer un projet de Deep Learning en production avec Keras et Flask
Ce guide vous permettra de déployer un modèle de Machine Learning en partant de zéro.

Définir l’objectif/le but
Il est évident que vous devez savoir pourquoi vous avez besoin d’un modèle de Machine Learning (ML) en premier lieu. La connaissance de l’objectif vous donne des indications sur :
- Le ML est-il la bonne approche ?
- De quelles données ai-je besoin ?
- À quoi ressemble un “bon modèle” ? Quelles métriques puis-je utiliser ?
- Comment puis-je résoudre le problème maintenant ? Quelle est la précision de la solution ?
- Combien cela va-t-il coûter pour faire fonctionner ce modèle ?
Dans notre exemple, nous essayons de prédire le prix des annonces Airbnb par nuit à New York. Notre objectif est clair : étant donné certaines données, nous voulons que notre modèle prédise le coût de la location d’une propriété par nuit.
Chargement des données
Les données proviennent de Airbnb Open Data et sont hébergées sur Kaggle.
Installation
Téléchargez les données de Google Drive avec gdown :
!gdown --id 1aRXGcJlIkuC6uj1iLqzi9DQQS-3GPwM -- outputairbnb_nyc.csv
Et le charger dans un DataFrame Pandas :
df = pd.read_csv('airbnb_nyc.csv')
Exploration des données
Cette étape est essentielle. L’objectif est de mieux comprendre les données. Vous pourriez être tenté de vous lancer dans le processus de modélisation, mais ce serait sous-optimal. La recherche de modèles et la visualisation de distributions vous permettront de développer votre intuition sur les données. Cette intuition sera utile lors de la modélisation, Une façon simple de commencer est de compter le nombre de lignes et de colonnes dans votre ensemble de données.
Une façon simple de commencer est de compter le nombre de lignes et de colonnes dans votre ensemble de données.
df.shape
(48895, 16)
Nous avons 48 895 lignes et 16 colonnes. Assez de données pour faire quelque chose d’intéressant. Commençons par la variable que nous essayons de prédire (le prix). Pour tracer la distribution, nous allons utiliser distplot() :
sns.distplot(df.price)

Nous avons une distribution très asymétrique avec quelques valeurs dans la gamme des 10 000 . Nous allons utiliser une astuce : la transformation logarithmique.
sns.distplot(np.log1p(df.price))

Le type de chambre semble être un autre point intéressant. Jetons un coup d’œil :
sns.countplot(x='room_type', data=df)

La plupart des annonces proposent des lieux entiers ou des chambres privées.
Une autre caractéristique intéressante est le nombre d’avis. Jetons-y un coup d’oeil :
sns.distplot(df.number_of_reviews)

Trouver des corrélations
L’analyse de corrélation peut vous donner des indications sur les caractéristiques qui pourraient avoir un caractère prédictif lors de l’entraînement de votre modèle.
Le calcul du coefficient de corrélation de Pearson entre une paire de paramètres est facile :
corr_matrix = df.corr()
price_corr = corr_matrix['price']
price_corr.iloc[price_corr.abs().argsort()]
latitude 0.033939
minimum_nights 0.042799
number_of_reviews -0.047954
calculated_host_listings_count 0.057472
availability_365 0.081829
longitude -0.150019
price 1.000000
Le coefficient de corrélation est défini dans une intervalle de -1 à 1. Une valeur proche de 0 signifie qu’il n’y a pas de corrélation. Une valeur de 1 signifie une corrélation positive parfaite (par exemple, lorsque le prix du bitcoin augmente, vos rêves de posséder plus de bitcoins augmentent également). La valeur de -1 signifie une corrélation négative parfaite (par exemple, un nombre élevé de mauvaises critiques devrait correspondre à des prix plus bas).
Préparer les données
L’objectif ici est de transformer les données dans une forme qui convient à votre modèle. Il y a plusieurs choses que vous voulez faire lorsque vous manipulez des données structurées :
- Traiter les données manquantes
- Supprimer les colonnes inutiles
- Transformez les données catégorielles en nombres/vecteurs.
Données manquantes
Commençons par une vérification des données manquantes :
missing = df.isnull().sum()
missing[missing > 0].sort_values(ascending=False)reviews_per_month 10052
last_review 10052
host_name 21
name 16
Nous nous contenterons de supprimer ces paramètres pour cet exemple. Dans les applications du monde réel, vous devriez envisager d’autres approches.
Nous supprimons également neighbourhood, host id (trop de valeurs uniques) et l’identifiant de la liste.
Ensuite, nous divisons les données en éléments que nous allons utiliser pour la prédiction et une variable cible y (le prix) :
X = df.drop('price', axis=1)
y = np.log1p(df.price.values)
Notez que nous appliquons la transformation logarithmique au prix.
nous allons faire une normalisation min-max et mettre à l’échelle des données dans l’intervalle 0–1. Heureusement, le MinMaxScaler de scikit-learn fait exactement cela.
Ensuite, nous devons prétraiter les données catégorielles. Pourquoi ?
Certains algorithmes d’apprentissage automatique peuvent fonctionner sur des données catégorielles sans aucun prétraitement (comme les arbres de décision, Naive Bayes). Mais la plupart ne le peuvent pas.
Malheureusement, vous ne pouvez pas remplacer les noms de catégories par un nombre. Convertir Brooklyn en 1 et Manhattan en 2 suggère que Manhattan est plus grand (2 fois) que Brooklyn. Cela n’a pas de sens. Comment pouvons-nous résoudre ce problème ?
Nous pouvons utiliser l’encodage One-hot. Pour avoir une idée de ce qu’il fait, nous allons utiliser OneHotEncoder de scikit-learn :
from sklearn.preprocessing import OneHotEncoder
data = [['Manhattan'], ['Brooklyn']]
OneHotEncoder(sparse=False).fit_transform(data)
array([[0., 1.],
[1., 0.]])
Essentiellement, vous obtenez un vecteur pour chaque valeur qui contient 1 à l’indice de la catégorie et 0 pour toutes les autres valeurs. Ce codage résout le problème de la comparaison. L’inconvénient est que vos données risquent maintenant de prendre beaucoup plus de mémoire.
Toutes les étapes de prétraitement des données doivent être effectuées sur les données de training et les données que nous allons recevoir via l’API REST pour la prédiction. Nous pouvons unir les étapes en utilisant make_column_transformer() :
Enfin, nous allons transformer nos données :
transformer.transform(X)
La dernière étape consiste à séparer les données en ensembles de training et de test :
X_train, X_test, y_train, y_test =train_test_split(X, y, test_size=0.2, random_state=RANDOM_SEED)
Vous n’utiliserez que l’ensemble de training pour développer et évaluer votre modèle. L’ensemble de test sera utilisé plus tard.
Construisez votre modèle
Enfin, il est temps de faire de la modélisation. Rappelez-vous l’objectif que nous sommes fixé au début :
Nous essayons de prédire le prix des annonces Airbnb par nuit à New York.
Nous avons un problème de prédiction de prix. Plus généralement, nous essayons de prédire une valeur numérique définie dans un très large intervalle. Cela s’inscrit parfaitement dans le cadre de la régression.
Nous utiliserons l’erreur quadratique moyenne qui mesure la différence entre la moyenne quadratique des valeurs prédites et des valeurs réelles :

où n est le nombre d’échantillons,Y est un vecteur contenant les valeurs réelles,Yhat est un vecteur contenant les prédictions de notre modèle.
Construire un réseau neuronal avec Keras
Keras vous permet de construire des modèles complexes à l’aide d’une interface agréable. Construisons un modèle avec lui :
L’API séquentielle vous permet d’ajouter facilement plusieurs couches à votre modèle. Notez que nous spécifions l’input_size dans la première couche en utilisant les données d’entraînement. Nous effectuons également une régularisation en utilisant des couches de Dropout.
Comment spécifier la métrique d’erreur ?
La méthode compile() vous permet de spécifier l’optimiseur et la métrique d’erreur que vous devez réduire.
Le training d’un modèle Keras implique l’appel d’une seule méthode — fit() :
Nous utilisons la méthode de training avec les données et spécifions les paramètres suivants :
- shuffle — trier les données de façon aléatoire
- epochs-le nombre de cycles de training
- validation_split-utiliser un certain pourcentage des données pour mesurer l’erreur
- batch_size — le nombre d’exemples a entrainer qui sont donnés en même temps à notre modèle
Une fois le long processus de training terminé, vous devez répondre à une question. Votre modèle peut-il faire de bonnes prédictions ?
Évaluation
Une façon simple de comprendre le processus de training est d’examiner la loss de training et de validation :

Nous pouvons constater une grande amélioration de l’erreur de training, mais pas beaucoup sur l’erreur de validation. Que pouvons-nous utiliser d’autre pour tester notre modèle ?
Utilisation des données de test
Rappelez-vous que nous disposons de quelques données supplémentaires. Il est maintenant temps de les utiliser et de tester la qualité de notre modèle. Notez que nous n’utilisons pas ces données pendant le training, mais seulement une fois à la fin du processus.
Obtenons les prédictions du modèle :
y_pred = model.predict(X_test)
Et nous utiliserons un certain nombre de paramètres pour l’évaluation :
from sklearn.metrics import mean_squared_error
from math import sqrt
from sklearn.metrics import r2_score
print(f'MSE {mean_squared_error(y_test, y_pred)}')
print(f'RMSE {np.sqrt(mean_squared_error(y_test, y_pred))}')
MSE 0.2139184014903989
RMSE 0.4625131365598159
Nous avons déjà parlé de MSE. Vous pouvez probablement deviner ce que signifie RMSE. La RMSE nous permet de pénaliser les points les plus éloignés de la moyenne.
Sauvegarder le modèle
Maintenant que vous avez un modèle entraîné, vous devez le stocker pour pouvoir le réutiliser plus tard. Rappelez-vous que nous avons un transformateur de données qui doit également être stocké ! Sauvegardons les deux :
import joblib
joblib.dump(transformer, "data_transformer.joblib")
model.save("price_prediction_model.h5")
L’approche recommandée pour stocker les modèles scikit-learn est d’utiliser joblib. La sauvegarde de l’architecture du modèle et des poids d’un modèle Keras s’effectue avec la méthode save().
Construire une API REST
Construire une API REST vous permet d’utiliser votre modèle pour faire des prédictions pour différents clients.
Flask vous permet de construire une API REST en quelques lignes seulement. Bien sûr, nous parlons ici d’un prototype rapide. Jetons un coup d’oeil au code complet :
L’API a une seule route (index) qui accepte uniquement les requêtes POST. Notez que nous préchargeons le transformateur de données et le modèle.
Le contrôleur de requêtes obtient les données JSON et les convertit en un DataFrame Pandas. Ensuite, nous utilisons le transformateur pour prétraiter les données et obtenir une prédiction de notre modèle. Nous inversons l’opération de log que nous avons effectuée dans l’étape de prétraitement et renvoyons le prix prédit sous forme de JSON.
Votre API REST est prête à fonctionner. Exécutez la commande suivante dans le répertoire du projet :
flask run
Ouvrez un nouvel onglet pour tester l’API :
Vous devriez voir quelque chose comme ce qui suit :
{"price":"72.70381414559431"}
Super. Comment pouvez-vous déployer votre projet et permettre aux autres de se servir des prédictions de votre modèle ?
Déployer en production
Nous allons déployer le projet sur Google App Engine,App Engine nous permet d’utiliser Python et de déployer facilement une application Flask.
Voici la configuration complète du fichier app.yaml :
Exécutez la commande suivante pour déployer le projet :
gcloud app deploy
Attendez que le processus soit terminé et testez l’API en production. Vous avez réussi !
Conclusion
Votre modèle devrait maintenant fonctionner, faire des prédictions et être accessible à tous. Bien sûr, vous disposez d’un prototype rapide . Vous aurez besoin d’un moyen de protéger et de surveiller votre API. Vous avez peut-être aussi besoin d’une meilleure stratégie de déploiement (automatisée) !
Références