Commencez par lire la documentation et faites le lien avec le cours.
On utilisera MLPClassifier
dont la documentation est ici.
Après avoir chargé les bibliothèques utiles, on reprend l'exemple breast_cancer
, pour lequel on gardera 30\% des données pour former une base de test.
from sklearn import datasets, model_selection, neural_network, model_selection, preprocessing, neighbors, naive_bayes, linear_model
import numpy as np
import matplotlib.pyplot as plt
# pour ignorer les "warnings" concernant les modifications futures
# (pour régression logistique et perceptron)
from warnings import simplefilter
simplefilter(action='ignore', category=FutureWarning)
%matplotlib inline
dataset = datasets.load_breast_cancer()
X_dataset = dataset.data
y_dataset = dataset.target
X_train, X_test, y_train, y_test = model_selection.train_test_split(X_dataset,y_dataset,test_size=.7)
print(X_train)
print(y_train)
print(X_test)
print(y_test)
On constate que dans ce jeu de données, les attributs présentent une forte variabilité: certains fluctuent autour de $10$, d'autres autour de $10^{-2}$ par exemple. Ceci peut poser problème pour l'estimation des paramètres des algorithmes, et particulièrement pour ceux des réseaux de neurones. sklearn
dispose de fonctions standardisant les données
Par exemple:
X_train_n = preprocessing.StandardScaler().fit_transform(X_train)
X_test_n = preprocessing.StandardScaler().fit(X_train).transform(X_test)
estime moyenne et écart-type de chaque attribut sur l'ensemble d'apprentissage (X_train
), centre et réduit chaque attribut selon ces paramètres, puis crée X_train_n
et X_test_n
, les ensembles d'apprentissage et de test "normalisés". Ici, on normalise la base de test avec les paramètres estimés sur la base d'apprentissage, car la base de test n'est habituellement pas disponible au moment de l'apprentissage.
Normalisez les bases d'apprentissage et de test, et observez l'effet de la normalisation sur les valeurs des attributs.
# Votre code:
On considère un perceptron avec une couche cachée à 15 neurones.
On spécifie les paramètres de MLPClassifier
par:
MLP=neural_network.MLPClassifier(hidden_layer_sizes=(15,), alpha=0.0,solver='lbfgs')
où hidden_layer_sizes
est un tuple décrivant les couches cachées: par exemple (15,)
pour une couche cachée avec 15 neurones, ou (5,3)
pour deux couches cachées, la première avec 5 neurones et la seconde avec 3...
L'algorithme s'arrête lorsque le critère d'arrêt (gouverné par tol
) est satisfait ou si le nombre d'epochs dépasse max_iter
: on garde pour l'instant les valeurs par défaut.
On fixe le paramètre de régularisation alpha
à 0 (pas de régularisation), et on utilise le solver lbfgs
comme conseillé dans la documentation pour des jeux de données de taille limitée.
On peut changer la fonction d'activation en passant l'option activation=...
(relu par défaut).
Comparez l'évolution des loss, score de classification sur la base d'apprentissage, et score de classification sur la base de test en fonction du nombre d'epoch, sur la base d'origine et sur la base normalisée (voir exercice 1). Vous comparerez le comportement des activations relu
et tanh
.
Indications: il faudra utiliser l'option warm_start
qui permet d'interrompre l'apprentissage après une epoch (combiné avec max_iter=1
), puis de reprendre.
# Votre code:
Si les paramètres d'un réseau de neurones (les poids) sont "appris", les hyperparamètres doivent être fixés par l'utilisateur. Les hyperparamètres sont le nombre de neurones dans la couche cachée, le paramètre de régularisation alpha
, le nombre maximum d'itérations max_iter
(c'est bien un paramètre car il permet un early stopping évitant le surapprentissage), la fonction d'activation...
sklearn
permet de faire une grid search: une validation croisée (par défaut à 3 plis) est effectuée pour chaque classifieur correspondant à toutes les combinaisons de valeurs des hyperparamètres. Le jeu de paramètres fournissant le meilleur score est ensuite sélectionné. Attention, le temps de calcul est potentiellement long (quelques dizaines de secondes ici). C'est ce que réalise le code de la cellule suivante.
parameters = {'solver': ['lbfgs'], 'max_iter': [500,1000,1500], 'alpha': 10.0 ** -np.arange(1, 5), 'hidden_layer_sizes':np.arange(5, 15),'activation': ['relu','tanh']}
clf_grid = model_selection.GridSearchCV(neural_network.MLPClassifier(), parameters, n_jobs=-1)
%time clf_grid.fit(X_dataset,y_dataset)
print("Meileur score pour dataset: %0.4f" % clf_grid.best_score_)
print("Avec les paramètres:")
print(clf_grid.best_params_)
print()
%time clf_grid.fit(X_dataset_n,y_dataset)
print("Meileur score pour dataset normalisé: %0.4f" % clf_grid.best_score_)
print("Avec les paramètres:")
print(clf_grid.best_params_)
Attention, si cette approche semble correctement fondée pour fixer les valeurs de alpha
ou, dans une certaine mesure, max_iter
, ce n'est pas le cas pour fixer le nombre de neurones de la couche cachée (ou le nombre de couches cachées). Tracez le graphe représentant l'évolution du score de validation croisée en fonction du nombre de neurones de la couche cachée (prenez max_iter=1000
, activation='tanh'
, et alpha=0.1
). Quelle conclusion en tirer?
# Votre code:
Comparez les scores de validation croisée du perceptron multicouche (vous utiliserez les paramètres "optimaux" obtenus par GridSearch
) avec les classifieurs vus lors du TP précédent. Vous testerez le jeu de données original (dans son intégralité) et sa version normalisée.
# Votre code:
Pour la base de donnée MNIST
(voit TP 3 exercice 1), identifiez les paramètres "optimaux" des classifieurs vus jusqu'à présent, et comparez les scores de validation croisée (ou, pour gagner du temps, les scores sur une base de test indépendante de la base d'apprentissage). Confrontez à différentes architectures de perceptrons multicouches. Dans cet exemple, on peut se permettre une centaine de neurones dans la couche cachée. Vous testerez vos algorithme sur les bases originales et normalisées. Même question pour le jeu de données SAHeart
(si vous avez le temps). Que vous inspirent ces expériences sur les résultats pouvant être obtenus avec des perceptrons multicouches?