Azure Machine Learning et Python: Apprentissage régulier et automatisé avec Scikit-learn

 

Bonjour,

Julien Moreau-Mathis nous propose aujourd'hui un deuxième article sur Python et Machine Learning.

Pour faire plus amples connaissances, Julien est étudiant à l’école IN’TECH INFO, une école d’informatique et est actuellement en alternance (Master) au sein de la Division DX (Developer Experience) de Microsoft France. A l’origine, Julien nous viens du monde de la 3D où il contribue au projet Babylon.js, à l’initiative de mes collègues David Catuhe (@deltakosh), David Rousset (@davrous), Pierre Lagarde (@pierlag) et Michel Rousseau (@rousseau_michel). Il a ainsi pu créer Community Play 3D, ce qui lui a donné l’occasion de rencontrer et de côtoyer d’autres personnes de DX. Il travaille ainsi aujourd’hui avec mon autre collègue Benjamin Guinebertière (@benjguin) sur le sujet du Machine Learning.

Un grand merci à Julien pour cette contribution ;-)

Je vous souhaite une bonne lecture de son billet.

:-) Benjamin

________________________________________

Introduction

Rappelez-vous, Azure Machine Learning permet d’exécuter des scripts Python et utilise le back-end Anaconda 2.1. Cet article montre comment prédire le prix d’un appartement en fonction d’une surface inconnue. Prédiction en utilisant Azure Machine Learning avec Python pour les deux phases, apprentissage et prédiction, en utilisant la librairie “scikit-learn” disponible dans le back-end Anaconda 2.1. De plus, comment rendre ces deux phases automatiques et utilisables en production seulement avec Python et Azure Machine Learning.

image

Azure Machine Learning

Azure Machine Learning, ou Azure ML , est un service Azurede Microsoftqui nous permet d’accéder au monde du Machine Learning. C’est un service basé sur le Cloud dans Azure qui permet la création de systèmes puissants et automatiques d’analyse prédictive avec des possibilités de déploiement rapide. Azure ML propose un studio en ligne (Machine Learning Studio) pour s’entraîner et expérimenter :)

Note : Quelques références
Rappels sur le Machine Learning Rappels sur Azure ML

image

Screenshot d’un modèle d’exemple dans le studio Azure ML

Le screenshot ci-dessus présente l’interface du studio avec un exemple fourni par défaut. Nous y trouvons un graphe dans lequel nous pouvons ajouter des éléments paramétrables et ainsi créer nos propres expérimentations ML.

Dans les éléments qui sont disponibles, il y en a un particulier qui attire notre attention. Il s’agit de l’élément “Execute Python Script” qui nous permet d’exécuter nos propres scripts Python pour ajouter une couche de personnalisation et tout ça dans le Cloud !

Note : Azure ML permet également d’exécuter des scripts R.

Plus d’informations sur les langages R et Python. Utilisation de R dans Azure ML.

Python et Machine Learning

Plusieurs librairies pour Machine Learning sont disponibles dans l’écosystème Python. On peut trouver PyBrain, MlPy mais aussi Scikit-learn.

Scikit-learnou Sklearn est très réputé surtout pour être simple, puissant et fait pour opérer avec les librairies NumPyet SciPytrès utilisées et connues de la communauté Python. De ce fait, il permet d’interagir avec “Matplotlib” qui est une librairie Python pour la visualisation de données ( plotting).

Azure ML & Python

Azure ML permet d’exécuter des scripts Python et met à disposition des librairies préalablement installées. Dans ces librairies on peut trouver :

Le but est de pouvoir pousser notre expérimentation ML en utilisant Sklearn et ainsi prédire nos résultats.

L’avantage d’utiliser Azure ML réside dans la puissance de calcul et la possibilité de déployer facilement et rapidement des Web Services. Ainsi, nous sommes capables de mettre rapidement à disposition des applications un modèle prédictif testable. Pour tester, nous disposons d’exemples en C#, R et même Python.

Cas d’étude

En reprenant l’exemple “immo ”du cours MVA disponible ici, le but est de le reproduire en utilisant Sklearn.

