Thématiques principales

Affichage des articles dont le libellé est Support Vector Machine. Afficher tous les articles
Affichage des articles dont le libellé est Support Vector Machine. Afficher tous les articles

vendredi 12 avril 2019

IA : Régression non linéaire avec scikit-learn

Dans les derniers articles nous avons vu l’astuce du noyau. Maintenant, nous allons le mettre en pratique avec un problème de régression non linéaire avec l’outil scikit learn [1].

Nous allons faire comme dans la problématique linéaire [2] , nous allons produire des données non linéaire parfaites que nous allons bruiter. Ensuite nous tâcherons d’extraire un modèles pour ces deux jeux de données et nous visualisons graphiquement comment celui ci se comporte.
Les données

Ainsi commençons par construire des données. D’un côté on va se donner un plage de données avec un pas important (ça limitera la quantité de données lors de l’apprentissage). Ensuite sur la base de ce résultat, on va générer une valeur aléatoire que l’on ajoutera où on retranchera à nos précédents résultats:


print(__doc__)
import numpy as np
from sklearn.svm import SVR
import matplotlib.pyplot as plt
import math

A=0.02
B=-12
C=51
D=2*math.pow(10,8)


X=np.arange(-1000,1000,35)
SIZE=np.size(X)
print(SIZE)
Y=(A*X**3+B*X**2+C*X+D)*0.00000001
Bruit=Y + np.random.randint(0,15, size=(1,SIZE))[0]*0.005*(np.random.rand(1,SIZE)-0.5)[0]


fig = plt.figure(1,figsize=(8,8))
plt.plot(X,Y,"bo")# model lineaire
plt.plot(X,Bruit,"r.")# model lineaire bruité
plt.show()

Si l’on visualise ces données, on obtient le graphe suivant (au passage on calcule l'écart moyen au carré du résultat de la prédiction avec la vraie données initiale):


Modèles

Ensuite on construit un modèle polynomial basé sur un degré 3 (ok on triche un peu on sait que nos données sont de degré 3), au passage on se construira un modèle linéaire histoire de comparer un peu.


svr_lin = SVR(kernel='linear', C=100, gamma='scale')
svr_poly = SVR(kernel='poly', C=100, gamma='scale', degree=3, epsilon=.001, coef0=2)
X_=X.reshape(-1, 1)

On va alors d’abord vérifier sur nos données non bruités ce que nos modèles sont capable de faire:


svrs = [svr_lin,svr_poly]
model_color = ['c', 'g']

fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(16, 8), sharey=True)
for index, svr in enumerate(svrs):
    PREDICT=svr.fit(X_, Y).predict(X_)
    axes[index].plot(X_, PREDICT, color=model_color[index], lw=2)
    # on affiche les points supports du SVM
    axes[index].scatter(X_[svr.support_], Y[svr.support_], facecolor="none",edgecolor=model_color[index])
    # les autres points qui ne sont pas les supports (d'ou le diff)
    axes[index].scatter(X_[np.setdiff1d(np.arange(len(X)), svr.support_)],Y[np.setdiff1d(np.arange(len(X)),
        svr.support_)],facecolor="none", edgecolor="k")
    print("eccart carré moyen : {}".format(np.square(Y-PREDICT).mean()))

plt.show()

On obtient un eccart carré moyen : 6.847129083752741e-07



On voit donc que nos données sont correctement décrits mais en soit c’est normal! Mais essayons sur les données bruitées?



svrs = [ svr_lin,svr_poly]
model_color = ['c', 'g']

fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(16,8), sharey=True)
for index, svr in enumerate(svrs):
    PREDICT=svr.fit(X_, Bruit).predict(X_)
    axes[index].plot(X_, PREDICT, color=model_color[index], lw=2)
    # on affiche les points supports du SVM
    axes[index].scatter(X_[svr.support_], Bruit[svr.support_], facecolor="none",edgecolor=model_color[index])
    # les autres points qui ne sont pas les supports (d'ou le diff)
    axes[index].scatter(X_[np.setdiff1d(np.arange(len(X)), svr.support_)],Bruit[np.setdiff1d(np.arange(len(X)),
        svr.support_)],facecolor="none", edgecolor="k")
    print("eccart carré moyen : {}".format(np.square(Y-PREDICT).mean()))


