Click here to Skip to main content
15,890,845 members
Please Sign up or sign in to vote.
3.00/5 (2 votes)
See more:
Hello all,

I am in the middle of making a most simplest generic algorithm for the multiple input and multiple output for training ANN using Backpropagation - but I have some non-converging error problem. Could someone go over my code and see what I did wrong?

FYI - I am not using the momentum method. i.e, I set that to 1.
And, the network is 3-6-2 (input-hidden_node-output)

Thanks

Here is the code,

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BackProbagationAlgor
{
    class Program
    {
        // step 1: initilize data
        static double w = 0.02; // connection weight
        static double Emax = 0.0001; // max error tolerate
        static double E = 0; // initial error
        static double zeta = 0.02; // learning rate

        static int numberInputNeuron = 3;
        // static int numberHiddenLayer = 1;
        static int numberHiddenNodeInEachLayer = 6;
        static int numberOutputNeuron = 2;
        static int numberTrainingPatterns = 4;

        static double[] errThisPat = new double[numberOutputNeuron];// set to 1 as first start
        static int patNum = 0;

        static double[] deltaO = new double[numberOutputNeuron]; // error signal for output layer
        static double[] deltaH = new double[numberHiddenNodeInEachLayer];
        static int epoch = 0; // count number of epoch. Has to go to 1 epoch at lease

        static void Main(string[] args)
        {
            try
            {
                epoch = 0;
                initData();

                //while (errThisPat[1] >= Emax || errThisPat[2] >= Emax || epoch < 1)
                while (errThisPat[0] >= Emax || errThisPat[1] > Emax || epoch < 1)
                {
                    for (int i = 0; i < numberTrainingPatterns; i++)
                    {
                        patNum = i;
                        trainData();
                    }
                    epoch++;
                }

                // Write to display the connection weight after all calculation
                for (int i = 0; i < numberOutputNeuron; i++)
                {
                    for (int j = 0; j < numberHiddenNodeInEachLayer; j++)
                    {
                        Console.WriteLine("Weight" + i + j + " is " + weightHO[i, j]);
                    }
                }

                for (int k = 0; k < numberHiddenNodeInEachLayer; k++)
                {
                    for (int l = 0; l < numberInputNeuron; l++)
                    {
                        Console.WriteLine("Weight" + k + l + " is " + weightIH[k, l]);
                    }
                }
                // end write display connection weight
            }
            catch
            {
                Console.WriteLine("Eror at Main");
            }

            tryOutPut();

            Console.Read();
        }

        static double[,] input = new double[numberTrainingPatterns, numberInputNeuron]; // input data array
        static double[,] output = new double[numberTrainingPatterns, numberOutputNeuron]; // output data array

        static double[,] try_input = new double[4, numberInputNeuron]; // set of test data input to see if the network can produce the correct result after trained
        static double[,] try_output = new double[4, numberOutputNeuron]; // // set of test data input to see if the network can produce the correct result after trained

        static double[] outputOfEachNuron = new double[numberHiddenNodeInEachLayer]; // place holder for calculating of output at each neuron in the hidden layer
        static double[,] weightIH = new double[numberHiddenNodeInEachLayer, numberInputNeuron]; // connective weight between input and hidden nodes
        static double[,] weightHO = new double[numberOutputNeuron, numberHiddenNodeInEachLayer]; // connective weight between hidden and output nodes
        static double[,] outputTemp = new double[numberHiddenNodeInEachLayer, numberOutputNeuron];// temporay array to store the output of each hidden node

        static Random randNum = new Random();
        // step 2: apply input
        public static void initData()
        {
            // set learning rate for HO
            for (int i = 0; i < numberOutputNeuron; i++)
            {
                errThisPat[i] = 1;//initilize error compued from a pattern of data set
                for (int j = 0; j < numberHiddenNodeInEachLayer; j++)
                {
                    weightHO[i, j] = randNum.NextDouble();
                }
            }

            // set learning rate for IH
            for (int k = 0; k < numberHiddenNodeInEachLayer; k++)
            {
                for (int l = 0; l < numberInputNeuron; l++)
                {
                    weightIH[k, l] = randNum.NextDouble();
                }
            }

            // training data
            input[0, 0] = 1;
            input[0, 1] = -1;
            input[0, 2] = 1;
            output[0, 0] = 1; // xor
            output[0, 1] = 1; // xor

            input[1, 0] = -1;
            input[1, 1] = 1;
            input[1, 2] = 1;
            output[1, 0] = 1;
            output[1, 1] = 1;

            input[2, 0] = 1;
            input[2, 1] = 1;
            input[2, 2] = 1;
            output[2, 0] = -1;
            output[2, 1] = -1;

            input[3, 0] = -1;
            input[3, 1] = -1;
            input[3, 2] = 1;
            output[3, 0] = -1;
            output[3, 1] = -1;
        }

        static int flag = 0;
        // static double[] delta
        public static void trainData()
        {
            try
            {
                // step 3: forward probagation
                // calculate the output of each neuron in the hidden layer
                for (int i = 0; i < numberHiddenNodeInEachLayer; i++)
                {
                    outputOfEachNuron[i] = 0; // clare array before use
                    for (int j = 0; j < numberInputNeuron; j++)
                    {
                        outputOfEachNuron[i] = outputOfEachNuron[i] + (input[patNum, j] * weightIH[i, j]);
                    }
                    outputOfEachNuron[i] = Math.Tanh(outputOfEachNuron[i]);
                }

                // calculate the output of each neuron in the output layer
                for (int i = 0; i < numberOutputNeuron; i++)
                {
                    flag = i;
                    //outputTemp[i, 0] = 0;
                    double outputTempHolder = 0;
                    for (int j = 0; j < numberHiddenNodeInEachLayer; j++)
                    {
                        outputTempHolder = outputTempHolder + outputOfEachNuron[j] * weightHO[i, j]; // output of 1 output neuron
                    }

                    // step 4: calculate the error
                    errThisPat[i] = 0.5 * Math.Pow(output[patNum, i] - outputTempHolder, 2) + E;
                    Console.WriteLine("Epoch = " + epoch + " EMS" + i + " = " + errThisPat[i]);

                    // compute the error signal of the output neuron
                    deltaO[i] = (1 + outputTempHolder) * (1 - outputTempHolder);// derivative of tanh

                    // step 5: Back probagation
                    // update weight of 3rd layer
                    updateWeightHO(deltaO[i], i);
                }

                // 2nd layer update
                updateWeightIH();
            }
            catch
            {
                Console.WriteLine("error");
            }
        }

        public static void updateWeightHO(double _delta, int n)
        {
            try
            {
                // 3rd layer weigh update
                for (int j = 0; j < numberHiddenNodeInEachLayer; j++)
                {
                    double weightChangeHO = zeta * _delta * outputOfEachNuron[j];
                    weightHO[n, j] = weightChangeHO + weightHO[n, j];
                }
            }
            catch { Console.WriteLine("Eror updateWeightHO"); }
        }

        public static void updateWeightIH()
        {
            try
            {
                for (int i = 0; i < numberHiddenNodeInEachLayer; i++)
                {
                    double temp = (1 + outputOfEachNuron[i]) * (1 - outputOfEachNuron[i]);//outputOfEachNuron[i] * (1 - outputOfEachNuron[i]);// holds the temp output of the tanh-derivative which is [(1-O)*(1+O)]
                    deltaH[i] = 0; // not sufficient - may need to clear the array at the beginnin of this loop
                    for (int j = 0; j < numberOutputNeuron; j++)
                    {
                        deltaH[i] += weightHO[j, i] * deltaO[j];
                    }
                    deltaH[i] = deltaH[i] * temp;
                }

                // update 2nd layer weight
                for (int k = 0; k < numberInputNeuron; k++)
                {
                    for (int l = 0; l < numberHiddenNodeInEachLayer; l++)
                    {
                        weightIH[l, k] = (zeta * deltaH[l] * input[patNum, k]) + weightIH[l, k]; // weight_new = weight_old + delta_weight
                    }
                }
            }
            catch { Console.WriteLine("Eror updateWeightIH"); }
        }

        static double[,] tryouput = new double[4, numberOutputNeuron];// should change 4 to correct number of data of try_output
        
        // this method will only run after the error converge, so for now, not to worry about this method
        public static void tryOutPut()
        {
            // testing data to see if ANN gives correct result after trained
            try_input[0, 0] = 1;
            try_input[0, 1] = -1;
            try_input[0, 2] = 1;
            try_output[0, 0] = 1; // xor
            try_output[0, 1] = 1; // xor

            try_input[1, 0] = -1;
            try_input[1, 1] = 1;
            try_input[1, 2] = 1;
            try_output[1, 0] = 1;
            try_output[1, 1] = 1;

            try_input[2, 0] = 1;
            try_input[2, 1] = 1;
            try_input[2, 2] = 1;
            try_output[2, 0] = -1;
            try_output[2, 1] = -1;

            try_input[3, 0] = -1;
            try_input[3, 1] = -1;
            try_input[3, 2] = 1;
            try_output[3, 0] = -1;
            try_output[3, 1] = -1;

            int tryoutputPat = 4;

            for (int x = 0; x < tryoutputPat; x++) // loop through all the try_ouput data sets
            {
                // calculate the output of each neuron in the hidden layer
                for (int i = 0; i < numberHiddenNodeInEachLayer; i++)
                {
                    outputOfEachNuron[i] = 0; // clare array before use
                    for (int j = 0; j < numberInputNeuron; j++)
                    {
                        outputOfEachNuron[i] = outputOfEachNuron[i] + (input[x, j] * weightIH[i, j]);
                    }
                    outputOfEachNuron[i] = Math.Tanh(outputOfEachNuron[i]);
                }

                // calculate the output of each neuron in the output layer
                for (int i = 0; i < numberOutputNeuron; i++)
                {
                    flag = i;
                    //outputTemp[i, 0] = 0;
                    double outputTempHolder = 0;
                    for (int j = 0; j < numberHiddenNodeInEachLayer; j++)
                    {
                        outputTempHolder = outputTempHolder + outputOfEachNuron[j] * weightHO[i, j]; // output of 1 output neuron
                        Console.WriteLine("");
                    }
                    tryouput[x, i] = outputTempHolder;
                    Console.WriteLine(" Set " + x + ": Target " + i + " is: " + try_output[x, i] + " ANN is " + tryouput[x, i]);
                }
            }
        }
    }
}
Posted
Comments
Sergey Alexandrovich Kryukov 6-Nov-12 14:14pm    
Do you mean "genetic", not "generic"?