Dans ce cours MVA, nous cherchons à prédire un prix pour une surface d’appartement donnée. Nous distinguons la phase d’entraînement et la phase de prédiction. La phase d’entraînement se fait grâce aux outils déjà présents dans Azure ML et un fichier CSV contenant les données de référence (surface et prix).

Dans notre cas d’étude, les données sont écrites dans une base de données Azure SQL. Notre expérimentation doit se connecter à la base de données pour récupérer les données de référence, lancer la phase d’entraînement puis prédire un prix pour une surface donnée via un Web Service.

De plus, nous voulons que notre expérimentation d’entraînement puisse ré-apprendre avec de nouvelles données supplémentaires écrites dans la base de données et nous voulons pouvoir re-déclencher la phase d’entraînement grâce à un Web Service. Pour plus d’optimisation, nous voulons enregistrer les modèles de prédiction issus de la phase d’entraînement et n’utiliser que le meilleur modèle dans la phase de prédiction.

Où récupérer les données immo

Les données de référence sont disponibles sur le cours MVA sous forme de fichier CSV. De plus, je vous invite à suivre ce tutoriel.

Expérimentation d’entraînement

Ici, l’expérimentation d’entraînement est un Web Service et se décompose en plusieurs parties :

  • Lire les données depuis la base de données.
  • Exécuter un script Python avec Sklearn qui prend en entrée les données issues de la base de données.
  • Ecrire le modèle de prédiction et le coefficient d’estimation issus du script Python dans une autre table de la base de données.

Expérimentation de prédiction

L’expérimentation de prédiction est un Web Service aussi et se décompose de la façon suivante :

  • Lecture des données en sortie de l’expérimentation d’entraînement.
  • Exécuter un script Python avec Sklearn qui prend en entrée depuis le Web Service une surface donnée et qui va prédire son prix associé.

Création de l’expérimentation d’entraînement

Lire dans la base de données Azure SQL

Les données de référence sont écrites dans la table immo de la base de données.

Pour lire les données de la table immo dans la base de données, nous ajoutons un élément de la liste dans le graphe appelé Reader.

Le Reader permet de lire et transformer les données issues d’une base de données en un dataset par une simple requête SQL.

image

Ajout d’un reader

Après avoir rempli les informations de connexion et la requête SQL, nous pouvons tester la connexion et la requête en cliquant sur “Run”.

image

Pour visualiser le dataset en sortie, il nous suffit de faire un clic droit sur le connecteur puis “Visualize”.

Ajouter un script Python

Tout comme le Reader, il nous suffit de glisser/déposer un élément de la liste dans le graphe.

image

La fonction azureml_main est la fonction exécutée par Azure ML lors de l’exécution du script. Les arguments dataframe1 et dataframe2 de la fonction correspondent aux deux datasets en entrée du script (input1 et input2) et peuvent être vides.

dataframe1 et dataframe2 sont des instances DataFrame de pandas et nous pouvons y accéder comme un dictionnaire classique :

 surface = dataframe1 [ "surface "] 
prix = dataframe1 [ "prix "] 
 OU
 import pandas as pd
surface = pd.DataFrame ( dataframe1, columns= [ "surface" ]) 
prix = pd.DataFrame ( dataframe1, columns= [ "prix" ]) 
Entraînement avec Sklearn et régression linéaire

Les deux principes clés de Sklearn sont “fit” et “predict”.

  • “fit” permet d’ajuster la fonction de prédiction en prenant deux paramètres : les données de référence et les résultats associés. Ici les données de référence sont les surfaces et les résultats sont les prix.
  • predict” permet de prédire un résultat en prenant en entrée une donnée de référence non connue, donc une surface.
Fit avec Sklearn et immo

Il s’agit ici d’importer Sklearn et d’ajuster la fonction de prédiction avec surface en fonction de prix grâce un modèle de régression linéaire pour l’exemple.

 from sklearn import linear_model
lr = linear_model.LinearRegression () 
 import pandas as pd
surface = pd.DataFrame ( dataframe1, columns= [ "surface" ]) 
prix = pd.DataFrame ( dataframe1, columns= [ "prix" ]) 
  # Ajuster le modèle