plt.show()

On obtient eccart carré moyen : 3.2041407166403025e-06

Donc la on voit que malgré le bruit, on obtient une prédiction qui colle à ce qu'étaient nos données non bruité!

Sur-modèle

Alors on pourrait se dire que si l’on cherche à augmenter le degré on pourrait peut être espérer augmenter la qualité de notre modèle… sauf que ….


svrs = [ svr_lin,svr_poly]
model_color = ['c', 'g']

fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(16,8), sharey=True)
for index, svr in enumerate(svrs):
    PREDICT=svr.fit(X_, Bruit).predict(X_)
    axes[index].plot(X_, PREDICT, color=model_color[index], lw=2)
    # on affiche les points supports du SVM
    axes[index].scatter(X_[svr.support_], Bruit[svr.support_], facecolor="none",edgecolor=model_color[index])
    # les autres points qui ne sont pas les supports (d'ou le diff)
    axes[index].scatter(X_[np.setdiff1d(np.arange(len(X)), svr.support_)],Bruit[np.setdiff1d(np.arange(len(X)),
        svr.support_)],facecolor="none", edgecolor="k")
    print("eccart carré moyen : {}".format(np.square(Y-PREDICT).mean()))


plt.show()

On obtient eccart carré moyen : 0.002954915450864114


Ce que l’on constate ici est ce que l’on appelle de l’overfiting, c’est à dire un sur-apprentissage, cela arrive lorsque l’on pousse le modèle à vouloir trop coller au données. Au lieu d'être une bonne approximation de l’ensemble des données, le modèle devient  une surreprésentation de celles ci et sera incapable d’en prédire de nouvelles.

Conclusion

Pour conclure la-dessus je ferai surtout un point sur notre avancement dans l’IA. Ainsi on peut remarquer que la nous sommes sur la fin des régressions non linéaires (et les linéaires). Bien sur on ne dira pas que l’on en a fait le tour car il serait encore possible de traiter aussi des algo de type lasso, ridge, ou même elastic-net cependant dans le principe, ces approches restent proches de ce que l’on pu voir jusque maintenant (de plus la littérature sur ces modèles de régression est plus que riche et vous laisserai donc chercher).

De même nous avons vu des classifications binaires mais aussi des classifications multi-étiquettes (souvenez vous du dataset iris) et nous avons la aussi fait un peu le tour! Nous nous attacherons quand même à conclure sur une problématique classique du domaine qu’est Mnist car ce problème est tellement un classique qu’il ne serait pas normal de ne pas en parler.

Mais du coup ça y est on a fini avec l’IA? bien sur que non… il reste encore plein de sujet!

Rassurez vous!! c’est loin d'être fini! Sans vouloir trop entrer dans ces sujets ou spoiler, le machine learning compte encore d’autres approches comme les arbres de décisions ou les forêts aléatoire et bien sur, après cela, les réseaux de neurones (ça y est on y arrive!!).

Cependant, il faudra un peu de patience… car d’autres sujets surprises vont s’intercaler entre tout ça…. enfin vous verrez!

Références

vendredi 29 mars 2019

SVM : Formule dual

Cet article sera court car il n’entrera pas dans le détail de l’obtention de l'équation dual mais juste dans l’explication de comment y parvenir en partant de la fonction de décision (où le modèle de régression. L’idée n’est pas d’entrer trop dans les détails mathématiques que d’une part je ne maîtrise pas forcement mais d’intègrer cet article dans la continuité des sujet sur SVM et finalement aboutir aux modèles SVM non linéaire. Pour plus de détails la littérature sur le sujet est vaste, en dehors de ressources de type cours de math de master, vous trouverez les articles suivant qui m’ont permis de mieux appréhender cette problématique [1,2,3].

