Travaux pratiques - Algorithmes à noyaux¶
L’objectif de cette séance de travaux pratiques est de montrer l’utilisation des plusieurs algorithmes à noyaux en python (scikit-learn). Nous allons aborder dans cette séance les One Class SVM (OCSVM) et SVM pour la régression.
Références externes utiles :
One Class SVM (OCSVM)¶
Les OCSVM sont des estimateurs de support de densité pour des données multidimensionnelles. L’idée derrière l’implémentation est de trouver l’hyperplan le plus éloigné de l’origine qui sépare les données de l’origine.
LibSVM¶
LibSVM est une implémentation sous licence libre qui s’est imposée ces dernières années et qui est utilisée par de nombreux logiciels comme « moteur de classification » (par exemple scikit-learn). Les deux paramètres qui permettent une meilleure adaptation aux données d’apprentissage sont le paramètre nu de régularisation et le paramètre de l’échelle du noyau (gamma). Pour obtenir et compiler libSVM suivre ces pas :
cd ~ rm -rf tpalgos mkdir tpalgos cd tpalgos wget http://cedric.cnam.fr/~ferecatu/RCP209/libsvm-3.22.tar.gz tar xzvf libsvm-3.22.tar.gz cd libsvm-3.22/ make
Pour comprendre les différents algorithmes, noyaux disponibles dans cette bibliothèque et leurs paramètres lisez le document README dans le répertoire libsvm-3.22/.
Dans une première étape nous évaluons les performances de OCSVM sur la base de données MNIST en utilisant un noyau gaussien. Nous examinons seulement 1 classe : le chiffre 5.
# Récupérer la base de données cd ~ cd tpalgos mkdir databases cd databases # Rendre les binaires visibles dans le repertoire courant ln -s ../libsvm-3.22/svm-train . ln -s ../libsvm-3.22/svm-predict . ln -s ../libsvm-3.22/svm-scale . ln -s ../libsvm-3.22/README . wget wget http://cedric.cnam.fr/~ferecatu/RCP209/mnist.bz2 wget wget http://cedric.cnam.fr/~ferecatu/RCP209/mnist.t.bz2 bzip2 -d mnist.bz2 bzip2 -d mnist.t.bz2
OCSVM utilise les étiquettes de +1 pour les éléments de la classe (inliers) et -1 pour les outliers (hors classe). Nousemployons sed pour préparer les données avec les bonnes étiquettes (+1) :
cat mnist | grep '^5' | shuf -n 2000 | sed -r s/^5/1/g > 5 cat mnist.t | grep '^5' | shuf -n 1000 | sed -r s/^5/1/g > 5.t # Nombre échantillons apprentissage et test classe 5 wc -l 5 >>> 2000 wc -l 5.t >>> 892
Entrainer un modèle OC-SVM à noyau gaussien et paramètres par défaut :
./svm-train -s 2 5 5.model_default ./svm-predict 5.t 5.model_default 5.output_default >>> Accuracy = 0% (0/892) (classification)
Nous pouvons remarqueer que les paramètres par défaut ne sont pas très adéquats. Les valeurs des données représentent les intensités des pixels dans une image en niveaux de gris (entre 0 et 255). La valeur par défaut pour le paramètre gamma (regardez le fichier 5.model_default) est 0.00133511 (1/num_features), ce qui n’est pas très adapté. Nous essayons avec une valeur plus raisonnable :
./svm-train -s 2 -g 0.0000001 5 5.model_default ./svm-predict 5.t 5.model_default 5.output_default >> Accuracy = 47.1973% (421/892) (classification)
Ceci est plus proche du résultat attendu, car le paramètre nu par défaut a une valeur de 0.5 (50% de outliers). Une autre approche est de mettre les données à l’échelle entre 0 et 1 sur tous les attributs :
./svm-scale -l 0 5 > 5.scaled ./svm-scale -l 0 5.t > 5.t.scaled ./svm-train -s 2 5.scaled 5.model_scaled ./svm-predict 5.t.scaled 5.model_scaled 5.output_scaled >> Accuracy = 47.7578% (426/892) (classification)
Question :
Changez le paramètre nu à 0.1. Quelle est l’erreur de classement ? Expliquez.
Question :
Testez differents noyaux sur le même probleme.
SVM-toy¶
Dans la suite nous employons l’outil svm-toy qui permet de visualiser le classement pour des problèmes en deux dimensions.
cd ~/tpsvm/libsvm-3.22/svm-toy/gtk make ./svm-toyTravail à faire :
Pour un ensemble de données bidimensionnelles dans un carré utilisez le noyau gaussien et essayez plusieurs valeurs pour les parametres
nu(regularisation) etgamma(échelle du noyau : plusgammaest faible, plus le noyau est « large »). Essayez de vous former une intuition sur la connexion entre l’espacement entre les points d’apprentissage (leur densité locale), les bonnes valeurs pour les parametrès et la probabilité pour que les points soient classés comme des outliers. Experimentez avec d’autres formes de classes, qui contiennent eventuellement des détails visibles à plusieurs échelles.
Scikit-learn¶
Dans Scikit-learn, les One-Class SVM sont implémentés dans le module “sklearn.svm”. Nous utilisons un noyau gaussien pour faire la détection des outliers dans un échantillon de données en deux dimensions :
import numpy as np import pylab as pl from sklearn import svm xx, yy = np.meshgrid(np.linspace(-7, 7, 500), np.linspace(-7, 7, 500)) X = 0.3 * np.random.randn(100, 2) X = np.r_[X + 2, X - 2] # Ajouter 10 % de *outliers* (ce qui nous conduit à utiliser nu = 0.1) X = np.r_[X, np.random.uniform(low=-6, high=6, size=(20, 2))] # Construire le modèle clf = svm.OneClassSVM(nu=0.1, kernel="rbf", gamma=0.05) clf.fit(X) # Afficher les points et les vecteurs les plus proches du plan de séparation Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) y_pred = clf.predict(X) pl.set_cmap(pl.cm.Paired) pl.contourf(xx, yy, Z) pl.scatter(X[y_pred>0,0], X[y_pred>0,1], c='white', label='inliers') pl.scatter(X[y_pred<=0,0], X[y_pred<=0,1], c='black', label='outliers') pl.axis('tight') pl.legend() pl.show()Travail à faire :
Testez plusieurs valeurs pour le paramètre
gamma. Pour quelle valeur le résultat semble meilleur (moins de outliers incorrectement classés) ? En pratique on ne connait pas les outliers, l’utilité des OCSVM est de les détecter. Le paramètrenudoit aussi avoir une bonne valeur pour ne pas sous-estimer (ou sur-estimer) le support de la distribution.
SVM pour la régression¶
Dans le cas de la régression il faut apprendre un modèle qui doit prédire les valeurs d’une fonction à partir des valeurs des variables d’entrée. L’idée est de trouver la fonction la plus « lisse » qui passe par les (ou à proximité des) données d’apprentissage. Scikit-learn implémente le modèle SVR (epsilon-regression) dans le module Python sklearn.svm.SVR.
SVM-toy¶
Lancez l’utilitaire svm-toy avec un paramètre -s 4 (nu-SVR) et placez des points sur la surface en suivant le contour d’une sinusoïde. Ajouter quelques points de « bruit » un peu plus éloignés. Testez plusieurs valeurs pour le paramètre C. Pour quelle valeur la prédiction SVR semble ignorer le bruit ?
Scikit-learn¶
Dans cette partie nous présenterons la régression dans le cas unidimensionnel en comparant plusieurs noyaux avec Scikit-learn. Le module sklearn.svm.SVR permet de faire varier tous les paramètres.
Il faut d’abord importer les modules :
import numpy as np from sklearn.svm import SVR import matplotlib.pyplot as plt
Ensuite, générer les données :
X = np.sort(5 * np.random.rand(40, 1), axis=0) y = np.sin(X).ravel()
Ajouter du bruit :
y[::5] += 3 * (0.5 - np.random.rand(8))
Apprendre avec les trois noyaux :
svr_rbf = SVR(kernel='rbf', C=1e3, gamma=0.1) svr_lin = SVR(kernel='linear', C=1e3) svr_poly = SVR(kernel='poly', C=1e3, degree=2) y_rbf = svr_rbf.fit(X, y).predict(X) y_lin = svr_lin.fit(X, y).predict(X) y_poly = svr_poly.fit(X, y).predict(X)
Afficher les résultats :
lw = 2
plt.scatter(X, y, color='darkorange', label='data')
plt.plot(X, y_rbf, color='navy', lw=lw, label='RBF model')
plt.plot(X, y_lin, color='c', lw=lw, label='Linear model')
plt.plot(X, y_poly, color='cornflowerblue', lw=lw, label='Polynomial model')
plt.xlabel('data')
plt.ylabel('target')
plt.title('Support Vector Regression')
plt.legend()
plt.show()
Question :
Pourquoi employer une valeur aussi grande pour le parametre \(C\) (1e3) ?