1

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]; 
     } 
    } 

(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?

+2

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

+0

@hbaderts que voulez-vous dire? voulez-vous dire la production attendue aux intrants? –

+1

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

Répondre

1

Je remarque que vous sélectionnez un nombre aléatoire compris entre 0 et 30 puis déterminez une sortie, mais vous oubliez de normaliser l'entrée. Les réseaux de neurones fonctionnent mieux si l'entrée est dans la plage de 0-1 (dépend de la fonction d'activation que vous utilisez).

Donc ce qu'il vous reste à faire est de faire normaliser cette entrée. Cela signifie, convertir les entrées de manière égale à un nombre compris entre 0 et 1.

Votre entrée est une valeur numérique, il vous suffit donc de choisir une valeur maximale avec laquelle vous divisez toutes les valeurs. Dans votre cas, cela peut être 30, car il n'y a pas d'entrée supérieure à 30. Ainsi, chaque numéro est converti comme suit:

10 -> 10/30 -> 0.33 
15 -> 15/30 -> 0.50 
etc. 

En savoir plus sur la normalisation here.