2010-11-16 42 views
2

J'essaie d'enseigner un réseau neuronal de 2 entrées, 4 nœuds cachés (tous dans la même couche) et 1 nœud de sortie. La représentation binaire fonctionne bien, mais j'ai des problèmes avec le bipolaire. Je ne peux pas comprendre pourquoi, mais l'erreur totale convergera parfois vers le même nombre autour de 2.xx. Mon sigmoïde est 2/(1+ exp (-x)) - 1. Peut-être que je suis en train de stigmatiser au mauvais endroit. Par exemple, pour calculer l'erreur de sortie, dois-je comparer la sortie sigmoided avec la valeur attendue ou avec la valeur attendue sigmoided?Enseigner un réseau neuronal: Bipolar XOR

Je suivais ce site Web ici: http://galaxy.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html, mais ils utilisent des fonctions différentes que j'ai été chargé d'utiliser. Même lorsque j'ai essayé d'implémenter leurs fonctions, j'ai toujours rencontré le même problème. De toute façon, je suis coincé environ la moitié du temps au même numéro (un nombre différent pour différentes implémentations). S'il vous plaît dites-moi si j'ai fait une erreur dans mon code quelque part ou si c'est normal (je ne vois pas comment cela pourrait être). Momentum est mis à 0. Est-ce un problème d'élan 0 commun? Les fonctions d'erreur que nous sommes censés être à l'aide sont:

si ui est une unité de sortie

Error(i) = (Ci - ui) * f'(Si)

si ui est une unité cachée

Error(i) = Error(Output) * weight(i to output) * f'(Si)

public double sigmoid(double x) { 
    double fBipolar, fBinary, temp; 
    temp = (1 + Math.exp(-x)); 
    fBipolar = (2/temp) - 1; 
    fBinary = 1/temp; 
    if(bipolar){ 
     return fBipolar; 
    }else{ 
     return fBinary; 
    } 

} 

// Initialize the weights to random values. 
private void initializeWeights(double neg, double pos) { 
    for(int i = 0; i < numInputs + 1; i++){ 
     for(int j = 0; j < numHiddenNeurons; j++){ 
      inputWeights[i][j] = Math.random() - pos; 
      if(inputWeights[i][j] < neg || inputWeights[i][j] > pos){ 
       print("ERROR "); 
       print(inputWeights[i][j]); 
      } 
     } 
    } 
    for(int i = 0; i < numHiddenNeurons + 1; i++){ 
     hiddenWeights[i] = Math.random() - pos; 
     if(hiddenWeights[i] < neg || hiddenWeights[i] > pos){ 
      print("ERROR "); 
      print(hiddenWeights[i]); 
     } 
    } 
} 

// Computes output of the NN without training. I.e. a forward pass 
public double outputFor (double[] argInputVector) { 
    for(int i = 0; i < numInputs; i++){ 
     inputs[i] = argInputVector[i]; 
    } 
    double weightedSum = 0; 
    for(int i = 0; i < numHiddenNeurons; i++){ 
     weightedSum = 0; 
     for(int j = 0; j < numInputs + 1; j++){ 
      weightedSum += inputWeights[j][i] * inputs[j]; 
     } 
     hiddenActivation[i] = sigmoid(weightedSum); 
    } 

    weightedSum = 0; 
    for(int j = 0; j < numHiddenNeurons + 1; j++){ 
     weightedSum += (hiddenActivation[j] * hiddenWeights[j]); 
    } 

    return sigmoid(weightedSum); 
} 

    //Computes the derivative of f 
public static double fPrime(double u){ 
    double fBipolar, fBinary; 
    fBipolar = 0.5 * (1 - Math.pow(u,2)); 
    fBinary = u * (1 - u); 
    if(bipolar){ 
     return fBipolar; 
    }else{ 
     return fBinary; 
    } 
} 

// This method is used to update the weights of the neural net. 
public double train (double [] argInputVector, double argTargetOutput){ 
    double output = outputFor(argInputVector); 
    double lastDelta; 

    double outputError = (argTargetOutput - output) * fPrime(output); 

    if(outputError != 0){ 
     for(int i = 0; i < numHiddenNeurons + 1; i++){ 
      hiddenError[i] = hiddenWeights[i] * outputError * fPrime(hiddenActivation[i]); 
      deltaHiddenWeights[i] = learningRate * outputError * hiddenActivation[i] + (momentum * lastDelta); 
      hiddenWeights[i] += deltaHiddenWeights[i]; 
     } 

     for(int in = 0; in < numInputs + 1; in++){ 
      for(int hid = 0; hid < numHiddenNeurons; hid++){ 
       lastDelta = deltaInputWeights[in][hid]; 
       deltaInputWeights[in][hid] = learningRate * hiddenError[hid] * inputs[in] + (momentum * lastDelta); 
       inputWeights[in][hid] += deltaInputWeights[in][hid]; 
      } 
     } 
    } 

    return 0.5 * (argTargetOutput - output) * (argTargetOutput - output); 
} 

Répondre

3

de codage général commentaires:

initializeWeights(-1.0, 1.0); 

peut ne pas obtenir les valeurs initiales attendues.

initializeWeights devraient probablement:

inputWeights[i][j] = Math.random() * (pos - neg) + neg; 
// ... 
hiddenWeights[i] = (Math.random() * (pos - neg)) + neg; 

au lieu de:

Math.random() - pos; 

pour que cela fonctionne:

initializeWeights(0.0, 1.0); 

et vous donne des valeurs initiales entre 0,0 et 1,0 plutôt qu'entre -1,0 et 0,0.

lastDelta est utilisé avant qu'il ne soit déclaré:

deltaHiddenWeights[i] = learningRate * outputError * hiddenActivation[i] + (momentum * lastDelta); 

Je ne sais pas si le + 1 sur numInputs + 1 et numHiddenNeurons + 1 sont nécessaires.

N'oubliez pas de faire attention à l'arrondi des ints: 5/2 = 2, pas 2,5! Utilisez plutôt 5.0/2.0. En général, ajoutez le .0 dans votre code lorsque la sortie devrait être un double. Plus important encore, avez-vous formé le NeuralNet assez longtemps? Essayez de l'exécuter avec numInputs = 2, numHiddenNeurons = 4, learningRate = 0,9 et pour 1 000 ou 10 000 fois.

En utilisant numHiddenNeurons = 2, il est parfois "bloqué" lorsque vous essayez de résoudre le problème XOR.