I'm afraid I have insufficient knowledge on generic technologies, but I clearly see the problem with your question:

You don't explain what are you trying to achieve, what is expected behavior, what do you observe and why do you think it's wrong, what is the purpose and expected functionality of each method, other relevant explanations. Without this information, I doubt someone will even volunteer to read your pure code dump...
--SA
aznftw 6-Nov-12 14:33pm    
Thanks for your input, here is what I am after:

I have 4 training data patterns - and 4 expected target. I start by training the network using backpropagation. I'd first iterate through all the training pattern available and compute the output.

I then go back to loop again the above training process, and I'll stop when the errors between the ANN outputs and the expected input targets get to 1% or less.

Once the error has become less than 1%, I'll stop training and begin using the network to compute output from any input pattern -

-----

With all that said, my problem is that I don't get the error to converge; it loos like this - where EMS0 and EMS1 is the error corresponding to Target[0] and Target[1] of each training patters.

(I hope that would help)

Epoch = 2697 EMS0 = 2.00000254541665
Epoch = 2697 EMS1 = 1.99999730940732
Epoch = 2698 EMS0 = 1.13413523407753E-12
Epoch = 2698 EMS1 = 1.0760281650917E-12
Epoch = 2698 EMS0 = 6.80310917072636E-13
Epoch = 2698 EMS1 = 8.48199764099365E-13
Epoch = 2698 EMS0 = 2.00000278610561
Epoch = 2698 EMS1 = 1.99999719921888
Epoch = 2698 EMS0 = 2.00000253588739
Epoch = 2698 EMS1 = 1.99999731948005
Epoch = 2699 EMS0 = 1.12565940135504E-12
Epoch = 2699 EMS1 = 1.06798662056182E-12
Epoch = 2699 EMS0 = 6.75226708688793E-13
Epoch = 2699 EMS1 = 8.41860861776392E-13
Epoch = 2699 EMS0 = 2.00000277567531
Epoch = 2699 EMS1 = 1.99999720970413
Epoch = 2699 EMS0 = 2.0000025263938
Epoch = 2699 EMS1 = 1.99999732951508
Epoch = 2700 EMS0 = 1.11724691195425E-12
Epoch = 2700 EMS1 = 1.06000517318597E-12
Epoch = 2700 EMS0 = 6.70180495806385E-13
Epoch = 2700 EMS1 = 8.35569332726501E-13
Epoch = 2700 EMS0 = 2.00000276528405
Epoch = 2700 EMS1 = 1.99999722015013
Epoch = 2700 EMS0 = 2.00000251693576
Epoch = 2700 EMS1 = 1.99999733951254
Epoch = 2701 EMS0 = 1.10889729178637E-12
Epoch = 2701 EMS1 = 1.05208337436717E-12
Epoch = 2701 EMS0 = 6.65171996043745E-13
Epoch = 2701 EMS1 = 8.29324822558286E-13
Epoch = 2701 EMS0 = 2.00000275493169
Epoch = 2701 EMS1 = 1.99999723055702
Epoch = 2701 EMS0 = 2.00000250751312
Epoch = 2701 EMS1 = 1.99999734947257
Epoch = 2702 EMS0 = 1.1006100716839E-12
Epoch = 2702 EMS1 = 1.04422077747794E-12
Epoch = 2702 EMS0 = 6.60200925665127E-13
Epoch = 2702 EMS1 = 8.23126979203225E-13
Epoch = 2702 EMS0 = 2.00000274461809
Epoch = 2702 EMS1 = 1.99999724092496
Epoch = 2702 EMS0 = 2.00000249812576
Epoch = 2702 EMS1 = 1.99999735939532
Epoch = 2703 EMS0 = 1.09238478505259E-12
Epoch = 2703 EMS1 = 1.03641694105945E-12
Epoch = 2703 EMS0 = 6.55267006112613E-13
Epoch = 2703 EMS1 = 8.16975455173876E-13
Epoch = 2703 EMS0 = 2.0000027343431
Epoch = 2703 EMS1 = 1.99999725125407
Epoch = 2703 EMS0 = 2.00000248877354
Epoch = 2703 EMS1 = 1.99999736928092
Epoch = 2704 EMS0 = 1.08422096884522E-12
Epoch = 2704 EMS1 = 1.02867142526056E-12
Epoch = 2704 EMS0 = 6.5036995912252E-13
Epoch = 2704 EMS1 = 8.10869902984667E-13
Epoch = 2704 EMS0 = 2.00000272410658
Epoch = 2704 EMS1 = 1.99999726154453
Epoch = 2704 EMS0 = 2.00000247945633
Epoch = 2704 EMS1 = 1.99999737912951
Epoch = 2705 EMS0 = 1.07611816516478E-12
Epoch = 2705 EMS1 = 1.02098379343278E-12
Epoch = 2705 EMS0 = 6.45509510150172E-13
Epoch = 2705 EMS1 = 8.0480997968956E-13
Epoch = 2705 EMS0 = 2.00000271390838
Epoch = 2705 EMS1 = 1.99999727179645
Epoch = 2705 EMS0 = 2.00000247017401
Epoch = 2705 EMS1 = 1.99999738894123
Epoch = 2706 EMS0 = 1.06807591569158E-12
Epoch = 2706 EMS1 = 1.01335361495377E-12
Epoch = 2706 EMS0 = 6.40685384303076E-13
Epoch = 2706 EMS1 = 7.98795344301653E-13
Epoch = 2706 EMS0 = 2.00000270374835
Epoch = 2706 EMS1 = 1.99999728201
Epoch = 2706 EMS0 = 2.00000246092643
Epoch = 2706 EMS1 = 1.99999739871621
Epoch = 2707 EMS0 = 1.06009376965239E-12
Epoch = 2707 EMS1 = 1.00578045885438E-12
Epoch = 2707 EMS0 = 6.35897311254366E-13
Epoch = 2707 EMS1 = 7.92825659184503E-13
Epoch = 2707 EMS0 = 2.00000269362637
Epoch = 2707 EMS1 = 1.99999729218531
Epoch = 2707 EMS0 = 2.00000245171348
Epoch = 2707 EMS1 = 1.99999740845461
Epoch = 2708 EMS0 = 1.05217127727728E-12
Epoch

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900