/// <summary> /// Initialiser le réseau /// </summary> /// <param name="transfert">Fonction de transfert</param> /// <param name="nbEntrees">Nb d'entrées des neurones de la couche d'entrée</param> /// <param name="transfertDerivee">Null ou dérivée de la fonction de transfert</param> /// <param name="seuil">Seuil de la fonction de transfert de la couche</param> /// <param name="topologie">Topologie du réseau</param> protected override void Initialiser(Func <double, double> transfert, double seuil, Func <double, double> transfertDerivee, int nbEntrees, int[] topologie) { Couches = new Couche[topologie.Length]; // couche d'entrée Couches[0] = new Couche(topologie[0], nbEntrees, FonctionsTransfert.Identite, 0); foreach (Neurone neurone in Couches[0].Neurones) { for (int i = 0; i < neurone.Poids.Length; i++) { neurone.Poids[i] = 1; } } // couches cachées for (int c = 1; c < Couches.Length - 1; c++) { //Couches[c] = new Couche(topologie[c], Couches[c - 1].Neurones.Length, FonctionsTransfert.HyperTan, 0, FonctionsTransfert.HyperTanDerivee); Couches[c] = new Couche(topologie[c], Couches[c - 1].Neurones.Length, FonctionsTransfert.Sigmoide, 0.5, FonctionsTransfert.SigmoideDerivee); Couches[c].Position = c; } // couche de sortie Couches[Couches.Length - 1] = new Couche(topologie[Couches.Length - 1], Couches[Couches.Length - 2].Neurones.Length, FonctionsTransfert.Sigmoide, 0.5, FonctionsTransfert.SigmoideDerivee); Couches[Couches.Length - 1].Position = Couches.Length - 1; }
/// <summary> /// Cacule la matrice des erreurs effectuées par le réseau sur le jeu de tests fournis /// </summary> /// <param name="tests">Jeu de tests</param> /// <param name="cibles">Cible pour chaque jeu de test</param> /// <returns> /// Matrice des erreurs contenant l'erreur commise par chaque neurone de la couche de sortie /// </returns> private double[] CalculerErreur(double[][] tests, double[] cibles) { Couche coucheSortie = Couches[Couches.Length - 1]; double[] erreurs = new double[coucheSortie.Neurones.Length]; for (int n = 0; n < coucheSortie.Neurones.Length; n++) { Neurone neurone = coucheSortie.Neurones[n]; double somme = 0.0; for (int i = 0; i < tests.Length; i++) { double sortie = neurone.CalculerSortie(tests[i]); double ecart = cibles[i] - sortie; // calcule l'erreur faite par le réseau lors de l'estimation de la cible // sur le neurone en cours de la dernière couche somme += ecart * ecart; } erreurs[n] = 0.5 * somme; } return(erreurs); }
public ReseauNeural(int nbEntree, int nbSortie, int nbCouche) { Entree = new float[nbEntree]; Sortie = new float[nbSortie]; NeuroneSortie = new Neurone[nbSortie]; for (int i = 0; i < nbSortie; i++) { NeuroneSortie[i] = new Neurone(nbEntree); } if (nbCouche < 0) { nbCouche = 1; } NbNeuronneMax = nbEntree > nbSortie ? nbEntree : nbSortie; LesCoucheNeural = new Couche[nbCouche]; for (int i = 0; i < nbCouche; i++) { if (i == 0) { LesCoucheNeural[i] = new Couche(nbEntree, NbNeuronneMax); } else { LesCoucheNeural[i] = new Couche(NbNeuronneMax, NbNeuronneMax); } } }
/// <summary> /// Propagation des erreurs entre couche1 et couche2 sur les poids et les biais /// </summary> /// <param name="pas">Pas d'apprentissage</param> /// <param name="couche1"></param> /// <param name="couche2"></param> /// <remarks> /// couche1 => couche2 /// </remarks> private void Propager(Couche couche1, Couche couche2, double pas) { for (int c2 = 0; c2 < couche2.Neurones.Length; c2++) { Neurone neurone2 = couche2.Neurones[c2]; for (int c1 = 0; c1 < couche1.Neurones.Length; c1++) { neurone2.Poids[c1] += pas * neurone2.Erreur * couche1.Neurones[c1].Sortie; } neurone2.Biais += pas * neurone2.Erreur; } }
/// <summary> /// Calcule des erreurs (gradiant local) des neurones de la couche de sortie /// </summary> /// <param name="tests">Jeu de tests</param> /// <param name="cible">Cible (valeur désirée) pour chaque jeu de test</param> private void CalculerDeltaO(double[] cible) { Couche coucheSortie = Couches[Couches.Length - 1]; for (int k = 0; k < coucheSortie.Neurones.Length; k++) { Neurone neuroneO = coucheSortie.Neurones[k]; double ecart = 0.0; ecart = cible[k] - neuroneO.Sortie; neuroneO.Erreur = neuroneO.TransfertDerivee(neuroneO.Somme + neuroneO.Biais) * ecart; //Debug.WriteLine("Gradiant O: " + neuroneO.Erreur.ToString()); } }
/// <summary> /// Calcule de l'erreur (gradiant local) des neurones des couches cachées /// </summary> /// <param name="couche1">Couche cachée N</param> /// <param name="couche2">Couche N + 1</param> /// <returns></returns> private void CalculerDeltaH(Couche couche1, Couche couche2) { for (int k = 0; k < couche1.Neurones.Length; k++) { Neurone neuroneH = couche1.Neurones[k]; double somme = 0.0; for (int i = 0; i < couche2.Neurones.Length; i++) { Neurone neurone2 = couche2.Neurones[i]; somme += neurone2.Poids[k] * neurone2.Erreur; } neuroneH.Erreur = neuroneH.TransfertDerivee(neuroneH.Somme + neuroneH.Biais) * somme; //Debug.WriteLine("Gradiant H: " + neuroneH.Erreur.ToString()); } }
/// <summary> /// Initialise la couche /// </summary> /// <param name="transfert">Fonction de transfert</param> /// <param name="transfertDerivee">Nom utilisé</param> /// <param name="topologie">Topologie du réseau</param> /// <param name="seuil">Seuil de la fonction de transfert</param> /// <param name="nbEntrees">Nb d'entrées des neurones de la couche d'entrée</param> protected override void Initialiser(Func <double, double> transfert, double seuil, Func <double, double> transfertDerivee, int nbEntrees, int[] topologie) { Couches = new Couche[1]; Couches[0] = new Couche(topologie[0], nbEntrees, transfert, seuil); }
static void Main(string[] args) { string selection = null; while (selection != "1" && selection != "2") { Console.Clear(); Console.WriteLine("1) Cartographie"); Console.WriteLine("2) Fleurs d'iris"); Console.WriteLine("Quel jeu de test?"); selection = Console.ReadLine(); selection = selection.Trim(); } #region Création Console.Clear(); Console.WriteLine("Création du réseau"); int[] topologie; if (selection == "1") { topologie = new int[] { 2, 2, 1 }; } else { topologie = new int[] { 4, 7, 3 }; } DeepNetwork deepNetwork = new DeepNetwork(1, topologie); Console.WriteLine("Nb de couches: {0}", deepNetwork.Couches.Length); Console.WriteLine("Topologie du réseau: {0}", string.Join("x", topologie)); int nbPoids = 0; for (int i = 1; i < topologie.Length; i++) { nbPoids += topologie[i] * topologie[i - 1]; } Console.WriteLine("Nombre de poids: {0}", nbPoids); Console.WriteLine("Nombre de biais/neurones: {0}", topologie[1] + topologie[topologie.Length - 1]); Console.WriteLine("---------------------------------------------"); Console.WriteLine(); #endregion Helper.PoidsAleatoires(deepNetwork, false); // vitesse d'apprentissage double pas = 0.5; double maxErreur = 0.03; int maxIteration = 5000; if (selection == "1") { Cartographie(); } else { // iris pas = 0.05; maxErreur = 0.001; maxIteration = 500; Iris(); } deepNetwork.Calculer(entrainement[0]); Helper.AfficherReseau(deepNetwork); // entraînement Console.WriteLine("Entraînement du réseau sur {0} tests et {1} itérations max", entrainement.Length, maxIteration); Console.WriteLine("Pas: {0}", pas); double erreur = deepNetwork.Entrainer(entrainement, cibleEntrainement, maxIteration, pas, maxErreur); Console.WriteLine("Erreur en fin d'apprentissage: {0}", erreur); Helper.AfficherReseau(deepNetwork); // jeu de test Couche coucheSortie = deepNetwork.Couches[2]; for (int i = 0; i < tests.Length; i++) { deepNetwork.Calculer(tests[i]); Console.WriteLine("Test {0}", i); Helper.AfficherVecteur(tests[i], "Entrées:"); Helper.AfficherSorties(coucheSortie.Neurones, "Calculé: "); Helper.AfficherVecteur(cibleTest[i], "Cible:"); Console.WriteLine(); } Console.WriteLine("Terminé"); Console.ReadLine(); }
/// <summary> /// Entraine le réseau /// </summary> /// <param name="maxIteration">Nombre d'itérations max</param> /// <param name="pas">Pas d'apprentissage</param> /// <param name="jeuEssai">Jeu d'essai pour entraîner le réseau. Il contient la valeur à appliquer à chaque neurone de la couche d'entrée</param> /// <param name="biais">Biais initial</param> /// <returns>L'erreur du réseau à la fin de son entraînement</returns> public double Entrainer(double[][] tests, double[][] cibles, int maxIteration, double pas, double maxErreur) { // Note: pour la suite on supposera qu'il n'y a qu'une seule couche cachée // inspiré de: // https://www4.rgu.ac.uk/files/chapter3%20-%20bp.pdf // https://www.youtube.com/watch?v=I2I5ztVfUSE Couche coucheSortie = Couches[Couches.Length - 1]; Couche coucheCachee = Couches[Couches.Length - 2]; Couche coucheEntree = Couches[0]; // erreur faite par le réseau double erreurReseau = 0; // important: ne pas inverser les deux boucles for // sinon on aura au final entraîné le réseau uniquement pour le dernier jeu de test et non pas le jeu complet for (int m = 0; m < maxIteration; m++) { Debug.WriteLine("Itération: " + m.ToString()); erreurReseau = 0; for (int t = 0; t < tests.Length; t++) { #region Passe avant // calcul d'un état du réseau (Somme et Sortie) Calculer(tests[t]); //Helper.AfficherReseau(this); #endregion #region Passe rétro // calcul des gradiants de la couche de sortie CalculerDeltaO(cibles[t]); //CalculerDeltaO(cibles[c]); // calculer des radiants de la couche cachée CalculerDeltaH(coucheCachee, coucheSortie); // recalculer les poids et les biais de la couche de sortie Propager(coucheCachee, coucheSortie, pas); // recalculer les poids et les biais de la couche cachée Propager(coucheEntree, coucheCachee, pas); #endregion //Helper.AfficherReseau(this); } // pour chaque test // le réseau a t'il convergé? for (int t = 0; t < tests.Length; t++) { Calculer(tests[t]); // calcule l'erreur qui doit converger vers la valeur cible 'maxErreur' double erreur = 0.0; for (int i = 0; i < coucheSortie.Neurones.Length; i++) { // TODO: en l'état Cibles n'est pas adapté au cas de réseau avec une couche de sortie à plusieurs neurones //double ecart = cibles[c][i] - coucheSortie.Neurones[i].Sortie; double ecart = cibles[t][i] - coucheSortie.Neurones[i].Sortie; erreur += ecart * ecart; } erreurReseau += erreur; } erreurReseau = 0.5 * Math.Sqrt(erreurReseau / tests.Length); //Console.WriteLine("Erreur réseau: {0}", erreurReseau); if (erreurReseau <= maxErreur) { break; } } // pour chaque itération return(erreurReseau); }