lr.fit ( surface ,  prix ) 
  # print le résulat de la prédiction pour une surface de 100m2
print( lr.predict ( 100 )) 

Pour récupérer le coefficient estimé, autrement dit la précision de la prédiction, il nous suffit d’accéder à la propriété “coef_”. Cette valeur nous sert à déterminer le meilleur modèle issu de la phase d’entraînement.

 #Estimated coefficient, contenu dans [0, 1000]
coef = lr.coef_
Enregistrer le modèle en sortie du script

Dans notre expérimentation, nous voulons enregistrer en sortie du script le résultat de la phase d’adaptation. Pour cela, il suffit simplement de sérializer l’objet “lr” et d’écrire par la suite le résultat de la sérialization dans une nouvelle table immo_model dans la base de données Azure SQL.

  #dump de l’objet "lr" avec pickle
import pickle
result = pickle.dumps ( lr ) 
  #print le résultat du dump
print( result ) 
Définir le dataset en sortie du script Python

Pour envoyer un dataset en sortie d’un script Python, il s’agit d’utiliser pandas. La fonction azureml_main retourne un dataset de type pandas.DataFrame de la manière suivante :

 import pandas as pd
 ret = pd.DataFrame ([ result ],  columns= [ "result" ]) 
ret [ "coef" ]   =  pd.DataFrame ( lr.coef_, columns= [ "coef" ]) 
 return ret,

Pour visualiser le résultat en sortie du script, il nous suffit de faire un clic droit sur le connecteur et cliquer sur “Visualize”.

image

image

Script complet
 def azureml_main ( dataframe1 = None, dataframe2 = None): 
    from sklearn import linear_model
    import pandas as pd
    import pickle
     surface = pd.DataFrame ( dataframe1, columns= [ "surface" ]) 
    prix = pd.DataFrame ( dataframe1, columns= [ "prix" ]) 
     lr = linear_model.LinearRegression () 
    lr.fit ( surface ,  prix ) 
     result = pickle.dumps ( lr ) 
     ret = pd.DataFrame ([ result ],  columns= [ "result" ])     
ret [ "coef" ]  = pd.DataFrame ( lr.coef_, columns= [ "coef" ]) 
     return ret,
Ecrire la sortie dans la base de données Azure SQL

Dans l’expérimentation de prédiction, la méthode est de récupérer le résultat du dump de “lr” puis de le reconstruire pour récupérer l’intégralité de notre objet. Pour le récupérer il s’agit d’enregistrer le résultat dans la base de données, dans la table immo_model.

Pour écrire dans la base de données, il nous suffit de glisser/déposer un élément de type “Writer” et de remplir les informations liées à la connexion vers la base de données.

image

Création de l’expérimentation de prédiction

L’expérimentation de prédiction est sensiblement la même que celle d’entraînement.

image

Le Reader récupère la ligne qui a le meilleur coefficient estimé dans la table immo_model. Le script Python reconstruit l’objet “lr” grâce à Pickle, prend en entrée une surface inconnue (Enter Data) et inscrit le résultat de la prédiction en sortie (le prix prédit).

Le script Python aura en input1 la surface à prédire et en input2 le résultat le plus récent de la partie entraînement lu depuis la base de données. Pour définir la structure de données en input1, il s’agit de définir Enter Data comme étant au format CSV.

Note : Enter Data peut contenir une valeur (ici 25) qui sera utilisée pour les tests avec “Run”

image

Recharger l’objet “lr” et prédiction

Pour récupérer l’objet “lr” il s’agit de désérializer l’objet avec pickle.loads(string) .

 import pickle
lr = pickle.loads ( dataframe2 [ "lr "][ 0 ]) 

Une fois l’objet désérializé, on peut accéder à ses méthodes.

 import pandas as pd
  #Transforme la surface donnée en dataset
given_surface = pd.DataFrame ( dataframe1, columns= [ "surface "]) 
  #Prédire le prix en fonction de la surface donnée
prediction = lr.predict ( given_surface ) 

lr.predict renvoie un tableau de résultats et prend en entrée un tableau de données. Une fois la prédiction faite, il nous suffit de retourner le résultat en sortie du script.

 import pandas as pd
 ret = pd.DataFrame ( prediction, columns= [ "result" ]) 
