Perceptron
|
|
Cet article est une ébauche concernant l’informatique.
Vous pouvez partager vos connaissances en l’améliorant (comment ?) selon les recommandations des projets correspondants.
|
Le perceptron a été inventé en 1957 par Frank Rosenblatt au Cornell Aeronautical Laboratory, inspiré par la théorie cognitive de Friedrich Hayek et celle de Donald Hebb.
Sommaire |
Définition [modifier]
Le perceptron peut être vu comme le type de réseau de neurones le plus simple. C'est un classifieur linéaire. Ce type de réseau neuronal ne contient aucun cycle (en anglais feedforward neural network). Dans sa version simplifiée, le perceptron est mono-couche et n'a qu'une seule sortie à laquelle toutes les entrées sont connectées. Les entrées et la sortie sont booléennes.
Le potentiel post-synaptique biaisé est représenté par
. Ici, θ définit le seuil (ou biais) à dépasser pour que la sortie Y soit à 1, et
est le poids de l'entrée
.
La fonction d'activation est la fonction de Heaviside (la fonction signe est parfois utilisée)
On trouve fréquemment une variante de ce modèle de base dans laquelle la sortie prend les valeurs -1 et 1 au lieu de 0 et 1.
La règle de Hebb [modifier]
La règle de Hebb établie par Donald Hebb est une règle d'apprentissage des réseaux de neurones artificiels dans le contexte de l'étude d'assemblées de neurones.
Cette règle suggère que lorsque deux neurones sont excités conjointement, il se crée ou renforce un lien les unissant.
Dans le cas d'un neurone artificiel seul utilisant la fonction signe comme fonction d'activation cela signifie que :
où
représente le poids
corrigé et
représente le pas d'apprentissage.
Cette règle n'est malheureusement pas applicable dans certains cas bien que la solution existe.
La règle d'apprentissage du Perceptron [modifier]
Le perceptron de Frank Rosenblatt est très proche de la règle de Hebb, la grande différence étant qu'il tient compte de l'erreur observée en sortie.
où
représente la sortie attendue,
le poids
corrigé et
le pas d'apprentissage.
Exemple de programme [modifier]
Ceci est un programme en C++, apprenant la fonction NAND appliquée à un ensemble de 2 bits (x1 et x2), auxquels on rajoute 1 bit (x0), qui est une constante à 1, on a donc 100,101,110,111 comme inputs, les résultat attendus étant respectivement 1,1,1,0. Pour une autre fonction (AND, OR ou NOR mais pas le XOR en raison des limitations du perceptron), le seul changement à opérer est le tableau des résultats attendus.
Le programme fonctionne par cycles où chaque exemple est testé une fois, tant que tous les exemples ne sont pas corrects (résultat produit = résultat attendu) dans le cycle, on en refait un. Par contre les poids sont modifiés à chaque exemple qui s'avère incorrect. Ils sont ici initialisés à 0, mais on pourrait tout aussi bien les mettre à 1 ou encore à une valeur aléatoire, cela modifie juste le nombre d'étapes avant d'arriver au résultat.
#include <iostream> using namespace std; int const X(3); // x1 et x2 les entrées, x0 est une constante à 1 int const NB_EX(4); // nombre d'exemples donnés float const SEUIL(0.5); // seuil d'activation float const PAS(0.1); // le pas d'apprentissage void affichage(float*,int,int,int); // affiche l'état actuel des poids int main () { int tabEntree[NB_EX][X] = { {1,0,0},{1,0,1},{1,1,0},{1,1,1} }; // les exemples donnés avec x0, x1, x2 int tabResPrevu[NB_EX] = {1,1,1,0}; // les résultats prévus correspondant aux entrées float tabPoids[X] = {0,0,0}; // les poids synaptiques int res, cptrCycle(0); // res est le résultat produit, à comparer au résultat prévu float somme(0); // la somme pondérée bool erreurs(true); // pour détecter fin apprentissage affichage(tabPoids,X,0,cptrCycle); // Phase d'apprentissage while (erreurs) { // on continue tant qu'on a au moins une erreur par cycle erreurs = false; cptrCycle++; for (int j=0; j<NB_EX; j++) { // un cycle somme = 0; for(int i=0; i<X; i++) { somme += tabEntree[j][i] * tabPoids[i]; // somme pondérée de l'exemple } res = (somme > SEUIL) ? 1 : 0; // fonction de seuil for (int i=0; i<X; i++) { tabPoids[i] += (tabResPrevu[j]-res) * PAS * tabEntree[j][i]; // modification des poids } if ((tabResPrevu[j] - res) != 0) { // détection de fin d'apprentissage erreurs = true; } affichage(tabPoids,X,j,cptrCycle); } } cout << "Apprentissage terminé en " << cptrCycle << " cycles" << endl; return 0; } void affichage(float* poids, int n, int cptr, int cptr2) { int i; cout << "----- Cycle " << cptr2 << " Etape " << cptr << " -----" << endl; for (i=0; i<n; i++) { cout << "poids[" << i << "] = " << poids[i] << endl; } }
Le même programme en Ruby
SEUIL = 0.5 PAS = 0.1 poids = Array.new [0,0,0] Entrees = Array.new [ [1,0,0], [1,0,1], [1,1,0], [1,1,1] ] Reponses = Array.new [ 1, 1, 1, 0 ] def afficher(poids, cycle, etape) p "--- Cycle #{cycle} - Etape #{etape}" poids.each_index do |i| p "Poids #{i} = #{poids[i]}" end end cycle_n = 0 erreur = true while erreur do erreur = false 4.times do |exemple_n| # Prediction somme = 0 3.times do |i| somme += poids[i] * Entrees[exemple_n][i] end resultat = if (somme > SEUIL) then 1 else 0 end # Correction diff = Reponses[exemple_n] - resultat 3.times do |i| poids[i] += PAS * diff * Entrees[exemple_n][i] end erreur = true if Reponses[exemple_n] != resultat afficher(poids, exemple_n, cycle_n) end cycle_n = cycle_n + 1 end p "Apprentissage terminé en #{cycle_n} cycles"
Le programme qui suit est en langage C et permet l'apprentissage de la fonction AND par un perceptron.
//apprentissage de la fonction and par un perceptron #include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> // n est le nombre d'entrée +1 pour le seuil theta #define N 4 // apprentissage grâce à la modification des poids void apprentissage (int*,float*,int, int,int); // calcule la sortie du perceptron int calculsortieperceptron (int*,float*,int); // calcule la sortie attendue int calculsortieatendu (int*,int); // affiche le résumé d'une itération void affinfo(int*,float*,int, int,int); // compteur binaire à n bits permettant de générer des entrées automatiquement int calculentre (int*,int); int main(void) { // O = sortie du perceptron et T sortie attendu int E[N], O, i, T, compteur, flag, ent; // tableau des poids associés aux entrées E[i] float W[N]; flag=0; // met le compteur d'itération à 0 compteur=0; srand(time (NULL)); rand(); // première étape initialisation des poids synaptique et des entrées for (i=0;i<n;i++) { W[i] = (double)(rand() * 5) / RAND_MAX; E[i] = 0; printf("le poids %d est initialise a :%f \n",i+1,W[i]); } // l'entrée de theta est toujours à 1 E[0] = 1; // cycle d'apprentissage while (flag != 1 || en t!= 0) { if (ent == 0) flag = 1; compteur++; O = calculsortieperceptron(&E[0], &W[0], n); T = calculsortieatendu(&E[0], n); affinfo(E, W, n, O, T); if (O != T) { flag = 0; apprentissage(&E[0], &W[0], n, O, T); } ent = calculentre (&E[0], n); } printf("le perceptron a appris la fonction en %d iterations", compteur); getchar(); return 0; } void apprentissage(int* E, float* W, int n, int O, int T) { int i = 0; for (i=0 ; i < n ; i++, E++, W++) *W += (T - O) * 1**E; } int calculsortieperceptron (int* E, float* W, int n) { int i, O = 0; for (i=0 ; i<n ; i++, E++, W++) O += (*W)**E; if (O > 0) O = 1; if (O <= 0) O=0; return O; } void affinfo(int* E, float* W, int n, int O, int T) { int i; printf ("\n\n\n"); for (i=1 ; i<n ; i++) { printf ("E%d=%d ", i, *(E+i)); printf ("W%d=%f\n", i, *(W+i)); } printf ("theta=%f\n\n", *W); printf ("sortie O=%d\n", O); printf ("sortie attendu T=%d\n", T); } int calculentre (int* E, int n) { int e1, i, e2; e1 = 0; n--; E++; for (i=0 ; i<n ; i++) e1 += (*(E+i) << (i)); e1++; if (e1 > (pow(2,n) - 1)) e1=0; for (i=0 ; i<n ; i++) { e2 = pow(2, i); *(E+i) = (e1 & e2) / e2; } return e1; } int calculsortieatendu (int* E, int n) { int i, T=0; T = *(E+1) & *(E+2); for (i=3 ; i<n ; i++) T = T & *(E+i); return T; }
Voir aussi [modifier]
Le perceptron : Algorithme et théorèmes
Bibliographie [modifier]
- F. Rosenblatt (1958), "The perceptron: a probabilistic model for information storage and organization in the brain",
- - repris dans J.A. Anderson & E. Rosenfeld (1988), Neurocomputing. Foundations of Research, MIT Press