Pour rappel cette fonction solution à notre problème est [6]:
TODO Dans ce cadre, le but est de maximiser la marge qui dans le cas de la SVM est inversement proportionnel à la norme de W par deux
TODO Pour faire plus simple, alors on propose de plutôt minimiser directement la norme de W. Que l’on préférera choisir sous la forme de (½)W^^2
TODO

Formule primal

Ainsi, la SVM devient un problème d’optimisation quadratique avec contrainte dans laquelle, on cherche:
TODO sous la contrainte
TODO A noter que cette contrainte dépend du type de modèle : régression ou classification

Ce problème est alors ce que l’on appelle le problème primal.

Ce qu’il faut savoir est que la solution à ce “facile” à la condition que le nombre de données soit conséquent par rapport au nombre de variable (rang(X)). Par contre lorsque le nombre de données devient equivalent au nombre de variable voir est inferieur, cette solution n’est plus efficace et il faut alors se tourner vers la solution duale.

Formule dual

Cette solution duale qui est le propos de cet article s’obtient à l’aide du multiplicateur de agrange [4,5] qui nous permettre de la reformuler la solution primale sous la forme suivante.
TODO avec
TODO et
TODO A noter que ce dernier element étant associée à la contrainte de la formule primale, il faut l’ajuster selon le type de modèle : classification ou régression. On obtient donc:
TODO L’utilisation des conditions Kuhn-Tucker à cette étape vont alors nous permettre en calculant de gradient de L de nous fournir la formule duale (au coef prés du type de modèle) qu’il faudra maximiser selon le paramètre alpha.
TODO L’intéret de cette approche est de fournir à l’inverse de la solution primale une solution adapté au calcule des W dans le cas ou le nombre de données est faible face au nombre de variable. Pour plus d’informations afin d’approfondir, je vous invite à consulter la formation [1] qui explique le rôle de alpha qui selon sa valeur permet d’identifier le rôle des vecteurs du support à la marge du SVM.

Enfin dernier intérêt de la formule duale sur la formule primale, comme nous le verrons dans les articles suivant, est que celui ci fait intervenir un produit scalaire…. mais nous verrons cela plus tard.

Références

[1] https://openclassrooms.com/fr/courses/4444646-entrainez-un-modele-predictif-lineaire/4507841-maximisez-la-marge-de-separation-entre-vos-classes
[2] https://zestedesavoir.com/tutoriels/1760/un-peu-de-machine-learning-avec-les-svm/#5-systemes-non-lineaires--astuce-du-noyau
[3] https://fr.wikipedia.org/wiki/Machine_%C3%A0_vecteurs_de_support
[4] https://fr.wikipedia.org/wiki/Multiplicateur_de_Lagrange
[5] https://fr.wikipedia.org/wiki/Optimisation_quadratique
[6] https://medium.com/coinmonks/support-vector-regression-or-svr-8eb3acf6d0ff

lundi 10 décembre 2018

IA : Classification SVC avec SciKit-Learn

Introduction

Dans les article précédent, nous avion aborder la problématique de la classification [1,2] qui consiste à séparer des ensembles binaire ou multiple, pour cela, nous avions réalisé un neurone à la main avec une approche rationalisée autour de la constitution d’un jeu de donné d’apprentissage et d’un jeu de donnée d'évaluation.

Dans cet article, on va industrialiser une peu plus en nous appuyant sur un framework pour réaliser toute ces tâches : scikit learn [3]. Nous prendrons le cas classique de la classification des données du jeu Iris sur lequel nous appliquerons l’algorithme de classification SVC (Support Vector Classification)[4].

Avant cela, nous présenterons rapidement (car nous aurons d’autres occasion de l’utiliser) scikit learn et son utilisation, nous verrons le principe général de SVC puis nous traiterons concrètement la problématique de classification du jeu de données Iris.

Description Scikit learn

