IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Réseau de neurones et rétro-propagation du gradient de l'erreur [Python 3.X]


Sujet :

Python

  1. #1
    Membre averti
    Homme Profil pro
    Développeur en formation
    Inscrit en
    Juillet 2013
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en formation
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juillet 2013
    Messages : 300
    Points : 413
    Points
    413
    Par défaut Réseau de neurones et rétro-propagation du gradient de l'erreur
    Bonjour !

    Je développe depuis quelques temps une classe qui doit me servir de base pour plusieurs autres programme : une classe "Réseau de Neurones" qui permet de générer très simplement un réseau de neurones avec des couches, une fonction d'activation, et des poids synaptiques. Bref, tout ce qu'il y a de plus banal. Jusque là, je pense avoir fait quelque chose qui marche à peu près.

    Mais quand j'ai voulu implémenter l'algorithme de rétro-propagation du gradient de l'erreur (voir ça ou ça), déjà uniquement pour les réseaux à 3 couches - pour tester, c'est là que j'ai dû me planter royalement. Les valeurs ne sont pas du tout celles attendues et avec certaines fonctions d'activation (j'en ai testé plusieurs comme vous pouvez le voir), ça finit par me donner des valeurs de plus en plus proche de l'infini, ou ou contraire de zéro... De plus, je me rends compte que quand je mets un seul neurone dans l'une des couches ou que je ne mets pas de couche cachée, le programme plante à cause d'un problème de taille de liste.

    Voici mon code, en espérant que vous arriverez à me suivre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    import random
    import math
     
     
    def f(x) :
        return 1/(1+math.e**(-x))
     
    def derivee(x) :
        return (math.e**(-x)) / ((1+math.e**(-x))**2)
     
    def f(x) :
        if x>=0 : return math.sqrt(x)
        else : return -math.sqrt(-x)
     
    def derivee(x) :
        if x>0 : return -0.5/math.sqrt(x)
        elif x==0 : return 0
        else : return 0.5/math.sqrt(-x)
     
     
     
    class ReseauDeNeurones :
        """Gere les principales fonctions d'un reseau de neurones."""
        def __init__( self, nb_neurones_par_couche=[10,8,1], valeur_par_defaut_synapses = "random.random()*2-1", fonction = f, derivee=derivee ) :
            """Constructeur de l'objet.
            nb_neurones_par_couche : liste contenant le nombre de neurones par couche
            le premier etant les entrees et le dernier les sorties
            valeur_par_defaut_synapses : contient la valeur par defaut des synapses sous la forme de str /!\
            fonction : fonction d'activation (sigmoide par defaut)"""
     
            self.f = self.fonction = fonction
            self.f_ = derivee
     
            self.couches = []#contient self.couches[couche][neurone][poids]
            for nb in range(len(nb_neurones_par_couche)-1) :
                     self.couches.append([])#une couche de plus
                     for i in range(nb_neurones_par_couche[nb]) :
                         self.couches[-1].append([])#un neurone de plus
                         for synapse in range(nb_neurones_par_couche[nb+1]) :
                             self.couches[nb][i].append(eval(valeur_par_defaut_synapses))
     
        def executer(self,*entrees) :
            """Execute le reseau de neurones avec les entrees donnees (qui doivent etre egales au nombre de neurones).
            Les neurones de sortie et d'entree n'appliquent pas la fonction d'activation."""
            sortie=[0]*len(self.couches[1])
            for i in range(len(entrees)) :
                     entree=self.f(entrees[i])
                     for ii in range(len(self.couches[0][i])) :
                         poids = self.couches[0][i][ii]
                         sortie[ii]+=poids*entree
     
            for couche in self.couches[1:] :
                sortie,entrees = [0]*len(couche[0]), sortie
                for i in range(len(entrees)) :
                     entree=self.fonction(entrees[i])
                     for ii in range(len(couche[i])) :
                         poids = couche[i][ii]
                         sortie[ii]+=poids*entree
            return [self.f(v) for v in sortie]
     
        def _executer_(self,*entrees) :
            """Execute le reseau de neurones avec les entrees donnees (qui doivent etre egales au nombre de neurones).
            Les neurones de sortie et d'entree n'appliquent pas la fonction d'activation.
            fonction renvoyant les sorties des differentes couches"""
            S = []
            sortie=[0]*len(self.couches[1])
            for i in range(len(entrees)) :
                     entree=self.f(entrees[i])
                     for ii in range(len(self.couches[0][i])) :
                         poids = self.couches[0][i][ii]
                         sortie[ii]+=poids*entree
            S.append(list(sortie))
     
            for couche in self.couches[1:] :
                sortie,entrees = [0]*len(couche[0]), sortie
                for i in range(len(entrees)) :
                     entree=self.fonction(entrees[i])
                     for ii in range(len(couche[i])) :
                         poids = couche[i][ii]
                         sortie[ii]+=poids*entree
                S.append(list(sortie))
            return S #-> valeurs brutes sans seuillage par la fonction f
     
        def retropropagation(self, entree, sortie) :
            """entree -> entrees voulues
            sortie -> sortie voulue
            s -> sortie obtenue avant modification
            deja pour 3 couches"""
            nouveaux_poids = []
            for couche in range(len(self.couches)) :
                     nouveaux_poids.append([])
                     for neurone in self.couches[couche] :
                         nouveaux_poids[-1].append(list(neurone))
            s = self._executer_()
            #dernière couche : k
            E=[]
            for i in range(len(s[1])) : #i : position du neurone dans la couche 2 = sortie
                erreur_neurone = self.f_(s[1][i]) * ( sortie[i] - self.f(s[1][i]) )
                #on "repare" l'erreur
                for j in range(len(self.couches[1])) :
                    nouveaux_poids[1][j][i] -= erreur_neurone * self.couches[1][j][i]
                E.append(erreur_neurone)
     
            for i in range(len(s[0])) : #i : position du neurone dans la couche 1
                somme = 0
                for k in range(len(self.couches[1][i])) :
                    somme+=E[k]*self.couches[1][i][k]
     
                erreur = self.f_(s[0][i])*somme
     
                #on "repare" l'erreur
                for j in range(len(self.couches[0])) :
                    nouveaux_poids[0][j][i] -= erreur * self.couches[1][j][i]
     
            self.couches = nouveaux_poids
     
     
     
    a=ReseauDeNeurones([2,2,2])
    print(a.executer(1,3))
    for i in range(10) :
        a.retropropagation((1,3),(10,2))
        s=(1,3)
        print(s,a.executer(*s))
    Je vous en serais très reconnaissant si quelqu'un de plus calé que moi en mathématiques pouvait m'aider sur le coup (outre le problème de taille de liste que je devrais pouvoir résoudre).

    Merci d'avance et bonne année !

  2. #2
    Membre averti
    Homme Profil pro
    Développeur en formation
    Inscrit en
    Juillet 2013
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en formation
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juillet 2013
    Messages : 300
    Points : 413
    Points
    413
    Par défaut
    Quelqu'un pourrait-il m'expliquer clairement l'algorithme de rétropropagation s'il vous plaît ? A chaque fois que je cherche sur internet, j'en vois soit un qui est faux, soit un qui utilise des variables dont il n'explique pas la signification.

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 428
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 428
    Points : 37 010
    Points
    37 010
    Par défaut
    Citation Envoyé par stalacta Voir le message
    Quelqu'un pourrait-il m'expliquer clairement l'algorithme de rétropropagation s'il vous plaît ? A chaque fois que je cherche sur internet, j'en vois soit un qui est faux, soit un qui utilise des variables dont il n'explique pas la signification.
    C'est peut être une question à poser dans les forums Algo.

    - W

  4. #4
    Membre averti
    Homme Profil pro
    Développeur en formation
    Inscrit en
    Juillet 2013
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en formation
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juillet 2013
    Messages : 300
    Points : 413
    Points
    413
    Par défaut
    Merci, je vais le faire.

  5. #5
    Membre averti
    Homme Profil pro
    Développeur en formation
    Inscrit en
    Juillet 2013
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en formation
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juillet 2013
    Messages : 300
    Points : 413
    Points
    413
    Par défaut
    J'ai fini par réussir à en programmer une première version (marche uniquement avec une sigmoïde) grâce à une vidéo que je vous recommande vivement si vous vous demandez comment ça marche. C'est simplement expliqué avec un exemple, et en français québécois en plus !

    La voici et mon code aussi pour ceux que ça intéresse :



    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    import random
    import math
     
     
    def f(x) :
        try :
            return 1/(1+math.e**(-x))
        except OverflowError :
            return 0
     
    def derivee_partielle(x) :
        return 1-x
     
     
     
     
    class ReseauDeNeurones :
        """Gere les principales fonctions d'un reseau de neurones."""
        def __init__( self, nb_neurones_par_couche=[10,8,1], valeur_par_defaut_synapses = "random.random()*2-1", fonction = f, derivee=derivee_partielle ) :
            """Constructeur de l'objet.
            nb_neurones_par_couche : liste contenant le nombre de neurones par couche
            le premier etant les entrees et le dernier les sorties
            valeur_par_defaut_synapses : contient la valeur par defaut des synapses sous la forme de str /!\
            fonction : fonction d'activation (sigmoide par defaut)"""
     
            self.f = self.fonction = fonction
            self.f_ = derivee
     
            self.couches = []#contient self.couches[couche][neurone][poids]
            for nb in range(len(nb_neurones_par_couche)) :
                     self.couches.append([])#une couche de plus
                     for i in range(nb_neurones_par_couche[nb]) :
                         self.couches[nb].append([])#un neurone de plus
                         try :
                             for synapse in range(nb_neurones_par_couche[nb+1]) :
                                 self.couches[nb][i].append(eval(valeur_par_defaut_synapses))
                         except :
                             pass
     
        def executer(self,*entrees) :
            """Execute le reseau de neurones avec les entrees donnees (qui doivent etre egales au nombre de neurones).
            Les neurones de sortie et d'entree n'appliquent pas la fonction d'activation."""
            #https://www.youtube.com/watch?v=0jh-jlWfKwo
     
            a=[[]] #a[layer][neurone] -> valeur sortie neurone
            for i in range(len(self.couches[0])) :
                a[0].append(entrees[i])
     
            in_=[[]] #in[layer][neurone] -> valeur entree neurone
            for l in range(1,len(self.couches)) :
                a.append([])
                in_.append([])
                for j in range(len(self.couches[l])) :
                    in_[l].append(0)
                    for i in range(len(self.couches[l-1])) :
                        in_[l][j] += a[l-1][i] * self.couches[l-1][i][j]
                    a[l].append(self.f(in_[l][j]))
     
            return a[-1]
            #return in_[-1]
     
     
     
        def retropropagation(self, entrees, sortie, taux=0.1) :
            """entrees -> entrees voulues
            sortie -> sortie voulue
            taux -> taux d'apprentissage"""
            #1) propagation normale
     
            a=[[]] #a[layer][neurone] -> valeur sortie neurone
            for i in range(len(self.couches[0])) :
                a[0].append(entrees[i])
     
            in_=[[]] #in[layer][neurone] -> valeur entree neurone
            for l in range(1,len(self.couches)) :
                a.append([])
                in_.append([])
                for j in range(len(self.couches[l])) :
                    in_[l].append(0)
                    for i in range(len(self.couches[l-1])) :
                        in_[l][j] += a[l-1][i] * self.couches[l-1][i][j]
                    a[l].append(self.f(in_[l][j]))
     
     
            #2) retropropagation
     
            delta=[[]]*len(self.couches) #delta[layer][neurone] -> erreur
            for j in range(len(self.couches[-1])) :
                delta[-1].append(sortie[j]-a[-1][j])
            for l in range(len(self.couches)-2, 0, -1) :
                for i in range(len(self.couches[l])) :
                    delta[l].append( a[l][i] * (1-a[l][i]) )
                    v=0
                    for j in range(len(self.couches[l+1])) :
                        v+=delta[l+1][j]*self.couches[l][i][j]
                    delta[l][i]*=v
     
            for l in range(len(self.couches)-1) :
                for i in range(len(self.couches[l])) :
                    for j in range(len(self.couches[l+1])) :
                        self.couches[l][i][j] += taux * a[l][i] * delta[l+1][j]

  6. #6
    Nouveau Candidat au Club
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Décembre 2018
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Nièvre (Bourgogne)

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2018
    Messages : 1
    Points : 1
    Points
    1
    Par défaut
    bonjour,

    Merci pour ce programme beaucoup plus intuitif que tout ceux que j'ai pu trouver.
    Je m'interresse enormement aux reseaux de neurones mais j'eprouve des difficultés à les implementer (en python) et davantage à utiliser des API.

    J'aurais quelques questions sur le programme:

    Est il possible de choisir le nombre de couches, neurones (dont entrées) ?
    J'ai cherché dans le script mais mon niveau est vraisemblablement trop juste pour tout apprehender.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Calcul des coefficients d'un réseau de neurones avec rétro-actions
    Par rei.uchiwa dans le forum Méthodes prédictives
    Réponses: 2
    Dernier message: 20/03/2012, 21h23
  2. Réponses: 1
    Dernier message: 20/06/2011, 12h08
  3. Réponses: 11
    Dernier message: 04/03/2010, 00h19
  4. Réponses: 1
    Dernier message: 09/02/2010, 10h13
  5. rétro-propagation du gradient
    Par vincent.mbg dans le forum Méthodes prédictives
    Réponses: 8
    Dernier message: 08/09/2008, 16h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo