2

I have written a simple Artificial Neural Network in Java as part of a project. When I begin training the data (Using a training set i gathered) The error count in each epoch quickly stabilizes (to around 30% accuracy) and then stops. When testing the ANN all outputs for any given input are EXACTLY the same.

I am trying to output a number between 0 and 1 (0 to classify a stock as a faller and 1 to classify a riser - 0.4-0.6 should indicate stability)

When adding the same training data into RapidMiner Studios a proper ANN with much greater (70+%) Accuracy is created, therefore I know that the dataset is fine. There must be some problem in the ANN logic.

Below is the code for running and adjusting the weights. Any and all help appreciated!

    public double[] Run(double[] inputs) {
    //INPUTS
    for (int i = 0; i < inputNeurons.length; i++) {
        inputNeurons[i] = inputs[i];
    }

    for (int i = 0; i < hiddenNeurons.length; i++) {
        hiddenNeurons[i] = 0;
    } //RESET THE HIDDEN NEURONS

    for (int e = 0; e < inputNeurons.length; e++) {
        for (int i = 0; i < hiddenNeurons.length; i++) {
            //Looping through each input neuron connected to each hidden neuron

            hiddenNeurons[i] += inputNeurons[e] * inputWeights[(e * hiddenNeurons.length) + i];
            //Summation (with the adding of neurons)  - Done by taking the sum of each (input * connection weight)
            //The more weighting a neuron has the more "important" it is in decision making
        }
    }

    for (int j = 0; j < hiddenNeurons.length; j++) {
        hiddenNeurons[j] = 1 / (1 + Math.exp(-hiddenNeurons[j]));
        //sigmoid function transforms the output into a real number between 0 and 1
    }

    //HIDDEN
    for (int i = 0; i < outputNeurons.length; i++) {
        outputNeurons[i] = 0;
    } //RESET THE OUTPUT NEURONS

    for (int e = 0; e < hiddenNeurons.length; e++) {
        for (int i = 0; i < outputNeurons.length; i++) {
            //Looping through each hidden neuron connected to each output neuron

            outputNeurons[i] += hiddenNeurons[e] * hiddenWeights[(e * outputNeurons.length) + i];
            //Summation (with the adding of neurons) as above
        }
    }

    for (int j = 0; j < outputNeurons.length; j++) {
        outputNeurons[j] = 1 / (1 + Math.exp(-outputNeurons[j])); //sigmoid function as above
    }

    double[] outputs = new double[outputNeurons.length];
    for (int j = 0; j < outputNeurons.length; j++) {
        //Places all output neuron values into an array
        outputs[j] = outputNeurons[j];
    }
    return outputs;
}

public double[] CalculateErrors(double[] targetValues) {
    //Compares the given values to the actual values
    for (int k = 0; k < outputErrors.length; k++) {
        outputErrors[k] = targetValues[k] - outputNeurons[k];
    }
    return outputErrors;
}

    public void tuneWeights() //Back Propagation
{
    // Start from the end - From output to hidden
    for (int p = 0; p < this.hiddenNeurons.length; p++)     //For all Hidden Neurons
    {
        for (int q = 0; q < this.outputNeurons.length; q++)  //For all Output Neurons
        {
            double delta = this.outputNeurons[q] * (1 - this.outputNeurons[q]) * this.outputErrors[q];
            //DELTA is the error for the output neuron q
            this.hiddenWeights[(p * outputNeurons.length) + q] += this.learningRate * delta * this.hiddenNeurons[p];
            /*Adjust the particular weight relative to the error
             *If the error is large, the weighting will be decreased
             *If the error is small, the weighting will be increased
             */
        }
    }

    // From hidden to inps -- Same as above
    for (int i = 0; i < this.inputNeurons.length; i++)       //For all Input Neurons
    {
        for (int j = 0; j < this.hiddenNeurons.length; j++)  //For all Hidden Neurons
        {
            double delta = this.hiddenNeurons[j] * (1 - this.hiddenNeurons[j]);
            double x = 0;       //We do not have output errors here so we must use extra data from Output Neurons
            for (int k = 0; k < this.outputNeurons.length; k++) {
                double outputDelta = this.outputNeurons[k] * (1 - this.outputNeurons[k]) * this.outputErrors[k];
                //We calculate the output delta again
                x = x + outputDelta * this.hiddenWeights[(j * outputNeurons.length) + k];
                //We then calculate the error based on the hidden weights (x is used to add the error values of all weights)
                delta = delta * x;
            }
            this.inputWeights[(i * hiddenNeurons.length) + j] += this.learningRate * delta * this.inputNeurons[i];
            //Adjust weight like above
        }
    }
}
Matthew Cassar
  • 223
  • 2
  • 5
  • 13
  • 1
    How do you initialize weights? Aren't they all 0 in the begining? – Marcin Możejko Apr 20 '16 at 19:05
  • Tried that with the same results, at the moment they are being randomly initialized between -1 and 1 – Matthew Cassar Apr 22 '16 at 09:14
  • Beacuse if you initialize them all with 0s you may get such effect (that your network will simply stuck in this configuration). Is it working now (after random initialization)? – Marcin Możejko Apr 22 '16 at 09:17
  • No :/ exact same results. I can't understand how all inputs cause the same outputs – Matthew Cassar Apr 22 '16 at 12:37
  • And what kind of outputs do you get? Are you 100% that weights are not initialized to 0? – Marcin Możejko Apr 24 '16 at 20:17
  • I am 100% sure, I even added a check which doesn't allow 0, and another one where it doesn't allow values between 0 and 0.05. Both secnarios didn't work – Matthew Cassar Apr 25 '16 at 11:22
  • And what are those outputs which you get every time? – Marcin Możejko Apr 25 '16 at 20:16
  • it's different every time I train the neural net I just ran it now to check for you - the outputs all came between 0.44 and 0.47 as you can see here where is written | OUT - https://gyazo.com/a9f923a33deeb64188d0355db6950fa4 This is slightly better than previous results – Matthew Cassar Apr 26 '16 at 13:02
  • How long have you trained this model? What was the learning rate? Have you used the additional bias term? This screen shows that your model might be bad. – Marcin Możejko Apr 26 '16 at 19:15
  • I'm using the following - 7 Hidden neurons (Tried all amounts from 3-8), Learning rate of .25 which decreases to .2 after a number of epochs, and no I have not used bias I do suspect that there is a logical problem in my model – Matthew Cassar Apr 28 '16 at 10:25
  • But Dude - not using bias is reeeaaaally bad idea. You also have to babysit your learning process. – Marcin Możejko Apr 28 '16 at 11:01
  • Okay, so what would I have to do to add a bias, I've heard it's useful but this is my first attempt at anything AI related – Matthew Cassar Apr 28 '16 at 11:03

1 Answers1

2

After long coversation I think that you may find an answer to your question in the following points :

  1. Bias is really important. Actually - one of the most popular SO questions about neural network is about bias :) : Role of Bias in Neural Networks
  2. You should babysit your learning process. It's good to keep track of your test on accuracy and validation set and to use appropriate learning rate during training. What I advise you is to use simpler dataset when you know that it is easy to find true solution (for example - a triangle or square - use 4 - 5 hidden units then). I also advise you to use the following playgroud :

http://playground.tensorflow.org/#activation=tanh&batchSize=10&dataset=circle&regDataset=reg-plane&learningRate=0.03&regularizationRate=0&noise=0&networkShape=4,2&seed=0.36368&showTestData=false&discretize=false&percTrainData=50&x=true&y=true&xTimesY=false&xSquared=false&ySquared=false&cosX=false&sinX=false&cosY=false&sinY=false&collectStats=false&problem=classification

Community
  • 1
  • 1
Marcin Możejko
  • 39,542
  • 10
  • 109
  • 120