Thématiques principales

Affichage des articles dont le libellé est loi de commande. Afficher tous les articles
Affichage des articles dont le libellé est loi de commande. Afficher tous les articles

mardi 17 juillet 2018

IA : Neuromimétique : classification sigmoide

Nous avons traité dans un article précédent de la classification de fruits (ananas et pastèques) avec un neurone en employant une fonction d'activation linéaire [1]

Nous avions évoqué la possible utilisation dans ce genre de problématique de fonctions d'activation de type sigmoide. Je vous propose donc de reprendre l'article précédent en appliquant ce type de fonctions a notre problème et comprendre leur fonctionnement, leur interprétation possible.

Considérons donc une autre manière d’implémenter nos neurones en vous proposant le rework suivant:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import math

def neuroneCore(entre,W,biais):
    return np.dot(entre,W.T)-biais
    
def limiter(a):
    if a > 0:
        return 1
    return 0

def sigmoid(a):
    return 1 / (1 + math.exp(-a))
    
def neuroneLim(entre,W,biais):
    a=neuroneCore(entre,W,biais)
    return limiter(a)

def neuroneSig(entre,W,biais):
    a=neuroneCore(entre,W,biais)
    return sigmoid(a)

Avec ce rework, on sépare d'un coté la fonction calculant la pondération des entrées par les dendrites et ensuite on applique dessus soit la fonction limiter soit sigmoïde. On a du coup deux types de neurones. Ce sera ici le seconde type qui nous intéressera.

Appliquons lui les poids initiaux que nous avions appliqués avec en entrée nos deux profils de fruits.

1
2
3
4
5
6
7
8
W=np.array([[1, 1, 1, 0]])
biais=1.5

pasteque=np.array([[0.2, 0.3, 0.2, 0.95]])
anana=np.array([[0.8, 0.65, 0.6, 0.8]])

print(neuroneSig(pasteque,W,biais))
print(neuroneSig(anana,W,biais))

1
2
0.31002551887238755
0.6341355910108007

Bon ceci signifie donc que la pastèque est a 31% un ananas et un ananas est un ananas a 63%. Oui n'oublions pas que avec le limiter, l'ananas valait 1 et la pastèque 0. Donc c'est assez logique donc que d'un coté le taux de similarité d'un pastèque avec un ananas soit prêt de seulement 30%... par contre il faut avouer que pour un ananas, on se serait attendu a être un peu plus ressemblant a un ananas!

N'oublions pas que ces taux sont issus d'un modèle produit a l'intuition. Essayons avec les poids issus de l'apprentissage en mode linaire pour rappel (W=[ 3.40784321 2.44027133 2.17143355 -1.26320997] )

1
2
3
W=np.array([[3.40784321, 2.44027133, 2.17143355, -1.26320997]])
0.12462296460187255
0.7340302487024424

Et bien, c'est évident que c'est mieux, 12% et 73% ! mais ce ne sont que des résultats obtenu sur les profils. Il faut regarder ce que nous donne ce modèle sur l'ensemble des données de test (oui car techniquement avec ce W on a déjà utilisé les 3/4 des données pour l'entrainement).

Mais comment évaluer l'efficacité du modèle? Comment évaluer la pertinence de ces différents taux ?

Ce que l'on peut imaginer pour valider ce nouveau type de neurone, faire c'est de construire un algorithme qui selon la valeur de la sortie du neurone,  classe en ananas ou en pastèque le fruit testé avec pour restriction qu'entre par exemple 40 et 60%, il faut considérer que le fruit est indiscernable et donc mis dans une autre catégorie erreur.

Mais attendez, on avait vu avec la matrice de confusion, qu'il était aussi possible que parfois lorsque l'on détecte un ananas, en fait c'est une pastèque et inversement! Il va nous falloir donc aussi des données étiquetées que nous confronterons avec la valeur prédite par le neurone quand celle ci est soit inférieur a 40% soit supérieur a 60%

