Tout d'abord, Bonjour à toutes et à tous !

Je sais qu'il existe beaucoup de postes sur les réseaux de neurones, surtout pour les XOR, donc je suis désolé si la question a déjà été posée malgré mes recherches sur le sujet.

Voila, après avoir passé des semaines sur des cours expliquant les réseaux de neurones et leurs applications, je me suis enfin décidé à en coder un en C.

Je l'ai donc codé, en réglant les problèmes un à un. Maintenant il marche, m'affichant bien des valeurs pour les différents cas du XOR. Mais pas les bonnes malheureusement. En effet, j'ai affiché l'erreur suivant les itérations et je me suis aperçu que celle-ce ne décroit plus ou très peu au alentours de 0.7...
Du coup, je me retrouve avec un XOR ou le premier cas donne 0 et les autres environ 0.6-0.7 et non 1 et 0.
J'ai beau cherché pourquoi l'erreur ne décroit plus au bout d'un moment, j'ai essayé de mettre des printf pour comprendre, mais je suis dans une impasse.

C'est pourquoi je viens demander de l'aide ici !

Voici mon réseau de neurones :
Code C : 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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "neural.h"
#include "Gaussian.h"
 
static ssize_t layerCount;
static int inputSize;
static int *layerSize;
static TransferFunction *transferFunction;
static double **layerOutput;
static double **layerInput;
static double **bias;
static double **delta;
static double **previousBiasDelta;
static double ***weight;
static double ***previousWeightDelta;
 
double Evaluate(TransferFunction tFunc, double input)
{
    switch(tFunc)
    {
        case None:
            return 0.0;
 
        case Sigmoid:
            return sigmoid(input);
 
        case Linear:
            return linear(input);
 
        default:
            return 0.0;
 
    }
}
 
double EvaluateDerivative(TransferFunction tFunc, double input)
{
    switch(tFunc)
    {
        case None:
            return 0.0;
 
        case Sigmoid:
            return sigmoidDerivative(input);
 
        case Linear:
            return linearDerivative(input);
 
        default:
            return 0.0;
 
    }
}
 
double sigmoid(double x)
{
    return 1.0 / (1.0 + exp(-x));
}
 
double sigmoidDerivative(double x)
{
    return sigmoid(x) * (1 - sigmoid(x));
}
 
double linear(double x)
{
    return x;
}
 
double linearDerivative(double x)
{
    return 1.0 + 0*x;
}
 
