Qu’est-ce que l’Auto-ML ?
L’AutoML (ou Machine Learning Automatisé) consiste à automatiser le processus d’apprentissage inhérent à toute solution de Machine Learning. L’AutoML va donc gérer et produire (en arrière boutique et sans intervention d’un data scientiste) le pipeline complet de modélisation de l’ensemble de données brutes jusqu’au modèle abouti déployable. Cette approche est proposée comme une solution elle-même d’intelligence artificielle qui permet de simplifier et accélérer cette phase de modélisation. C’est du moins sa promesse ! voyons ce que cela donne …
L’idée est donc de permettre aux non-experts de concevoir et utiliser des modèles et des techniques d’apprentissage automatique sans avoir à devenir au préalable un expert dans ce domaine.
La réalité est toute autre car si ces solutions d’AutoML ne fonctionne pas trop mal (nous allons le voir ici avec AutoGluon), dans la réalité la patte de l’artiste (le data scientiste) reste indispensable notamment pour ajuster les données et les affiner.
Néanmoins – et à l’heure actuelle – ces solutions ont au moins pour vertu de démocratiser le machine Learning en le rendant plus accessible. Ne négligeons donc pas son apport pédagogique, et puis nous en sommes au début et il parait évident que ce type de solution se profilent comme l’avenir dans ce domaine.
AutoGluon
Pour s’initier à l’AutoML nous allons utiliser AutoGluon.
AutoGluon est une librairie Open-Source publiée par Amazon. Il est vrai que j’aurai pu commencer plus simple en utilisant un outil plus graphique tel que Dataiku (qui fera certainement l’objet d’un article ultérieur) … mais je voulais garder la comparaison possible par rapport au travail Python/scikit-learn effectué précédemment (Cf. articles).
En allant sur le site d’AutoGluon on comprend très vite son utilité :
- Rapide prototypage de Modèles de ML en quelques lignes
- Ajustement automatique des hyperparamètres, de la sélection de modèle / recherche d’architecture et du traitement des données.
- Utilisation automatique des techniques de Deep Learning.
- Amélioration des modèles et des pipelines de données existants
En plus AutoGuon est personnalisable … alors pourquoi s’en priver ?
Tout d’abord, installons les librairies Python d’AutoGluon (avec PIP et sans GPU):
pip install --upgrade mxnet
pip install autogluon
AutoGluon vs Titanic
Puis déclarerons les librairies :
import autogluon as ag
import pandas as pd
from autogluon import TabularPrediction as task
Maintenant, récupérons le dataset du titanic (Kaggle) :
train_data = task.Dataset(file_path="../datasources/titanic/train.csv")
print(train_data.head())
Loaded data from: ../datasources/titanic/train.csv | Columns = 12 / 12 | Rows = 891 -> 891
PassengerId Survived Pclass \
0 1 0 3
1 2 1 1
2 3 1 3
3 4 1 1
4 5 0 3
Name Sex Age SibSp \
0 Braund, Mr. Owen Harris male 22.0 1
1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1
2 Heikkinen, Miss. Laina female 26.0 0
3 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1
4 Allen, Mr. William Henry male 35.0 0
Parch Ticket Fare Cabin Embarked
0 0 A/5 21171 7.2500 NaN S
1 0 PC 17599 71.2833 C85 C
2 0 STON/O2. 3101282 7.9250 NaN S
3 0 113803 53.1000 C123 S
4 0 373450 8.0500 NaN S
Regardons de plus près le dataset:
print("Détail sur la colonne survivant: \n", train_data['Survived'].describe())
Détail sur la colonne survivant:
count 891.000000
mean 0.383838
std 0.486592
min 0.000000
25% 0.000000
50% 0.000000
75% 1.000000
max 1.000000
Name: Survived, dtype: float64
Maintenant créons et entraînons directement le modèle sur les données brutes. On voit ici l’intérêt de l’AutoML. Pas besoin de:
- Segmenter le jeu de données
- Préparer les données
- Choisir un modèle de Machine Learning
- … et encore moins besoin d’affiner les hyper-paramètres!
dir = 'models'
label_col = 'Survived'
predictor = task.fit(train_data=train_data, label=label_col, output_directory=dir)
Quand on lance la commande précédente, AutoGluon se met en effet au travail … les lignes défilent alors comme ci-dessous et on peut voir les étapes de travail que l’on effectuait manuellement s’opérer mais cette fois ci de manière automatique !
Beginning AutoGluon training ...
AutoGluon will save models to models/
Train Data Rows: 891
Train Data Columns: 12
Preprocessing data ...
Here are the first 10 unique label values in your data: [0 1]
AutoGluon infers your prediction problem is: binary (because only two unique label-values observed)
If this is wrong, please specify `problem_type` argument in fit() instead (You may specify problem_type as one of: ['binary', 'multiclass', 'regression'])
Selected class <--> label mapping: class 1 = 1, class 0 = 0
Feature Generator processed 891 data points with 33 features
Original Features:
int features: 4
object features: 5
float features: 2
Generated Features:
int features: 22
All Features:
int features: 26
object features: 5
float features: 2
Data preprocessing and feature engineering runtime = 0.34s ...
AutoGluon will gauge predictive performance using evaluation metric: accuracy
To change this, specify the eval_metric argument of fit()
AutoGluon will early stop models using evaluation metric: accuracy
/opt/anaconda3/lib/python3.7/imp.py:342: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3,and in 3.9 it will stop working
return _load(spec)
Fitting model: RandomForestClassifierGini ...
0.8268 = Validation accuracy score
0.81s = Training runtime
0.12s = Validation runtime
...
Fitting model: weighted_ensemble_k0_l1 ...
0.8547 = Validation accuracy score
0.39s = Training runtime
0.0s = Validation runtime
AutoGluon training complete, total runtime = 13.3s ...
Mais, que s’est-il passé lors de l’entrainement (avec fit()) ?
Rappelons que l’on est dans un problème de classification binaire (survivant ou pas). AutoGluon déduit alors automatiquement que la mesure de performance appropriée est la précision. Il analyse le dataset et déduit ensuitele type de chaque entité (c’est-à-dire quelles colonnes contiennent des nombres continus par rapport à aux catégories discrètes). En plus, AutoGluon a géré des problèmes de données manquantes et la mise à l’échelle des valeurs des fonctionnalités. Voilà qui simplifie la vie n’est-ce pas ?
Dans l’exemple ci-dessus, nous n’avons pas spécifié de données de validation distinctes. AutoGluon choisit donc automatiquement un découpage aléatoire des données pour l’entrainement. Les données utilisées pour la validation sont automatiquement séparées des données d’apprentissage et sont utilisées pour déterminer les modèles et les valeurs d’hyper-paramètre qui produisent les meilleurs résultats. Et oui ! l’idée de fond est ne pas utiliser qu’un seul algorithme/modèle ! AutoGluon teste donc plusieurs modèles et les assemble pour garantir des performances prédictives optimales.
La solution va donc essayer différents types de modèles de manière itérative (dont des modèles de deep learning) et choisir le meilleur tout en ajustant les hyper-paramètres les mieux adaptés à) chacun.
Regardons maintenant les prédictions de ce modèle :
predictor = task.load(dir) # Nécéssaire seulement si le modèle n'avait pas été chargé au préalable
y_train = train_data[label_col]
x_train_data = train_data.drop(labels=[label_col],axis=1)
y_train_pred = predictor.predict(x_train_data)
print("Predictions: ", y_train_pred)
Predictions: [0 1 1 1 0 0 0 0 1 1 1 1 0 ...
0 0 1 0 1 1 1 1 0 0 0 1 0 0 1 1 0 0 1 0 1 0 0 1 1 0 0 0 1 1 0 0 0 0 0 0 1
0 1 0]
Et sa performance dans tout ça ? facile, utilisons la méthode evaluate_predictions()
perf = predictor.evaluate_predictions(y_true=y_train, y_pred=y_train_pred, auxiliary_metrics=True)
Evaluation: accuracy on test data: 0.961841
Evaluations on test data:
{
"accuracy": 0.9618406285072951,
"accuracy_score": 0.9618406285072951,
"balanced_accuracy_score": 0.954702329594478,
"matthews_corrcoef": 0.919374313148082,
"f1_score": 0.9618406285072951
}
Detailed (per-class) classification report:
{
"0": {
"precision": 0.9541446208112875,
"recall": 0.9854280510018215,
"f1-score": 0.9695340501792115,
"support": 549
},
"1": {
"precision": 0.9753086419753086,
"recall": 0.9239766081871345,
"f1-score": 0.9489489489489489,
"support": 342
},
"accuracy": 0.9618406285072951,
"macro avg": {
"precision": 0.9647266313932981,
"recall": 0.954702329594478,
"f1-score": 0.9592414995640801,
"support": 891
},
"weighted avg": {
"precision": 0.9622681844904067,
"recall": 0.9618406285072951,
"f1-score": 0.9616326981918379,
"support": 891
}
}
Nous avons une performance de 96% sur les données d’entraînement, c’est pas mal mais ça ne veut pas dire grand chose. Pour voir si notre modèle est performant nous allons bien sur le confronter au jeu de test Kaggle et soumettre le résultat de la prédiction afin de voir notre score.
Soumettons notre modèle à Kaggle
Nous allons pour cela récupérer le jeu de test sur le site Kaggle et utiliser la prédiction de notre modèle :
test_data = task.Dataset(file_path='../datasources/titanic/test.csv')
print(test_data.head())
predictor = task.load(dir) # Nécéssaire seulement si le modèle n'avait pas été chargé au préalable
y_pred = predictor.predict(test_data)
print("Predictions: ", y_pred)
Predictions: [0 1 0 0 1 0 1 0 1 0 0 0 1 0 1 1 0 0 0 1 0 1 1 1 1 0 1 0 0 0 0 0 1 1 1 0 1
1 0 1 0 0 0 1 1 0 0 0 1 1 0 0 1 1 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 1 1 0 0 0
1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 1 1 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 0 0 0 0 0
1 1 1 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 0
0 0 1 0 0 1 0 0 1 1 0 1 1 1 1 0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 1 1 0 1 1 0 1
0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 1 1 1 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 1 0 1 0
1 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 1 1 1 1 1 0 0 0 1 0 1 1 1 0 0 0 0 0 0 0 1
0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 1 1 1 1 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 1 1 0 0 1 0 0
1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 1 0 1 0 0 0 0 1 1 0 1 0 0 0 1 0
0 1 0 0 1 1 1 0 0 0 0 0 1 1 0 1 0 0 0 0 0 1 1 0 1 1 0 1 0 0 1 0 1 0 0 0 0
0 1 1 1 1 0 0 1 0 0 0]
Maintenant formatons les données prédisent pour que Kaggle puisse étudier notre résultat :
final = pd.DataFrame()
for i in range(len(test_data)):
row = {'PassengerId' : str(test_data['PassengerId'][i]) , 'Survived' : str(y_pred[i])}
final = final.append(row , ignore_index=True)
final.to_csv("result.csv", columns=["PassengerId", "Survived"], index=False)
… Suspence !!!
Ouch ! après soumission sur kaggle on obtient un score de 0.55980 …
Conclusion
C’est pas terrible quand même (56%) mais cela prouve une chose: ces outils (AutoML) ne sont pas magique. C’est vrai, j’aurais pu personnaliser le comportement d’AutoGluon pour gagner en précision, mais alors quid du coté Automatique qui est en quelque sorte la raison d’être de l’AutoML ? Au delà de ce résultat qui peut paraître décevant, je trouve que ce type d’outil possède à minima deux vertus. La première est pédagogique bien sur. la seconde est de permettre un prototypage rapide.
Pour moi cela prouve aussi – et encore une fois – que la connaissance des données (et donc par corollaire sa préparation) est une étape cruciale dans tout projet de Machine Learning. Alors, Data Scientistes, rassurez-vous ! votre boulot n’est pas – encore – en danger. Par contre, il vont certainement révolutionner la manière de modéliser avec une approche moins technique. En effet, il est intéressant de constater comme ces outils masquent de plus en plus les aspects techniques au profit d’une meilleure connaissance métier.