Scikit learn est un framework python dédié au machine learning. il implémente de façon exhaustive les algorithmes les plus commun du domaine (il suffit de télécharger la documentation pdf du framework pour se rendre compte de la quantité d'algorithme que regorge scikit learn).

On y trouvera donc autant des algorithmes à base d'apprentissage supervisé (K plus proche voisin, Régression linéaire/logistique, SVM, arbre de décisions, etc…), non supervisé (partitionnement, visualisation ou réduction de dimension, règle d’association) ou semi-supervisé (issu de la combinaison des deux précédentes approches)

À cela, scikit-learn va proposer des outils facilitateurs pour construire des processus de traitements incluant phases de traitements des données (visualisations, analyse, nettoyage, calibrage, découpage, transformation), de paramétrages (par quadrillage, recherche aléatoire ou avec des modèles), d’apprentissages (sous format batch c’est à dire en une fois, en ligne c’est à dire de façon progressive ou encore avec des stratégies d’optimisation comme la descente de gradient ordinaire ou stochastique, l’utilisation de mini-lots, d'arrêt précoce), d’évaluations et de mises en production tout cela sous la forme de pipeline.

Nous aurons l’occasion d’explorer l’ensemble des fonctionnalités de scikit learn, aujourd’hui intéressons nous aux SVM et entre autre à SVC.

Description SVC

SVC (ou Support Vector Classifier) est un algorithme de machine learning faisant parti de la famille des SVM (Support Vector Machine) [4].

En fait un SVM est un algorithme utilisant la composante vectorielle des éléments du jeu de données d’apprentissage afin d’en déterminer une orientation préférentielle. Ainsi selon que l’on se place dans un contexte de régression ou de classification, il va être possible de
  • soit définir une droite porté par cette orientation donnée par la composante vectorielle 
  • soit de construire une droite perpendiculaire à ce même vecteur (et placer à équidistance des ensembles à séparer)
Si vous avez pris le temps de lire l’article précédent sur la classification [1], l’exemple de la construction de la droite séparatrice des fruits est classiquement un SVM et entre une forme de SVC.

edit 1: pas tout a fait car le SVM va chercher a minimiser la distance avec les quelques éléments choisis des deux ensembles, ces elements etant les "vecteurs supports", dans le cas de l'article [1], tous les elements sont des vecteurs supports.

edit 2: le schema ci dessous a pour but d'illustrer le principe de la separation d'ensemble pas que ce soit celle ci qui est obtenu

L'iris dataset

Pour illustrer l’utilisation d’un SVM avec scikit learn, nous allons utiliser un jeu de donnée (dataset) classiquement employé pour justement illustrer les approches de classification. Ne faisons pas mentir les habitudes.


iris= pd.read_csv('iris.data.txt',sep=',') #https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data
print(iris.shape)
pandata = pd.DataFrame(np.array(iris),columns=['sepal_length',  'sepal_width',  'petal_length',  'petal_width', 'species'])
print(pandata[:5])
sns.pairplot(pandata,hue='species', size=2.5)


Ce jeu de donnée est accessible les archives en ligne [5]. Pour visualiser un peu les données comme nous l’avions fait dans le précédent article à l’aide de panda:

Comme on le voit sur le schéma, le jeu de donnée est constitué de différentes informations sur les iris comme la largeur et la longueur du pétale ainsi que la longueur du sepal (la sorte de petal mais verte et enfermant le bouton). Une dernière information permet enfin de déterminer le type de la fleur en fonction des informations données. 

Celle ci sont de trois types:
  • Iris-setosa
  • Iris-virginica
  • Iris-versicolor
Tentons maintenant avec scikit learn d'entraîner un modèle SVC nous permettant de déterminer le type de fleur à partir des informations précédentes.

Traitement avec scikit learn

Pour construire notre modèle il nous faut avant tout chose penser à constituer un jeu de donnée de test afin nous permettre de l'évaluer une fois l’apprentissage réalisé.

Ainsi nous allons scinder le jeu de donné. Le data set n’est pas énorme (150 échantillons), il faut donc faire un choix entre quantité lié à l’apprentissage et quantité dédié à la validation. À cet effet on prendra 125 échantillons pour l’apprentissage et les 25 derniers pour la validation.

A noter cependant que les données iris sont initialement trié, nous allons donc les mélanger d’abord avant de les scinder à laide d’un tableau de valeurs aléatoires pour constituer le jeux d’apprentissage et le jeu de validation.

perm=random.permutation(np.array(iris)[:,4].size)
irisRand=np.array(iris)[perm]
targetPerm,dataPerm=irisRand[:,4],irisRand[:,:4]
division=125
print("base:",targetPerm.size,dataPerm.shape)
targetLearn,targetTest=targetPerm[:division],targetPerm[division:]
print("target:",targetLearn.size,targetTest.size)
dataLearn,dataTest=dataPerm[:division,:],dataPerm[division:,:]
print("data:",dataLearn.size,dataTest.shape)

Maintenant, on va réaliser la partie peut être la plus facile, instancier un modèle et faire une phase d'apprentissage:

model=SVC()
model.fit(dataLearn,targetLearn)

On vérifie que celui-ci fonctionne:

print(model.predict(dataTest[:4]))
print(targetTest[:4])

Bon on voir que ca fonctionne mais on ne peut pas se limiter à ce genre d’evaluation pour mesurer l’efficacité de notre modèle. Dans nos précédents exemple, nous avions utilisé la matrice de confusion.

Matrice de confusion

Nous avons un modèle qui à appris, nous avons un jeu de test maintenant regardons comment Scikit learn nous facilite la vie pour l'évaluer.

Pour cela Scikit nous propose une api générique du package metrics: confusion_matrix.

Prenons l’exemple de jeu de test:

predicData=model.predict(dataTest)
confusion_matrix(targetTest,predicData)


array([[8, 0, 0],
       [0, 9, 1],
       [0, 0, 6]], dtype=int64)

Nous voyons que la matrice est diagonale, donc le modèle est dans l’absolu idéal! mais comme nous ne croyons pas aux licornes on peut légitimement se demander si cela n’est pas du à un jeu de test un peu trop petit. Essayons avec quelques jeux de test un peu plus important (mais du coup reduisant à l’inverse le jeu d’apprentissage et donc diminuant forcement la qualité du modele aussi…) avec les ratio suivant: 100/50, 75/75, 50/100:


array([[19,  0,  0],
       [ 0, 17,  1],
       [ 0,  0, 12]], dtype=int64)

array([[21,  0,  0],
       [ 0, 25,  1],
       [ 0,  3, 24]], dtype=int64)


array([[30,  0,  0],
       [ 0, 35,  3],
       [ 0,  0, 31]], dtype=int64)


À cela, on se rend compte que sensiblement le modèle se dégrade mais réagit plutôt bien (puisque à priori notre jeu de test est lui plus performant) Apres le choix de l’ajustement et de la balance des données reste un choix et un paramètre à prendre en compte mais il faut toujours avoir un moyen d’évaluation et d’en connaitre la pertinence et la limite

Conclusion

Bien sur il y à d’autre algo de classification et aussi bien sur d’autres outils mais ceux la sont les basiques, on en verra d’autres. Aujourd’hui nous avons vu le modèle SVC appliqué au jeu de données Iris en appliquant une approche mettant en avant la problématique de l’apprentissage face à la validation.

Notes: vous trouverez l’intégralité des exemples sur le depot github [6]

Référence

[1] https://un-est-tout-et-tout-est-un.blogspot.com/2018/07/ai-approche-neuromimetique-la.html
[2] http://un-est-tout-et-tout-est-un.blogspot.com/2018/07/ai-approche-neuromimetique.html
[3] http://scikit-learn.org/
[4] https://zestedesavoir.com/tutoriels/1760/un-peu-de-machine-learning-avec-les-svm/