.. _chap-tpSVMLineaires: ################################# Travaux pratiques - SVM Lineaires ################################# L'objectif de cette séance de travaux pratiques est de montrer l'utilisation des machines à vecteurs de support (en anglais : Support Vector Machines ou SVM) pour les problèmes de classification linéaires en python (sklearn). Références externes utiles : * `Documentation NumPy `_ * `Documentation SciPy `_ * `Documentation MatPlotLib `_ * `Site scikit-learn `_ * `Site langage python `_ * `Site LibSVM `_ * `Site LibLinear `_ Machines à vecteurs de support linéaires **************************************** Les machines à vecteurs de support (SVM : Support Vector Machines) est une classe des méthodes d'apprentissage statistique basés sur le principe de la maximisation de la marge (séparation des classes). Il existe plusieurs formulations (linéaires, versions à noyaux) qui peuvent s'appliquer sur des données séparable (linéairement) mais aussi sur de données non séparables. Les avantages des SVM : * Très efficace en dimension élevée * Ils sont aussi efficace dans le cas ou la dimension de l'espace est plus grande que le nombre d'échantillons d'apprentissage * N'utilisent pas tous les échantillons d'apprentissage, mais seulement une partie (les vecteurs de support). En conséquence, ces algorithmes demandent moins de mémoire. Désavantages : * Si le nombre d'attributs est beaucoup plus grand que le nombre d'échantillons, les performances seront moin bonnes * Comme il s'agit de méthodes de discrimination entre les classes, elles ne fournissent pas des estimations de probabilités LibLinear et libSVM ******************* Dans cette partie nous allons tester `LibLinear `_, une implémentation libre de la formulation SVC sur un problème de classification. Ouvrez un terminal ligne de commande et créez un répertoire 'tpsvm' : .. code-block:: bash cd ~ mkdir tpsvm cd tpsvm Commençons par récupérer et compiler le code de la bibliothèque. .. code-block:: bash wget http://www.csie.ntu.edu.tw/~cjlin/liblinear/liblinear-2.1.tar.gz tar xzvf liblinear-2.1.tar.gz cd liblinear-2.1/ make Nous allons utiliser la base de chiffres en en écriture manuscrite MNIST : 10 classes, 60000 échantillons d'apprentissage, 10000 échantillon de test, 784 attributs. .. code-block:: bash mkdir databases cd databases wget https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass/mnist.bz2 wget https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass/mnist.t.bz2 bzip2 -d mnist.bz2 bzip2 -d mnist.t.bz2 Entrainer un modèle SVMC linéaire avec les paramètres par défaut : .. code-block:: bash time ../train mnist >>> real 2m22.716s time ../predict mnist.t mnist.model mnist.t.output >>> Accuracy = 80.26% (8026/10000) >>> real 0m0.283s .. admonition:: Question : SVM est par sa conception un classifieur binaire. Comment LibLinear gere la classification multiclasse (10 classes sur la base MNIST) ? LibSVM ------ On peut obtenir la même type de classification (linéaire) en utilisant `LibSVM `_ et un noyaux linéaire. .. code-block:: bash cd ~ cd tpsvm wget http://www.csie.ntu.edu.tw/~cjlin/libsvm/libsvm-3.22.tar.gz tar xzvf libsvm-3.22.tar.gz cd libsvm-3.22/ make ln -s ~/tpsvm/liblinear-2.1/databases . # Prendre 30000 échantillons aléatoires shuf -n 20000 databases/mnist > mnist30000 time ./svm-train -t 0 mnist30000 >>> real 3m10.783s time ./svm-predict databases/mnist.t mnist30000.model mnist.t.output >>> Accuracy = 90.86% (9086/10000) (classification) >>> real 0m33.433s Avec seulement 30000 échantillons sur la base d'apprentissage la construction du modèle prends plus de temps que LibLinear avec tous les échantillons. Par contre les performances sont un peu meilleures sur ce jeux de données. L'intérêt de LibLinear est donc la vitesse, ce qui permet de l'appliquer sur des gros jeux de données, mais bien sûr sa limitation est qu'on peut l'appliquer seulement pour des problèmes linéaires. La différence entre les deux vient du fait que LibLinear minimise une fonction de perte quadratique alors que LibSVM minimise la perte non non-quadratique, ce qui sur cette base semble mieux fonctionner, mais ce n'est pas la règle. .. admonition:: Question : Expliquez le paramètre '-t 0'. (Regardez la documentation). SVM-toy ------- Par la suite on va explorer l'outil 'svm-toy' qui permet de visualiser la classification pour des problèmes en deux dimensions. .. code-block:: bash cd ~/tpsvm/libsvm-3.22/svm-toy/qt make ./svm-toy Si la version Qt ne compile pas, essayez la version 'svm-toy/gtk' ou la version java 'libsvm-3.22/java'. Cliquez sur la surface d'affichage pour ajouter des points d'apprentissage. Changez de couleur pour ajouter une nouvelle classe (l'outil gère aussi la classification multi-classe). Utilisez l'option '-t 0' pour sélectionner la classification linéaire. Pour changer le paramètre à C=valeur utilisez l'option '-c valeur' (par exemple : -c 2.5). Testez plusieurs valeurs pour le paramètre C pour voir son comportement de régularisation pour les fichier suivants : `01.dat `_, `02.dat `_, `03.dat `_. Scikit-learn ************ Dans Scikit-learn, les SVM sont implémentées dans le module 'sklearn.svm'. Dans cette partie nous allons nous intéresser à la version linéaire (scikit-learn utilise les bibliothèques LibLinear et LibSVM déjà discutées). Nous allons utiliser le jeu de donnée 'iris' déjà rencontré dans les séances précédentes. Pour pouvoir afficher les résultats, on va utiliser seulement les premiers deux attributs (longueur et largeur des sépales). Les modèles linéaires LinearSVC() et SVC(kernel='linear'), comme nous l'avons déjà dit, produisent des résultats légèrement différents a cause du fait qu'ils optimisent des fonctions de couts différents mais aussi a cause du fait qu'ils gèrent les problèmes multi-classe de manière différente (LinearSVC utilise One-vs-All et SVC utilise One-vs_One). .. code-block:: python import numpy as np import matplotlib.pyplot as plt from sklearn import svm, datasets # Chargement des données iris = datasets.load_iris() # Garder juste les premiers deux attributs X = iris.data[:, :2] y = iris.target # Pour afficher la surface de décision on va discrétiser l'espace avec un pas h h = .02 C = 1.0 # paramètre de régularisation svc = svm.SVC(kernel='linear', C=C).fit(X, y) lin_svc = svm.LinearSVC(C=C).fit(X, y) # créer la surface de décision discretisée x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h)) titles = ['SVC with linear kernel', 'LinearSVC (linear kernel)'] for i, clf in enumerate((svc, lin_svc)): plt.subplot(1, 2, i + 1) plt.subplots_adjust(wspace=0.4, hspace=0.4) Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) # Utiliser une palette de couleurs Z = Z.reshape(xx.shape) plt.contourf(xx, yy, Z, cmap=plt.cm.coolwarm, alpha=0.8) # Afficher aussi les points d'apprentissage plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.coolwarm) plt.xlabel('Sepal length') plt.ylabel('Sepal width') plt.xlim(xx.min(), xx.max()) plt.ylim(yy.min(), yy.max()) plt.xticks(()) plt.yticks(()) plt.title(titles[i]) plt.show() .. admonition:: Question : Testez differentes valeurs pour le paramètre C. .. admonition:: Question : Utilisez les données 'mnist' pour construire un classifieur LinearSVC et testez-le sur les données 'mnist.t'. Si le temps d'apprentissage est trop long, sélectionnez une partie plus petite de la base d'apprentissage (par exemple 10000 échantillons). Pour quelle valeur de C on obtient le meilleurs résultats sur la base de test 'mnist.t' ?