return ret,
Script complet
 def azureml_main ( dataframe1 = None, dataframe2 = None): 
    import pickle
    import pandas as pd
     lr = pickle.loads ( dataframe2 [ "lr "][ 0 ]) 
     given_surface = pd.DataFrame ( dataframe1, columns= [ "surface "]) 
    prediction = lr.predict ( given_surface ) 
     ret = pd.DataFrame ( prediction, columns= [ "result" ]) 
    return ret,

Tester la prédiction avec un Web Service

Créer un Web Service ici permet à un client d’accéder à l’expérimentation de prédiction et prédire un prix en fournissant une surface inconnue.

Pour ajouter un Web Service à l’expérimentation, il s’agit d’ajouter les deux éléments “Input” et “Output” de la catégorie Web Service. Dans notre cas, l’Input est connectée à input1 sur le script Python et l’Output à la sortie du script Python. L’Input remplacera dans ce cas-ci l’élément Enter Data et l’Output renverra le dataset en sortie du script Python.

Note : L’élément Enter Data définit le format des données à fournir pour l’Input du Web Service. Il est donc nécessaire de le laisser dans l’expérimentation.

Une fois le couple Input/Output connecté, il nous suffit de cliquer sur “Publish Web Service”.

image

Une fois le Web Service créé, toutes les informations de connexion nous sont fournies. Pour tester le Web Service et prédire un prix, cliquer sur “Test”.

image

Le résultat suivant montre la prédiction pour 25 m2 qui est quasi égale à la valeur de référence dans la base de données.

image

Appel du Web Service côté client

Les appels du Web Service peuvent se faire via C# , R et Python. La documentation est accessible en cliquant sur le lien “REQUEST/RESPONSE”. La documentation fournit l’URL vers le Web Service et un exemple de code pour les trois langages.

image

Lien vers le script

image

Le processus suivit par le script Python est le suivant :

  • Définir le format JSON pour la requête (data)
  • Envoyer la requête en fournissant l’API Key et l’URL du Web Service
  • Récupérer la réponse et la désézialiser
  • Récupérer les informations sur la prédiction en parcourant l’objet JSON renvoyé par le Web Service.

Gestion du meilleur modèle de prédiction

Afin de récupérer le meilleur modèle de prédiction, nous choisissons arbitrairement de n’utiliser que le dernier modèle ayant un coefficient estimé supérieur ou égal à 0.8. Afin d’identifier facilement le dernier modèle utilisable dans la base de données, nous ajoutons un flag “flag_use” dans la table immo_model.

De ce fait, la requête SQL de l’élément Reader dans l’expérimentation d’entraînement

 SELECT TOP 1 lr
FROM immo_model as IM
ORDER BY IM.coef DESC

devient

 SELECT TOP 1 lr
FROM immo_model as IM
WHERE IM.flag_use = 1

Après cette modification, chaque modèle de prédiction ajouté dans la base de données doit être vérifié. C’est-à-dire :

  • Si le coefficient d’estimation >= 0.8, alors ajouter le modèle avec “flag_use = 1” et modifier les autres modèles avec “flag_use = 0”.
  • Si le coefficient d’estimation < 0.8, alors ajouter le modèle avec “flag_use = 0

Création du Web Service de la partie entraînement

Le processus de ré-apprentissage transforme l’expérimentation d’entraînement en un Web Service. On situe l’Input et l’Output au niveau du script Python.

image

Une fois la partie Web Service mise en place, l’élément Writer est grisé et ne sera jamais exécuté si le ré-apprentissage se fait par un appel au Web Service.

Note: Le Writer est exécuté si l’apprentissage est déclenché depuis le studio.

Pour re-déclencher l’apprentissage, il s’agit ici d’utiliser un script Python côté client qui récupère le dump de “lr” et qui écrit le résultat dans la base de données grâce à PyODBC.

Installer PyODBC et requêter la base de données Azure SQL
 pip install pyodbc

