J'essaye d'écrire une MLP qui classe l'entrée dans trois objets. J'ai un nombre qui représente chaque objet.Le perceptron multicouche choisit toujours la dernière classe qu'il a été formé pour spécifier. Backpropagation
1-10 : Banana
11-20 : Apple
21:30 : Carrot
Il n'y a que deux couches MLP: une couche cachée (2 unités) et une couche de sortie (3 unités).
Chaque unité a:
-
entrées
- [] (entrées qui ont été transmises à cette unité)
- poids []
- delta
- somme (résumées poids d'entrées)
- sortie (somme activé)
également chaque unité a une fonction d'activation:
double activate(double[] inputs) {
this.inputs = inputs;
sum = 0;
for (int i = 0; i < inputs.length; i++)
sum += weights[i] * inputs[i];
output = 1.0/(1.0 + (Math.exp(-sum))); // activation
return output;
}
et une fonction pour corriger les poids:
void correctWeights(double momentum, double learningRate) {
for (int i = 0; i < weights.length; i++) {
weights[i] = weights[i] * momentum + learningRate * delta * (output * (1 - output)) * inputs[i];
}
}
où (output * (1 - output))
est dérivé.
Pour former le réseau j'ai une fonction qui boucle N fois, dans la boucle je génère l'entrée par rapport à l'objet, puis le propager au réseau et utiliser la rétropropagation.
private void train() {
for (int i = 0; i < 10000; i++) {
int[] expectedOutput = new int[3];
double[] inputs = {ThreadLocalRandom.current().nextInt(1, 30 + 1)};
if (inputs[0] <= 10) {
expectedOutput[0] = 1;
expectedOutput[1] = 0;
expectedOutput[2] = 0;
}
if (inputs[0] <= 20 && inputs[0] > 10) {
expectedOutput[0] = 0;
expectedOutput[1] = 1;
expectedOutput[2] = 0;
}
if (inputs[0] <= 30 && inputs[0] > 20) {
expectedOutput[0] = 0;
expectedOutput[1] = 0;
expectedOutput[2] = 1;
}
double[] outputs = propagate(inputs);
backPropagate(expectedOutput, outputs);
}
}
La fonction de propagation parcourt tout le réseau et active les unités.
private double[] propagate(double[] inputs) {
double[] hiddenOutputs = new double[hiddenLayer.length];
for (int i = 0; i < hiddenLayer.length; i++)
hiddenOutputs[i] = hiddenLayer[i].activate(inputs);
double[] outputs = new double[outputLayer.length];
for (int i = 0; i < outputs.length; i++)
outputs[i] = outputLayer[i].activate(hiddenOutputs);
return outputs;
}
algorithme de rétropropagation a été prise de http://home.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html
private void backPropagate(int[] expectedOutput, double[] output) {
for (int i = 0; i < outputLayer.length; i++) {
outputLayer[i].setDelta(expectedOutput[i] - output[i]);
}
for (int i = 0; i < hiddenLayer.length; i++) {
double delta = 0;
for (int j = 0; j < outputLayer.length; j++) {
delta += outputLayer[j].getDelta() * outputLayer[j].getWeight(i);
}
hiddenLayer[i].setDelta(delta);
}
for (int i = 0; i < hiddenLayer.length; i++)
hiddenLayer[i].correctWeights(momentum, learningRate);
for (int i = 0; i < outputLayer.length; i++)
outputLayer[i].correctWeights(momentum, learningRate);
}
Il a également une fonction de reconnaître des objets après avoir obtenu une formation
private void recognize(String number) {
double[] inputs = {Double.parseDouble(number)};
double[] outputs = propagate(inputs);
System.out.println("Banana: " + outputs[0]);
System.out.println("Apple: " + outputs[1]);
System.out.println("Carrot: " + outputs[2]);
}
Le problème est que quand je passe une numéro à la reconnaître fonction que je reçois la sortie semblable à ceci:
Banana: 0.49984367018594233
Apple: 0.49984367018594233
Carrot: 0.5001563298140577
La carotte est choisie à chaque fois (aussi la carotte est le dernier objet entraîné par le filet). Donc, si je saisis 5, il sortira que c'est une carotte. si je saisis 15, il sortira que c'est une carotte. Si je change l'ordre des objets qui sont en train d'apprendre dans train et que la banane soit le dernier objet appris alors le net choisira toujours la banane comme réponse.
Je travaille sur cela depuis quelques jours maintenant et je n'ai pas trouvé de solution, s'il vous plaît aidez-moi, qu'est-ce que je fais mal?
Il est très important de mélanger vos données, c'est-à-dire de sélectionner au hasard un nombre entre 1 et 30 comme entrée et de créer l'étiquette correspondante dans * chaque * itération. – hbaderts
@hbaderts que voulez-vous dire? voulez-vous dire la production attendue aux intrants? –
Vous ne devriez pas 1) passer à travers toutes les bananes, 2) passer à travers toutes les pommes, 3) passer à travers toutes les carottes. Si vous avez un tableau d'entrée, mélangez les lignes, ou lorsque vous générez vos données à la volée, créez aléatoirement des bananes/pommes/carottes à chaque itération. – hbaderts