lien vers le compte rendu du TP 2

publicité
Université Sidi Mohamed Ben Abdellah
Faculté Des Sciences et Techniques
Fès
Compte Rendu du TP N°2
Réseau de neurones
Réalisé par :
Encadré par :
MAADOUR Soufiane
ZYATE Mahmoud
KAMRANI Abdelhalim
HAMOUT Hamza
BOUTAYEB Aymane
Date début du projet : 18/02/2015
Pr. MAJDA Aicha
Date Fin du projet : 05/05/2015
Lien du Blog : www.gsirx.wordpress.com
Objectifs
Détailler le fonctionnement de l’application du TP N°2 des réseaux de neurones – Perceptron multicouche.
2014 – 2015
Sommaire
SOMMAIRE ......................................................................................................................................................... 2
INTRODUCTION .................................................................................................................................................. 3
PARTIE 1 ............................................................................................................................................................. 4
Application du calcul effectué dans un PCM ...................................................................................................... 4
QUESTION 1 : ............................................................................................................................................................ 4
QUESTION 2 : ............................................................................................................................................................ 6
PARTIE 2 ............................................................................................................................................................. 7
Implémentation de perceptron multicouche ..................................................................................................... 7
VUE GENERALE DE LA CONCEPTION ................................................................................................................................. 7
DESCRIPTION DES CLASSES UTILISEES ............................................................................................................................... 8
L’interface graphique......................................................................................................................................... 8
Main.java ......................................................................................................................................................................... 8
GraphPanel.java ............................................................................................................................................................ 10
NetworkGraph.java ....................................................................................................................................................... 12
Structure de donnée ........................................................................................................................................ 12
Character.java................................................................................................................................................................ 12
Data.txt .......................................................................................................................................................................... 12
DataHandler.java ........................................................................................................................................................... 12
Implémentation de l’algorithme de rétropropagation .................................................................................... 12
BackPropagation.java .................................................................................................................................................... 12
Apprentissage ........................................................................................................................................................... 13
Test de classification ................................................................................................................................................. 15
2
GROUPE SIRX MSIR 2014
Introduction
Un réseau de neurones artificiels est un modèle de calcul dont la conception est très schématiquement inspirée du fonctionnement des neurones biologiques, ils sont généralement utilisés
dans des méthodes d'apprentissages afin de prendre des décisions.
Notre objectif et d'arriver à concevoir un programme capable d’identifier des objets, plus exactement des lettres latins. On a utilisé dans un premier temps les réseaux bayésiens qui sont déjà
expliqué et détaillé dans le premier projet, alors que dans ce projet nous allons opter pour les
réseaux de neurones, plus exactement le perceptron multi couche et son algorithme de rétropropagation.
Ce document est divisé en deux partie, dans la première on montre le calcule effectuer dans une
seule itération de l’algorithme de rétropropagation. Ensuite nous allons implémenter l’algorithme
et l’utiliser dans une application pour classifier les lettres.
3
GROUPE SIRX MSIR 2014
Partie 1
Application du calcul effectué dans un PCM
On considère le PCM suivant
Avec :
xi : Les entrées du réseau.
hj : Les sorties de la couche cachée.
y : La sortie du réseau.
Question 1 :
Fonction XOR-logique
En utilisant l’algorithme de la rétro-propagation pour l’apprentissage de la fonction logique XOR, on calcule
les nouveaux poids synaptiques wij pour une seule itération.
On prend comme exemple d’apprentissage le vecteur (x1=0, x2=1).
Les données de notre réseau sont :
La fonction de transfert sigmoïde:
f(x)=1/ (1+e(-x))
Le taux d’apprentissage
α = 0.7
4
GROUPE SIRX MSIR 2014
Les biais
b1 = 0.4
b2 =0.6
b3 = -0.3
Les poids
W11 = 0.7
W21 = -0.4
W12 = -0.2
W22 = 0.3
W1 = 0.5
W2= 0.1
L’apprentissage de notre fonction comporte 3 phases :
La propagation en avant
-Cette étape consiste à calculer les valeurs des neurones de la couche cachée et ceux de la couche de sortie
par la fonction sigmoïde calculée pour la somme pondéré de chaque neurone.
Somme pondérée du neurone i : Si = Σ Wj Xj + bi avec Wj les poids synaptiques entrants au neurone
Fonction sigmoïde : f(x)=1/ (1+e(-x)) pour tout réel x
Neurones
H1 (couche cachée)
Valeurs des neurones
0.55
H2 (couche cachée)
Y (couche de sortie)
0.71
0.51
Y (couche de sortie)
Le calcul de l’erreur
La formule utilisée pour calculer l’erreur est :
Neurones
H1 (couche cachée)
H2 (couche cachée)
Erreur des neurones
0.12
0.015
0.025
La rétro-propagation de l’erreur
On doit maintenant ajuster les poids en rétro-propageant l’erreur observée par le biais de la relation suivante :
5
GROUPE SIRX MSIR 2014
Poids
Nouvelle
valeur
B3
-0.26
W1
B1
0.51
0.43
W11
0.7
W12
W22
B2
W21
W2
-0.19
0.30
0.60
-0.4
0.12
Donc notre réseau devient comme suit :
Question 2 :
La fonction OU-logique
Pour l’apprentissage de la fonction logique OU, c’est le même traitement effectué pour le
XOR, car la sortie désirée est la même (d=1) par le vecteur d’apprentissage (0,1).
6
GROUPE SIRX MSIR 2014
Partie 2
Implémentation de perceptron multicouche
On se propose d’implémenter dans cette partie un perceptron multicouche afin de faire avec la classification de caractères alphabétiques majuscules. L’implémentation est faite entièrement en langage JAVA.
Notre perceptron comprends, en plus de sa couche d’entré et de sortie, une seule couche caché composée de 200 neurones (hormis le biais de cette couche). La couche d’entrée est fixée à 2500 neurones, évidemment puisqu’on travaille avec des images de 50*50 pixels. La couche de sortie contient initialement 26
neurones pour chaque lettre d’alphabet.
Vue générale de la conception
Nos caractères sont à la base des images binaires composées de 0 et de 1. On se propose de les saisir
dans nos programmes puis de transformer la matrice d’image en vecteur. La sauvegarde de l’information se
fait suivant la structure de la classe Character.java qu’on détaillera par la suite.
L’interface propose en premier lieu de faire l’apprentissage, que ce soit de sa base de connaissance déjà
stockées dans le fichier data.txt ou avec de nouveaux exemples que l’utilisateur ajoute (et qui seront éventuellement stockés dans notre fichier). Une fois l’apprentissage est terminé, une courbe de variation de
l’erreur quadratique durant les itérations de l’apprentissage. L’interface propose également de faire le test
ou plus exactement de classifier les images de caractères alphabétiques que l’utilisateur importe tout en
traçant un réseau simplifié montrant les valeurs de sortie sur lesquelles le réseau de neurone a appuyé sa
décision.
7
GROUPE SIRX MSIR 2014
Description des classes utilisées
L’application de classification de caractères alphabétiques se base sur sept classes. Quatre classes à
connotation graphique, deux classes utilitaires et une classe modèle.
L’interface graphique
Le coté graphique est géré par 4 classes, une classe principale Main.java faisant appel en cas de besoin à
trois autres classes qui sont des implémentations de panels : GraphPanel.java, NetworkGraph.java et Loading.java.
Main.java
Il s’agit du corps général et la classe pilote de l’interface. En plus de la présentation de la vue, la gestion des
événements y est incluse ainsi que le chargement de données depuis le fichier data.txt.
FIGURE 1 : PARAMETRES PAR DEFAUT
On propose deux sections, la première pour l’apprentissage et la seconde pour la classification. Dans celle
de l’apprentissage l’utilisateur peut choisir entre « utiliser la base d’exemples d’entrainement existante »
ou « ajouter un exemple à la base d’entrainement ». On utilise les exemples existants par défaut.
Quand l’ajout d’exemple est coché, des choix supplémentaires apparaissent à l’utilisateur lui demandant de
spécifier la nature des caractères qu’il souhaite ajouter à la base d’apprentissage. Il s’agit d’exemple existant quand la classe figure déjà dans notre liste de classes (ce qui présente la liste défilante) et qu’on veut
8
GROUPE SIRX MSIR 2014
enrichir ses modèles. Et encore, il s’agit d’un nouvel exemple quand il n’y pas de classe correspondante,
l’utilisateur doit entrer dans ce cas dans le champ de texte de quel caractère il s’agit.
FIGURE 2 : OPTIONS D 'AJOUT D ' EXEMPLES
Le bouton « Importer » ouvre l’interface d’import de fichier. Une fois son choix effectué, l’image sera transformée en vecteur grâce à une méthode de la classe DataHandler.java et ajoutée dans le fichier data.txt.
Le bouton « Lancer l’apprentissage », permet bien entendu de calculer la propagation et la rétro propagation jusqu’à atteinte de poids satisfaisants en faisant appel à la méthode Learning(ArrayList<Character>
baseExemples) de la classe BackPropagation.java qui sera détaillé par la suite.
Malencontreusement, on ne peut prédire le temps d’exécution de l’apprentissage. L’exécution est lente car
non seulement l’algorithme de rétro-propagation peut s’exécuter jusqu’à 1000 fois pour atteindre une
erreur quadratique acceptable mais la taille d’image qui interfère aussi. Nos images sont de 50*50 pixel,
soit 2500, on calcule les poids pour 200 neurones de la couche caché et ensuite pour 26 neurones de sortie
(ce qui inclus déjà plusieurs calculs : la valeur d’activation de chaque neurone ainsi que les deltas d’erreurs
et la correction de valeurs) nous laissant ainsi avec des milliers de calculs à faire dans l’unique itération. A
noter que lors de nos premiers tests pour l’implémentation de l’algorithme on utilisait des images de 5*5
pixels et donc 25 neurones d’entrée, on allait jusqu’à 3500 itération mais en si peu de temps.
On a du coup pensé à permettre à l’utilisateur de paramétrer l’erreur quadratique désirée. Emax = 2 par
défaut.
9
GROUPE SIRX MSIR 2014
GraphPanel.java
Une fois terminé on récupère la collection contenant l’erreur quadratique calculée à chaque itération et on
instancie avec le dessin du graphe de sa variation. C’est la classe GraphPanel.java qui s’occupe de cette
tâche pour avoir au final un graphe comme ci-dessous.
FIGURE 3 : APERÇU DU GRAPHE DE VARIATION D' ERREUR QUADRATIQUE
Cette exécution indique qu’on a fait à peu près 320 itérations avant d’attendre une erreur quadratique égal
à 0.99 et qui satisfait nos paramètres.
À ce stade, l’apprentissage du perceptron multicouche est effectué. On peut ainsi passer à l’autre section,
celle de la classification.
Présentée de la manière la plus simple, l’utilisateur est invité à importer l’image de caractère voulu puis
pourra ensuite lancer le test.
10
GROUPE SIRX MSIR 2014
FIGURE 4 : PROCEDURE D' IMPORT D 'IMAGE A CLASSIFIER
Le bouton de test fait appelle à la méthode Testing(int[] lettre) qui prend en paramètre le vecteur contenant le valeurs de la couche d’entrée du réseau de neurones. Ce vecteur est en effet l’image entrée par
l’utilisateur transformée par une méthode de la classe DataHandler.java.
FIGURE 5 : APERÇU DE TEST POUR UNE IMAGE CONTENANT LA LETTRE T.
11
GROUPE SIRX MSIR 2014
NetworkGraph.java
Quand l’exécution du test est terminé, en récupère les valeurs calculées sur les neurones de la couche de
sortie et les passent en paramètres dans une instance de la classe NetworkGraph.java. Cette dernière dessine un réseau un graph simplifié du perceptron multicouche et liste l’ensemble des caractères de sortie
ainsi que les valeurs sur lesquels le perceptron s’est appuyé pour sa décision comme montré dans la figure
5.
Structure de donnée
L’interface repose principalement sur des images contenant des caractères. On a donc besoin de saisir ces
informations et les transformer selon nos besoins.
Character.java
Cette classe contient le modèle qu’on a utilisé; une instance de cette classe correspond à un caractère que
ce soit d’apprentissage ou de validation. On peut accéder à son nom grâce à l’attribut classe ou encore à
son vecteur de valeurs grâce à l’attribut vecteur.
Data.txt
Le fichier est en guise de base de données. Il contient pour chaque exemple de la base d’apprentissage les
données de son vecteur. Il est structuré de la manière suivante :
Ou d’une façon simplifiée : <la classe du caractère> : <vecteur des valeurs>.
DataHandler.java
Pour manipuler ce fichier ou encore transformer l’image importée en vecteur on fait appel à cette classe. La
base de connaissance est stockée dans une collection d’instances de la classe Character.java.
Implémentation de l’algorithme de rétropropagation
On va simplement lister le contenu de la classe
BackPropagation.java
import java.util.ArrayList;
public class BackPropagation {
private static double Emax = 2; //l'erreur quadratique désirée
private static final double nu = 0.1; // le paramètre nu du taux d'apprentissage.
public static String Classes =""; //contient l'ensemble des classes pris en compte.
public static String Exemples ="";//contient la suite des exemples d'apprentisages.
public static int nombreClasses; // le nombre de classes.
static int[] input; // la couche d'entrée
static double[] hidenVector; //la couche cachée
static double[] output; //la couche de sortie
12
GROUPE SIRX MSIR 2014
static
static
static
static
static
static
double[] outBias; //les poids du biais de la couche de sortie
double[] hidBias; //les poids du biais de la couche cachée
double[][] inW; // les poids de la couche d'entrée
double[][] hidW; //les poids de la couche cachée
int vectorSize = 2500; // le nombre de pixels
ArrayList<Double> cycleError; //la collection contenant l'erreur quadratique
//calculée dans chaque itération.
private static void Allocation() // simple allocation des vecteurs et matrices
{
input = new int[vectorSize];
hidenVector = new double[200];
output = new double[nombreClasses];
outBias = new double[nombreClasses];
hidBias = new double[200];
inW = new double[vectorSize][200];
hidW = new double[200][nombreClasses];
cycleError = new ArrayList<Double>();
}
public static void setInput(int[] input) {
for (int i = 0; i < input.length; i++){
BackPropagation.input[i] = input[i];
}
}
public static void setEmax(double emax) {
Emax = emax;
}
public static ArrayList<Double> getCycleError() {
return cycleError;
}
public static double[] getOutput() {
return output;
}
private static void initWeights() //initialisation des poids
{
for (int i = 0; i < vectorSize; i++)
for (int j = 0; j < 200; j++){
inW[i][j] = (Math.random() - 0.5); // compris entre -0.5 et 0.5
}
for (int i = 0; i < 200; i++)
for (int j = 0; j < nombreClasses; j++){
hidW[i][j] = (Math.random() - 0.5);
}
for (int j = 0; j
outBias[j]
}
for (int i = 0; i
hidBias[i]
}
< nombreClasses; j++){
= (Math.random() - 0.5)/5;
// compris entre -0.1 et 0.1
< 200; i++){
= (Math.random() - 0.5)/5;
}
Apprentissage
//méthode de l'apprentissage
public static void Learning(ArrayList<Character> baseExemples) {
// TODO Auto-generated method stub
//nombreExemples = baseExemples.size();
13
GROUPE SIRX MSIR 2014
nombreClasses = Classes.length();
Allocation();
initWeights();
double E;
do
{
E=0;
for(Character exemple:baseExemples)
{
setInput(exemple.getVecteur());
//calcul des sorties de la couche cachée
for (int k = 0; k < 200; k++)
{
double s = 0;
for (int j = 0; j < vectorSize; j++){
s += input[j]*inW[j][k];
}
s+=hidBias[k];
hidenVector[k] = 1.0 / (1.0 + Math.exp(-s));
}
//calcul des sorties de la couche de sortie puis erreur
double[] errOut = new double[nombreClasses];
for (int k = 0; k < nombreClasses; k++)
{
double s = 0;
for (int j = 0; j < 200; j++){
s += hidenVector[j]*hidW[j][k];
}
s+=outBias[k];
output[k] = 1.0 / (1.0 + Math.exp(-s));
//calcul de l'erreur de sortie – c’est délicat ici.
int d = k==Classes.indexOf(""+exemple.getName())?1:0;
//Deltam
errOut[k]= (d-output[k])*output[k]*(1-output[k]);
E+=Math.pow((d-output[k]), 2); //Erreur quadratique
//Mise à jour des poids de la couche de sortie
for (int j = 0; j < 200; j++){
hidW[j][k]+=nu*errOut[k]*hidenVector[j];
//Delta Wjk : modification de poids - couche de sortie
}
outBias[k]+= nu*errOut[k];
}
// Calcul de l'erreur de la couche caché
double[] errHid = new double[200];
for (int j = 0; j < 200; j++)
{
double contribution=0;
for (int k = 0; k < nombreClasses; k++){
contribution+=errOut[k]*hidW[j][k];
}
errHid[j]+=hidenVector[j]* (1 hidenVector[j])*contribution;
//Mise à jour des poids de la couche cachée
for (int k = 0; k < vectorSize; k++){
inW[k][j]+=nu*errHid[j]*input[k];
}
hidBias[j]+=nu*errHid[j];
14
GROUPE SIRX MSIR 2014
}
}
E=E/2;
cycleError.add(E);
//System.out.println(E);
}while(E>Emax);
//System.out.println("terminé!");
//System.out.println(cycleError.size());
}
Test de classification
//méthode du test
public static void Testing(int[] lettre)
{
setInput(lettre);
//calcul des sorties de la couche cachée
for (int k = 0; k < 200; k++)
{
double s = 0;
for (int j = 0; j < vectorSize; j++){
s += input[j]*inW[j][k];
}
s+=hidBias[k];
hidenVector[k] = 1.0 / (1.0 + Math.exp(-s));
}
//calcul des sorties de la couche de sortie
for (int k = 0; k < nombreClasses; k++)
{
double s = 0;
for (int j = 0; j < 200; j++){
s += hidenVector[j]*hidW[j][k];
}
s+=outBias[k];
output[k] = 1.0 / (1.0 + Math.exp(-s));
//System.out.println(output[k]);
}
}
}
15
GROUPE SIRX MSIR 2014
Téléchargement