Pour se connecter à la base de données avec PyODBC, nous devons fournir une chaîne de connexion (connection string) qui est la suivante :

 connection  =  pyodbc . connect ( """DRIVER={SQL Server};
                             SERVER=server_adress;
                             DATABASE=database_name;
                             UID=username;
                             PWD=password """) 
Le processus

Le processus décrit trois étapes :

  • (1) déclencher l’expérimentation d’entraînement
  • (2) récupérer le dump de “lr” et son coefficient estimé qui lui est associé
  • (3) écrire le dump de “lr” (toujours sous forme d’une chaîne de caractères), le coefficient et le flag d’utilisation dans la base de données avec PyODBC

image

Ecriture avec PyODBC

Déroulement de l’écriture dans la base de données :

  • Connexion à la base de données (pyodbc.connect)
  • Création d’un curseur pour requêter la base de données (cursor)
  • Vérifier le coefficient d’estimation du nouveau modèle de prédiction. Si >= 0.8 alors modifier (UPDATE) tous les modèles existants avec “flag_use = 0
  • Exécution d’une requête INSERT INTO avec “lr”, “coef” et “flag_use” en paramètres
  • commit () pour informer le serveur de ne pas annuler les requêtes
 import pyodbc
 def write_to_database ( result ): 
    connection  =  pyodbc . connect (""" DRIVER={SQL Server};<br>                                 SERVER=server_adress;<br>                                 DATABASE=database_name;<br>                                 UID=username;<br>                                 PWD=password """)     
cursor = connection.cursor () 
     val =result [ "Results" ][ "learn_output" ][ "value" ][ "Values" ][ 0 ]     
lr = val [ 0 ]     
coef = float( val [ 1 ])     
flag_use = True if ( coef >= 0.8 ) else False
     if flag_use : 
        cursor.execute ( "UPDATE immo_model SET flag_use = 0;" ) 
     cursor.execute (" INSERT INTO immo_model VALUES(?, ?, ?);  "<br>                   ,  lr, coef, flag_use ) 
    cursor.commit () 
Définir l’expérimentation d’entraînement comme étant un Web Service

Pour transformer l’expérimentation d’entraînement en Web Service, l’astuce tient à définir l’Input comme étant vide et donc ajouter un élément “Enter Data” sans données particulières (cf. capture d’écran ci-dessous).

Le JSON du script Python côté client définira donc la colonne “None” mais avec une valeur nulle.

image

Le JSON devient le suivant :

 data =  { 
     "Inputs ": { 
         "learn_input ": { 
             "ColumnNames":  [ "None "], 
             "Values ": [ [   ""], ] 
         },<br>    }, 
     "GlobalParameters ": {<br>    } 
 } 
Script Python complet (lien vers le script)

Requête :

image

Ecriture dans la base de données :

imageS

Optimiser l’entraînement : créer un WebJob

L’utilisation des WebJobs dans Azure est très simple. Une fois notre Web App créée dans Azure, il suffit d’ajouter un package sous forme d’un fichier zip contenant notre fichier Python à exécuter dans la liste des WebJobs.

image

Créer un WebJob ici nous permet d’automatiser la phase d’apprentissage. Par exemple, si la base de données est constamment mise à jour, nous pouvons ajouter un WebJob qui sera exécuté toutes les heures afin d’améliorer le modèle de prédiction.

Note: Ajouter des librairies compilées ( .pyd ) au WebJob nécessite que ces librairies soient compilées dans leur version 32 bits.

PyODBC n’est pas disponible par défaut dans l’environnement présent sur Azure. C’est pourquoi nous devons ajouter le fichier “ pyodbc.pyd ” à la racine du dossier contenant notre script Python à exécuter. Lien vers la librairie PyODBC Python 3.4 version 32 bits .

Ajouter un WebJob qui s’exécutera de façon récurrente :

image

Configurer le WebJob afin qu’il s’exécute toutes les heures à partir de maintenant :

image

Conclusion

Nous avons vu dans cet article comment créer les deux phases, d’entraînement et de prédiction, en utilisant la librairie scikit-learn dans des script Pythons personnalisés.

De plus, ce cas d’étude montre un cas concret d’utilisation de Azure Machine Learning ne serait-ce que par la rapidité de développement et la mise en production rapide des Web Services.