void Setup(int *layerSizes, TransferFunction *transferFunctions, int sizesLength, int funcLength)
{
    if(funcLength != sizesLength || transferFunctions[0] != None)
        printf("We cannot construct a network with this parameters");
 
    //Initialize network layers
    layerCount = sizesLength - 1;
    inputSize = layerSizes[0];
 
    layerSize = (int *)malloc(layerCount * sizeof(int));
    for(ssize_t i=0; i < layerCount; i++)
        layerSize[i] = layerSizes[i+1];
 
    transferFunction = (TransferFunction *)malloc(layerCount * sizeof(transferFunction));
    for(ssize_t i = 0; i < layerCount; i++)
        transferFunction[i] = transferFunctions[i+1];
 
    //Start dimensioning arrays
    bias = (double **)malloc(layerCount * sizeof (double*));
    previousBiasDelta = (double **)malloc(layerCount * sizeof (double*));
    delta = (double **)malloc(layerCount * sizeof (double*));
    layerOutput = (double **)malloc(layerCount * sizeof (double*));
    layerInput = (double **)malloc(layerCount * sizeof (double*));
 
    weight = (double ***)malloc(layerCount * sizeof (double**));
    previousWeightDelta = (double ***)malloc(layerCount * sizeof (double**));
 
    //Fill two dimensional arrays
    for(ssize_t l = 0; l < layerCount; l++)
    {
        bias[l] = (double *)malloc(layerSize[l] * sizeof (double));
        previousBiasDelta[l] = (double *)malloc(layerSize[l] * sizeof (double));
        delta[l] = (double *)malloc(layerSize[l] * sizeof (double));
        layerOutput[l] = (double *)malloc(layerSize[l] * sizeof (double));
        layerInput[l] = (double *)malloc(layerSize[l] * sizeof (double));
 
        weight[l] = (double **)malloc((l == 0 ? inputSize : layerSize[l-1]) * sizeof (double*));
        previousWeightDelta[l] = (double **)malloc((l == 0 ? inputSize : layerSize[l-1]) * sizeof (double*));
 
        for(int i = 0; i < (l == 0 ? inputSize : layerSize[l-1]); i++)
        {
            weight[l][i] = (double *)malloc(layerSize[l] * sizeof (double));
            previousWeightDelta[l][i] = (double *)malloc(layerSize[l] * sizeof (double));
        }
    }
 
    //Initialize the weights
    for(ssize_t l = 0; l < layerCount; l++)
    {
        for(int j = 0; j < layerSize[l]; j++)
        {
            bias[l][j] = GetRandomGaussian(-1.0, 1.0);
            previousBiasDelta[l][j] = 0.0;
            delta[l][j] = 0.0;
            layerOutput[l][j] = 0.0;
            layerInput[l][j] = 0.0;
        }
 
        for(int i = 0; i < (l == 0 ? inputSize : layerSize[l-1]); i++)
        {
            for(int j = 0; j < layerSize[l]; j++)
            {
                weight[l][i][j] = GetRandomGaussian(-1.0, 1.0);
                previousWeightDelta[l][i][j] = 0.0;
            }
        }
    }
 
 
}
 
void Run(double *input, int inputLength, double *output)
{
    if(inputLength != inputSize)
        printf("Input Data is not of the correct dimension !");
 
    //Create and Dimension
    //output = (double *)malloc(layerSize[layerCount - 1] * sizeof (double));
 
    //Run the Network
    for(ssize_t l = 0; l < layerCount; l++)
    {
        for(int j = 0; j < layerSize[l]; j++)
        {
            double sum = 0.0;
            for(int i = 0; i < (l == 0 ? inputSize : layerSize[l-1]); i++)
                sum += weight[l][i][j] * (l == 0 ? input[i] : layerOutput[l-1][i]);
 
            sum += bias[l][j];
            layerInput[l][j] = sum;
 
            layerOutput[l][j] = Evaluate(transferFunction[l], sum);
        }
    }
 
    //Copy the Output to the output array
    for(int i = 0; i < layerSize[layerCount - 1]; i++)
    {
        output[i] = layerOutput[layerCount - 1][i];
    }
}
 
double Train(double *input, int inputLength, double *desired, int desiredLength, double TrainingRate, double Momentum)
{
    //Parameter validation
    if(inputLength != inputSize)
        printf("Invalid input parameter");
 
    if(desiredLength != layerSize[layerCount-1])
        printf("Invalid desired parameter");
 
    //Local variables
    double error = 0.0, sum = 0.0, weightDelta = 0.0, biasDelta = 0.0;
    double *output = (double *)malloc(layerSize[layerCount - 1] * sizeof (double));
 
    //Run the Network
    Run(input, inputLength, output);
 
    //Back-propagate
    for(ssize_t l = layerCount - 1; l >= 0; l--)
    {
        //Output layer
        if(l == layerCount - 1)
        {
            for(int k = 0; k < layerSize[l]; k++)
            {
                delta[l][k] = output[k] - desired[k];
                error += pow(delta[l][k], 2);
                delta[l][k] *= EvaluateDerivative(transferFunction[l], layerInput[l][k]);
 
            }
        }
        else //Hidden layer
        {
            for(int i = 0; i < layerSize[l]; i++)
            {
                sum = 0.0;
                for(int j = 0; j < layerSize[l+1]; j++)
                {
                    sum += weight[l+1][i][j] * delta[l+1][j];
                }
                sum *= EvaluateDerivative(transferFunction[l], layerInput[l][i]);
 
                delta[l][i] = sum; 
            }
        }
    }
 
    //Update the weights and biases
    for(ssize_t l = 0; l < layerCount; l++)
        for(int i = 0; i < (l == 0 ? inputSize : layerSize[l-1]); i++)
            for(int j = 0; j < layerSize[l]; j++)
            {
                weightDelta = TrainingRate * delta[l][j] * (l == 0 ? input[i] : layerOutput[l-1][i])
                                + Momentum * previousWeightDelta[l][i][j];
                weight[l][i][j] -= weightDelta;
 
 
                previousWeightDelta[l][i][j] = weightDelta;
            }
 
    for(ssize_t l = 0; l < layerCount; l++)
        for(int i = 0; i < layerSize[l]; i++)
        {
            biasDelta = TrainingRate * delta[l][i];
            bias[l][i] -= biasDelta + Momentum * previousBiasDelta[l][i];
 
            previousBiasDelta[l][i] = biasDelta;
        }
 
    return error;
}

et voila mon main :
Code C : 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
        int *layerSizes = (int *)malloc(3 * sizeof (int));
        layerSizes[0] = 2; layerSizes[1] = 2; layerSizes[2] = 1;
 
        TransferFunction *tFuncs = (TransferFunction *)malloc(3 * sizeof (TransferFunction));
        tFuncs[0] = None; tFuncs[1] = Sigmoid; tFuncs[2] = Sigmoid;
 
        Setup(layerSizes, tFuncs, 3, 3);
 
        //Define the cases
        double **input = (double **)malloc(4 * sizeof (double *));
        double **output = (double **)malloc(4 * sizeof (double *));
 
        for(int i = 0; i < 4; i++)
        {
            input[i] = (double *)malloc(2 * sizeof (double));
            output[i] = (double *)malloc(1 * sizeof (double));
        }
 
        input[0][0] = 0.0; input[0][1] = 0.0; output[0][0] = 0.0; // false xor false = false
        input[1][0] = 1.0; input[1][1] = 0.0; output[1][0] = 1.0; // true xor false = true
        input[2][0] = 0.0; input[2][1] = 1.0; output[2][0] = 1.0; // false xor true = true
        input[3][0] = 1.0; input[3][1] = 1.0; output[3][0] = 0.0; // true xor true = false
 
        //Train the netork
        double error = 0.0;
        int max_count = 100000, count =0;
 
        do
        {
 
            count++;
            error = 0.0;
 
            for(int i = 0; i < 4; i++)
            {
                error += Train(input[i], 2, output[i], 1, 0.15, 0.10);
            }
 
            if(count % 10000 == 0)
            {
                printf("Iteration %d ----> Error : %f\n", count, error);
                //printf("Output[1] = %f\n", output[1]);
            }
 
        }while(error > 0.0001 && count <= max_count);
 
        //Display Results
        printf("\n");
        double *networkOutput = (double *)malloc(1 * sizeof (double));
 
        //Run(input[1], 2, networkOutput);
        //printf("Run en 1 -----> Output[1] = %f\n", networkOutput[0]);
 
        for(int i = 0; i < 4; i++)
        {
            Run(input[i], 2, networkOutput);
            printf("%f\n", networkOutput[0]);        
        }

Je vous remercie par avance de votre aide !

PS : J'ai oublié de vous donner le .h concernant la structure :
Code C : 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
typedef enum TransferFunction TransferFunction;
enum TransferFunction
{
    None,
    Sigmoid,
    Linear
};
 
double Evaluate(TransferFunction tFunc, double input);
double EvaluateDerivative(TransferFunction tFunc, double input);
double sigmoid(double x);
double sigmoidDerivative(double x);
double linear(double x);
double linearDerivative(double x);
 
void Setup(int *layerSizes, TransferFunction *transferFunctions, int sizesLength, int funcLength);
 
void Run(double *input, int inputLength, double *output);
double Train(double *input, int inputLength, double *desired, int desiredLength, double TrainingRate, double Momentum);