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 !