Construisons d'abord nos données étiquetés, données d'entrainement et données de tests.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
pasteques=generateSet(pasteque,1999,4)
ananas=generateSet(anana,1999,4)
pasteques2=addEtiquette(pasteques,0)
ananas2=addEtiquette(ananas,1)

datas=pasteques2+ananas2
random.shuffle(datas)
print(len(datas))
datasApprentissage=datas[:3000]
datasTest=datas[3000:]
print(len(datasApprentissage)+len(datasTest))

La bien sur vous allez dire mais on a déjà un W, pourquoi refaire des données d'entrainement? Ba effectivement on va re-procéder a une phase d'entrainement de notre modèle car si nous avions trouvé un modèle intéressant dans l'article précédent, ici, il ne faut pas oublié que nous utilisons une fonction d’activation de type sigmoïde pour laquelle nous avons décidé que toute réponse comprise entre 40% et 60% serait ignoré. Ainsi pendant la phase d'entrainement, il semble pertinent de procéder a la même règle.

A noter de plus que sans nous en apercevoir, dans notre phase d'apprentissage avec un limiter, nous avions un peu mis de coté les corrections sur le biais! Corrigeons ça:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
biaisFactor=np.array([[1, 1, 1, 1]])
marjMin=0.25
marjMax=0.75

print("W initial:",W,biais)    
for (val,etiquete) in datasApprentissage:
    sortie=neuroneSig(val,W,biais)
    if(sortie < marjMin) or (sortie > marjMax):
        W=majW(W, sortie, etiquete,val)
        biais=(np.dot(W,biaisFactor.T))/2
    
print("W final:",W,biais)  

1
2
W initial: [[1 1 1 0]] 1.5
W final: [[16.20492332 10.44986249 12.34447655  2.96069606]] [[20.97997921]]

Par curiosité, que se passe t il si on applique ces paramètres sur nos profils? Regardons.

1
2
print(neuroneSig(pasteque,W,biais))
print(neuroneSig(anana,W,biais))

1
2
8.938402177973581e-05
0.9998068041389231

Wahou! Presque 0% et 99%! C'est prometteur!

Calculons notre matrice de confusion car c'est probablement trop beau.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
erreur=[]
patequesTestIsP=[]
patequesTestIsA=[]
ananasTestIsP=[]
ananasTestIsA=[]
#Revoir comment construire le taux d'erreur
for (val,etiquete) in datasTest:
    sortie=neuroneSig(val,W,biais)
    if (sortie > marjMin) and (sortie < marjMax):
        erreur.append(val)
    if (sortie < marjMin) :
        if etiquete == 0:
            patequesTestIsP.append(val)
        if etiquete == 1:
            patequesTestIsA.append(val)
    if (sortie > marjMax):
        if etiquete == 0:
            ananasTestIsP.append(val)
        if etiquete == 1:
            ananasTestIsA.append(val)

print(len(erreur),":",len(datasTest))
print(len(patequesTestIsP),":",len(datasTest))
print(len(patequesTestIsA),":",len(datasTest))
print(len(ananasTestIsP),":",len(datasTest))
print(len(ananasTestIsA),":",len(datasTest))

1
2
3
4
5
15 : 1000
471 : 1000
40 : 1000
22 : 1000
452 : 1000

Donc nous avons comme matrice de confusion les données suivantes:
  • 15 données indécidables
  • 471 pasteques qui sont bien des pasquetes!
  • 452 ananas qui sont bien des ananas!
  • 40 pasteques qui se prennent pour des ananas
  • 22 ananas qui se prennent pour des pastèques
Donc nous avons 471/(471+22)=0.95 de précision et 471/(471+40)=0.92 de rappel (nous ne comptons pas les données exclu puisque c'est justement le but)

C'est effectivement mieux que pour la classification avec une fonction d'activation limiter.

Maintenant essayons de comprendre comment ça marche. Visualisons un peu nos données.

1
2
3
4
5
6
7
8
9
fig = plt.figure(1,figsize=(12,12))

plt.plot(patequesTestIsP.T[0],patequesTestIsP.T[1],"b.")
plt.plot(ananasTestIsA.T[0],ananasTestIsA.T[1],"b.")
plt.plot(patequesTestIsA.T[0],patequesTestIsA.T[1],"r.")
plt.plot(ananasTestIsP.T[0],ananasTestIsP.T[1],"y.")
plt.plot(erreur.T[0],erreur.T[1],"g.")
plt.xlabel('rugausité')
plt.ylabel('couleur')

Produisant le graphe suivant:


Il faut avouer que ce n'est pas très parlant même si l'on devine une section de données jaune quasi verticales.

Il ne faut pas oublier que nous traitons de données selon 4 dimensions ainsi, dans cette projection, l'hyperplan séparateur des deux classes de fruit n'est probablement pas perpendiculaire au plan du graphique. Ainsi, il est difficile de vraiment visualiser le résultat (ou il faudrait identifier une transformation des données dans un base adéquat... vous savez, matrice de passages, etc... je laisse ça aux motivés mais ça serait intéressant de s'y attarder quand même un de ces quatre).

Simplification

Pour comprendre malgré tout notre problème, je vous propose de le simplifier et de travailler seulement en deux dimensions des le départ.

Reprenons donc nos données et recalculons nos ensembles:

1
2
3
4
5
6
7
8
W=np.array([[1, 1]])#, 1, 0]])
biais=1.5

pasteque=np.array([[0.2, 0.3]])#, 0.2, 0.95]])
anana=np.array([[0.8, 0.65]])#, 0.6, 0.8]])

print(neuroneSig(pasteque,W,biais))
print(neuroneSig(anana,W,biais))

On adapte la procédure d’apprentissage

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#On utilise l'algo en limiter

biaisFactor=np.array([[1, 1]])#, 1, 1]])
marjMin=0.25
marjMax=0.75

print("W initial:",W,biais)    
for (val,etiquete) in datasApprentissage:
    sortie=neuroneSig(val,W,biais)
    if(sortie < marjMin) or (sortie > marjMax):
        W=majW(W, sortie, etiquete,val)
        biais=(np.dot(W,biaisFactor.T))/2
    
print("W final:",W,biais)        

Ensuite on fait passer nos données de tests dans notre algorithme d’évaluation (voir précédent celui ci n'a pas changé) et on finit par afficher les données en adaptant forcement au fait que nous sommes maintenant en deux dimensions (au passage on utilise les paramètres du neurone pour dessiner la droite séparatrice).


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
fig = plt.figure(1,figsize=(12,12))

plt.plot(patequesTestIsP.T[0],patequesTestIsP.T[1],"b.")
plt.plot(ananasTestIsA.T[0],ananasTestIsA.T[1],"b.")
plt.plot(patequesTestIsA.T[0],patequesTestIsA.T[1],"r.")
plt.plot(ananasTestIsP.T[0],ananasTestIsP.T[1],"y.")
plt.plot(erreur.T[0],erreur.T[1],"g.")
plt.xlabel('rugausité')
plt.ylabel('couleur')

x=np.linspace(0,1,10)
plt.plot(x,(biais[0][0]-W[0][0]*x)/W[0][1])

Voyons donc ce que cela donne:


Ainsi, tout devient plus clair avec cette simplification. Pour rappel, en bleu nous avons les données correctement classées, en vert, les données écartées, en rouge et jaune, les faux positifs et les vrais négatifs.

Avec ce graphe on comprend tout de suite mieux l’intérêt de la fonction sigmoïde. Elle permet de construire une zone autour de la droite séparatrice dans laquelle on pousse le modèle a ne pas prendre de décision (ou du moins donner aux prédictions une crédibilité minimale) Bien sur en faisant de la sorte, on sacrifie potentiellement des prédictions justes, cependant, et c'est le contexte de métier qui l'impose, il est parfois préférable de ne pas décider plutôt que de faire une erreur.

Ainsi en utilisant une fonction d'activation de type sigmoïde, on améliore la qualité de la classification en se permettant de rejeter certaines prise de décisions.

Conclusion

Voila, nous avons fait un bon tour de la notion de classification a l'aide de modèle linéaire (ici un seul neurone) Dans les prochains articles je vous propose, maintenant que nous avons acquis les bases des concepts de la classification , d'une part de découvrir quelques outils et framework permettant un travail similaire, et d'autre part d’élargir nos types de modèles. A très bientôt.

Références

[1] https://un-est-tout-et-tout-est-un.blogspot.com/2018/07/ai-approche-neuromimetique-la.html

mardi 10 avril 2018

IA : Principe de l'automatique

Souvent assimilé à une sous classe (ou parfois une sur classe) de l’informatique, l’automatique est en fait une branche de la cybernétique au même titre que l’informatique [1]
L’automatique est l’ensemble des méthodes et théories mathématiques relevant de l'étude et la modélisation des systèmes (dynamiques) et de leur commande. Derrière cette définition un peu vaste se pose la question de la compréhension des conditions amenant un système dans un état particulier (voir l’ensemble des états atteignables) et comment, par la modélisation de son comportement, éventuellement optimiser ce comportement ou le limiter.

L'automaticien a pour rôle de définir cette modélisation et de construire en conséquence une loi de commande pour ce système en suivant l’un de ces deux objectifs : soit simplement d’aider le système à atteindre son objectif et à converger plus rapidement, à garantir sa convergence, ou à minimiser son erreur, soit réduire les comportements non attendu, afin d'éviter sa rupture ou plus grave qu’il ne mette en danger des individus.

La plupart des systèmes de contrôle commande actuels reposent sur des systèmes informatiques, mais ce n’est pas une condition d'existence car ces systèmes ont eut leur équivalent mécanique ou électronique. Il est vrai que si l’on considère l’informatique comme le traitement pure et simple de l’information il serait acceptable de considérer l’informatique comme une branche de l’automatique ou le système dynamique étudié est l’information et les lois de commande à produire comme l’ensemble des transformations opérables en vue d’obtenir d’autres informations optimisés et/ou filtrés.

Seulement, tout ceci est très réducteur car l’informatique s’est largement émancipé de ce genre de préoccupation et aujourd’hui les deux disciplines se distinguent clairement même si elles interagissent encore beaucoup et c’est d’ailleurs sur ce point que je souhaite concentrer cet article : voir les principes de l’automatique en nous concentrant non sur ce que l’informatique peut apporter à l’automatique (je laisse aux automaticiens de faire ce travail) mais sur ce que l’automatique apporte à l’informatique.

En effet, informatique et automatique sont des disciplines qui tirent partie l’une de l’autre. Et jusqu'à ces dernières années on pouvait dire que c'était l’automatique qui tirait le plus partie de l’informatique. Aujourd’hui cependant, on ne peut s'arrêter à cette vision car cette dépendance s’inverse : l’informatique vient de plus en plus chercher les concepts de l’automatique pour adresser ses propres problèmes, c’est pourquoi il est important de regarder ce qui forme les concepts de base de l’automatique afin de mieux en comprendre l’héritage dans les approches actuelles comme le big data, le machine learning, les réseaux de neurones ou plus globalement l’IA qui seront l’objet des articles futur.

Ainsi comme nous l’avons évoqué, l’automatique repose sur deux axes, l'étude des systèmes d’un côté et l'élaboration d’une loi de commande de l’autres, ce dernier axe étant généralement nommé contrôle-commande.

Etude des systèmes

L’etude des systemes est un vaste domaine et couvre bien plus de champs que celui de l’automatique. Cela peut traiter du comportement de véhicules terrestres, du comportement des fluides dans des conditions particulières, du comportement des foules, ou même de la météo. En fait à partir du moment on l’on considère une entité physique dans un environnement bien déterminé, nous faisons de cette considération une étude.

De cette étude viendra alors ensuite par l’utilisation d’outils mathématiques ou de langage de modélisation des objets appelés modèles. Nous ne rentrerons pas dans la question de qu’est ce que la modélisation (sujet déjà traité ici []) mais l’idée ici est d’avoir une entité, représentant le système nous permettant de déduire des propriétés structurelles ou comportementales que ce dernier possède (il est bien sûr très important de toujours garder en tête que le modèle n’est pas le système mais qu’une abstraction de celui ci avec ses propres limites) Donc, ces modèles nous permettent de discriminer le système selon différents critères comme sa nature, sa dynamique, etc.

Loi de commande

Le rôle de la commande est alors de se focaliser sur l’un des axes de ses propriétés (mise en évidence par les modèles adéquat) afin de, par exemple, limiter un comportement, ou à l’inverse en lui permettant d’en avoir de nouveau, etc… Le choix des modèles choisi est très important car il va de soit que les outils permettant de les construire ne sont pas les même selon le besoin de l'étude et également les besoins de contrôle commandes. Pour comprendre le comportement d’un véhicule, il sera nécessaire de s’appuyer sur des équations différentielles pour représenter la dynamique du système alors que dans l'étude d’une population, des outils statistiques seront probablement plus adapté mais de la même façon, afin de permettre la commande d’un système, il faudra également produire des modèles en adéquation avec l’objectif de la commande souvent lui même représenté par un modèle.

Comme il n’est pas forcément possible d’avoir systématiquement la connaissance du bon langage pour chaque cas, il faut être capable de raisonner sur des schéma de principe propre à l’automatique permettant de manipuler les concepts du domaine et élaborer des stratégies de traitement qui pourront s’appliquer à des ensembles de problèmes de même famille. Pour cela, nous avons vu dans le schéma xxx qu’un système existe dans un environnement, qu’il répond à une fonction traitant de paramètre d’entrée afin de produire des données de sorties

Ainsi la figure xxx présente un schéma de principe résumant le fonctionnement d’un système. Si ensuite on projet de lui appliquer une loi de commande, on va alors réaliser l’un des principes les plus important de l’automatique : le feedback ou rétroaction où rebouclage où encore rétropropagation.

Pourquoi autant de termes pour représenter la même chose? Simplement parce que chaque terme s’associe souvent à des domaines autres que l’automatique comme le terme de rétropropagation qui classiquement utilisé dans le domaine de l’IA, du machine learning et du deep learning lorsqu’il est nécessaire de reporter la sortie produite sur les entrées afin d’ “apprendre”.

Bien sur chaque rétroaction s'implémente différemment et cela est conditionné par la nature même du système. Pourtant de façon générale on peut considérer le traitement et les interactions entre le système et la loie de commande comme la mise en relation des éléments du schéma suivant.
Pourtant ; il n’y a jamais de vérité définitive et selon le type du systèmes, les outils de modélisations choisis, les propriétés que l’on souhaite contrôlé et les moyens d'élaborer la loi de commande, il est possible de trouver des versions simplifiées de cette vue en convergeant vers le schéma déjà présenté (schéma asservissement) qui nous ramène à ce concept fondamental, qu’est le feedback.

Conclusion

Voila, je n’irais pas plus loin dans cet article déjà assez long surtout que le but était surtout d’introduire la notion de feedback, qui va nous être d’une aide indispensable dans le traitement de l’IA dont les articles vont venir très prochainement.

Références:

[1] https://interstrate.com/2016/10/18/cybernetique-et-theorie-des-systemes/