Example #1
0
        public static OptimizableNeuralNetwork randomNeuralNetworkBrain()
        {
            OptimizableNeuralNetwork nn = new OptimizableNeuralNetwork(15);

            for (int i = 0; i < 15; i++)
            {
                var f = ThresholdFunction.Random();
                nn.SetNeuronFunction(i, f, ThresholdFunction.GetDefaultParams(f));
            }
            for (int i = 0; i < 6; i++)
            {
                nn.SetNeuronFunction(i, ThresholdFunction.Function.Linear, ThresholdFunction.GetDefaultParams(ThresholdFunction.Function.Linear));
            }
            for (int i = 0; i < 6; i++)
            {
                for (int j = 6; j < 15; j++)
                {
                    nn.AddLink(i, j, random.NextDouble());
                }
            }
            for (int i = 6; i < 15; i++)
            {
                for (int j = 6; j < 15; j++)
                {
                    if (i < j)
                    {
                        nn.AddLink(i, j, random.NextDouble());
                    }
                }
            }
            return(nn);
        }
Example #2
0
        //---------------------------------------------


        #region Public Methods
        public NetworkContainer CreateNetworkContainer()
        {
            NetworkContainer neuralNetwork = null;

            int[] hiddenLayers = new int[cbHiddenLayerNumber.SelectedIndex];

            switch (hiddenLayers.Length)
            {
            case 0:
                break;

            case 1:
                hiddenLayers[0] = (int)this.nHidden1.Value;
                break;

            case 2:
                hiddenLayers[1] = (int)this.nHidden2.Value;
                goto case 1;

            case 3:
                hiddenLayers[2] = (int)this.nHidden3.Value;
                goto case 2;

            case 4:
                hiddenLayers[3] = (int)this.nHidden4.Value;
                goto case 3;

            default:
                break;
            }

            IActivationFunction activationFunction = null;

            if (this.rbBipolarSigmoid.Checked)
            {
                activationFunction = new BipolarSigmoidFunction((double)numSigmoidAlpha.Value);
            }
            else if (this.rbSigmoid.Checked)
            {
                activationFunction = new SigmoidFunction((double)numSigmoidAlpha.Value);
            }
            else if (this.rbThreshold.Checked)
            {
                activationFunction = new ThresholdFunction();
            }

            neuralNetwork = new NetworkContainer(
                tbNetworkName.Text,
                m_networkSchema,
                activationFunction,
                hiddenLayers);


            //         neuralNetwork.Schema.DataRanges.ActivationFunctionRange = new AForge.DoubleRange((double)numRangeLow.Value, (double)numRangeHigh.Value);


            return(neuralNetwork);
        }
        public void NeuronInitializeActivationThresHold()
        {
            int    InputCount  = 3;
            double outputValue = 0;
            IActivationFunction ActivationThresHold = new ThresholdFunction();
            Neuron ActNeuron = new ActivationNeuron(InputCount, ActivationThresHold);

            ActNeuron.FeedForward(InputValues);
            outputValue = ActNeuron.Compute();

            Assert.True(outputValue != 0);
        }
Example #4
0
        public void Evaluate()
        {
            ThresholdFunction fn = new ThresholdFunction();

            Assert.AreEqual(1.0, fn.Evaluate(1.0));
            Assert.AreEqual(1.0, fn.Evaluate(1.1));
            Assert.AreEqual(1.0, fn.Evaluate(0.1));
            Assert.AreEqual(1.0, fn.Evaluate(1000));

            Assert.AreEqual(0.0, fn.Evaluate(-0.1));
            Assert.AreEqual(0.0, fn.Evaluate(-0.5));
            Assert.AreEqual(0.0, fn.Evaluate(0.0));

            Assert.AreEqual(0.0, fn.Evaluate(-1.0));
            Assert.AreEqual(0.0, fn.Evaluate(-1.1));
            Assert.AreEqual(0.0, fn.Evaluate(-1000));
        }
Example #5
0
        public void CreateDistanceLayerTest()
        {
            LayerFactory        factory             = new LayerFactory();
            IActivationFunction ActivationThresHold = new ThresholdFunction();

            DistanceLayer layer = (DistanceLayer)factory.CreateLayer(NETWORK_TYPE_DISTANCE, INPUT_COUNT, ActivationThresHold);

            Assert.Equal(3, layer.GetNeuronCount());
            DistanceNeuron actNeuron = (DistanceNeuron)layer.GetNeuron(1);

            Assert.NotNull(actNeuron);

            List <ISynapse> inputs = actNeuron.FetchInputs();

            Assert.NotNull(inputs);
            Assert.Equal(INPUT_COUNT, inputs.Count);

            ISynapse input = inputs[1];

            Assert.True(input.Weight != 0);
        }
Example #6
0
    // { 0, 500, 500, 2000, 2000, 4000, 4000, 8000, 8000, 16000, 16000, 22000 };
    public static void analyse(DecoderInterface decoder)
    {
        loadingProgress = 0;
        abortAnalysis = false;
        // For finding the volume levels
        List<int> volumeLevelList = new List<int> ();
        float rollingAverage = 0.01f;
        float alpha = 0.15f;
        int activePart = -1;
        int sampleCounter = 0;
        float totalMax = -1;

        // Get spectral flux
        SpectrumProvider spectrumProvider = new SpectrumProvider (decoder, BUFFER_SIZE, HOP_SIZE, true);
        float[] spectrum = spectrumProvider.nextSpectrum ();
        float[] lastSpectrum = new float[spectrum.Length];
        List<List<float>> spectralFlux = new List<List<float>> ();
        for (int i = 0; i < bands.Length / 2; i++)
            spectralFlux.Add (new List<float> ());

        int bufferCounter = 0;

        do {

            if(abortAnalysis) return;

            #region SPECTRAL ANALYSIS
            for (int i = 0; i < bands.Length; i+=2) {
                int startFreq = spectrumProvider.getFFT ().freqToIndex (bands [i]);
                int endFreq = spectrumProvider.getFFT ().freqToIndex (bands [i + 1]);
                float flux = 0;
                for (int j = startFreq; j <= endFreq; j++) {
                    float value = (spectrum [j] - lastSpectrum [j]);
                    value = (value + Mathf.Abs (value)) / 2;
                    flux += value;
                }
                (spectralFlux [i / 2]).Add (flux);
            }

            System.Array.Copy (spectrum, 0, lastSpectrum, 0, spectrum.Length);
            #endregion

            #region GET MAX SAMPLE
            foreach (float sample in spectrumProvider.getCurrentSamples()) {
                if (sample > totalMax)
                    totalMax = sample;
            }
            #endregion

            bufferCounter++;
            loadingProgress = 0.75f*(((bufferCounter*BUFFER_SIZE)/(float)AudioManager.frequency)/AudioManager.audioLength);

        } while( (spectrum = spectrumProvider.nextSpectrum() ) != null );

        #region VOLUME CLASSIFICATION
        DecoderInterface dec = spectrumProvider.getDecoder ();
        dec.reset ();

        float [] samples = new float[spectrumProvider.getWinSize ()];
        float factor = 1f / totalMax;
        List<float> decibelLevels = new List<float>();
        float avgDecibels = 0;

        float oldProgress = loadingProgress;

        while (dec.readSamples(ref samples) !=0) {

            if(abortAnalysis) return;

            float max = -1;

            /* Normalize the volume using the previously calculated factor */
            for (int i =0; i < samples.Length; i++) {
                samples [i] = Mathf.Abs (samples[i] * factor);
                if (samples [i] > max)
                    max = samples [i];
            }

            float db = Mathf.Abs(20*Mathf.Log10(max));
            if(max != 0) decibelLevels.Add(db);
            avgDecibels += db;

            rollingAverage = (alpha * max) + ((1 - alpha) * rollingAverage);

            // Have we found a part which classifies as extremely loud?
            if (rollingAverage > 0.82f) { //0.8

                // Are we already in that part?
                if (activePart != 5) {
                    activePart = 5; // Set flag that we are now in that part
                    volumeLevelList.Add (sampleCounter * spectrumProvider.getCurrentSamples ().Length);
                    volumeLevelList.Add (activePart);
                }

                // Have we found a part which classifies as damn loud?
            } else if (rollingAverage > 0.7f) { //0.6

                // Are we already in that part?
                if (activePart != 4) {
                    activePart = 4; // Set flag that we are now in that part
                    volumeLevelList.Add (sampleCounter * spectrumProvider.getCurrentSamples ().Length);
                    volumeLevelList.Add (activePart);
                }

                // Have we found a part which classifies as pretty loud?
            } else if (rollingAverage > 0.4f) { //0.2

                // Are we already in that part?
                if (activePart != 3) {
                    activePart = 3; // Set flag that we are now in that part
                    volumeLevelList.Add (sampleCounter * spectrumProvider.getCurrentSamples ().Length);
                    volumeLevelList.Add (activePart);
                }

                // Have we found a part which classifies as pretty normal?
            } else if (rollingAverage > 0.1f) { //0.0716

                // Are we already in that part?
                if (activePart != 2) {
                    activePart = 2; // Set flag that we are now in that part
                    volumeLevelList.Add (sampleCounter * spectrumProvider.getCurrentSamples ().Length);
                    volumeLevelList.Add (activePart);
                }

                // Have we found a part which classifies as pretty quiet?
            } else if (rollingAverage > 0.0016f) { //0.0016

                // Are we already in that part?
                if (activePart != 1) {
                    activePart = 1; // Set flag that we are now in that part
                    volumeLevelList.Add (sampleCounter * spectrumProvider.getCurrentSamples ().Length);
                    volumeLevelList.Add (activePart);
                }

                // Have we found a part which classifies as very quiet?
                // Below 40db (== below 0.06f amplitude)
            } else {

                // Are we already in that part?
                if (activePart != 0) {
                    activePart = 0; // Set flag that we are now in that part
                    volumeLevelList.Add (sampleCounter * spectrumProvider.getCurrentSamples ().Length);
                    volumeLevelList.Add (activePart);
                }
            }
            sampleCounter++;
            loadingProgress = oldProgress + 0.25f*(((sampleCounter*BUFFER_SIZE)/(float)AudioManager.frequency)/AudioManager.audioLength);
        }
        #endregion

        if(abortAnalysis) return;

        // Store volumelevels
        volumeLevels = volumeLevelList.ToArray ();
        volumeLevelList.Clear();
        volumeLevelList = null;

        #region SPECTRAL FLUX ANALYSIS
        // Convert spectral flux arraylist to array
        float[][] spectralFluxArray = new float[spectralFlux.Count][];
        for (int i = 0; i < spectralFluxArray.Length; i++) {
            spectralFluxArray [i] = spectralFlux [i].ToArray ();
        }
        spectralFlux.Clear ();
        spectralFlux = null;

        if(abortAnalysis) return;

        // Get thresholds
        float[][] thresholds = new float[bands.Length / 2][];
        float[][] prunnedSpectralFlux = new float[bands.Length / 2][];
        for (int i = 0; i < bands.Length / 2; i++) {
            float[] threshold = new ThresholdFunction (HISTORY_SIZE, multipliers [i]).calculate (spectralFluxArray [i]);
            thresholds [i] = threshold;

            float[] tempPSF = new float[spectralFluxArray [i].Length];
            for (int j = 0; j < spectralFluxArray[i].Length; j++) {
                if (threshold [j] <= spectralFluxArray [i] [j])
                    tempPSF [j] = spectralFluxArray [i] [j] - threshold [j];
                else
                    tempPSF [j] = 0;
            }
            prunnedSpectralFlux [i] = tempPSF;
        }
        thresholds = null;

        if(abortAnalysis) return;

        // Get Peaks
        List<int[]> peaksList = new List<int[]> ();
        float[] peakAvgs = new float[prunnedSpectralFlux.Length];
        float[] minPeaks = new float[prunnedSpectralFlux.Length];
        for (int i = 0; i < prunnedSpectralFlux.Length; i++) {

            List<int> tempPeaks = new List<int> ();
            minPeaks [i] = float.MaxValue;

            for (int j = 0; j < prunnedSpectralFlux[i].Length -1; j++) {
                if (prunnedSpectralFlux [i] [j] > prunnedSpectralFlux [i] [j + 1]) {
                    tempPeaks.Add (j);
                    peakAvgs [i] += prunnedSpectralFlux [i] [j];
                    if (prunnedSpectralFlux [i] [j] != 0 && prunnedSpectralFlux [i] [j] < minPeaks [i])
                        minPeaks [i] = prunnedSpectralFlux [i] [j];
                }
            }
            peaksList.Add (tempPeaks.ToArray ());
            peakAvgs [i] /= tempPeaks.Count;
        }

        if(abortAnalysis) return;

        // Save current peaks & reset list
        peaks = peaksList.ToArray ();
        peaksList.Clear ();

        // Lowpass filter the peaks
        for (int i = 0; i < peaks.Length; i++) {
            List<int> tempPeaks = new List<int> ();
            for (int j = 0; j < peaks[i].Length; j++) {
                if (prunnedSpectralFlux [i] [peaks [i] [j]] > minPeaks [i] + 0.7f * (peakAvgs [i] - minPeaks [i])) {
                    tempPeaks.Add (peaks [i] [j]);
                    tempPeaks.Add (Mathf.RoundToInt(prunnedSpectralFlux[i][peaks[i][j]]));
                }
            }
            peaksList.Add (tempPeaks.ToArray ());
        }
        peaks = peaksList.ToArray ();
        #endregion

        if(abortAnalysis) return;

        #region NORMALIZE PEAK INTENSITIES
        for(int i = 0; i < peaks.Length; i++) {
            float max = -1;
            for(int j = 1;j < peaks[i].Length; j+=2) {
                if(peaks[i][j] > max) max = peaks[i][j];
            }
            for(int j = 1;j < peaks[i].Length; j+=2) {
                peaks[i][j] = Mathf.RoundToInt(100f*(peaks[i][j]/max));
            }
        }
        #endregion

        if(abortAnalysis) return;

        #region VARIATION FACTOR
        float[] dbLvls = decibelLevels.ToArray();
        decibelLevels.Clear();
        decibelLevels = null;

        avgDecibels /= (float)dbLvls.Length;

        float stDev = 0;
        for (int i = 0; i < dbLvls.Length; i++) {
            stDev += (dbLvls[i] - avgDecibels) * (dbLvls[i] - avgDecibels);
        }

        stDev = Mathf.Sqrt (stDev / (float)dbLvls.Length);

        if(stDev > 25f) stDev = 25f;
        else if (stDev < 5f) stDev = 5f;

        stDev /= 25f;
        variationFactor = stDev;
        #endregion

        isAnalyzing = false;
    }
Example #7
0
        public void Train(IForecastingDataSets datasets)
        {
            NeedToStop = false;
            if (ModelStartRunning != null)
            {
                ModelStartRunning(this, new ComponentRunEventArgs(datasets));
            }
            IActivationFunction actFunc = null;
            double sigmoidAlphaValue    = mAnnModelParameter.SigmoidAlphaValue;

            if (mAnnModelParameter.HiddenActivationFunction == fann_activationfunc_enum.FANN_SIGMOID_SYMMETRIC)
            {
                actFunc = new BipolarSigmoidFunction(sigmoidAlphaValue);
            }
            else if (mAnnModelParameter.HiddenActivationFunction == fann_activationfunc_enum.FANN_SIGMOID)
            {
                actFunc = new SigmoidFunction(sigmoidAlphaValue);
            }
            else if (mAnnModelParameter.HiddenActivationFunction == fann_activationfunc_enum.FANN_THRESHOLD)
            {
                actFunc = new ThresholdFunction();
            }
            else
            {
                actFunc = new BipolarSigmoidFunction(sigmoidAlphaValue);
            }

            mAnnModelParameter.InputNeuronCount  = datasets.InputData[0].Length;
            mAnnModelParameter.OutputNeuronCount = datasets.OutputData[0].Length;
            int inputsCount  = mAnnModelParameter.InputNeuronCount;
            int outputsCount = mAnnModelParameter.OutputNeuronCount;

            // mAnnModelParameter.HiddenNeuronsCount = new int[1];
            //      mAnnModelParameter.HiddenNeuronsCount[0] = datasets.InputData[0].Length * 2 + 1;
            mAnnModelParameter.HiddenCount = 1;

            int[] neuronsCount = new int[mAnnModelParameter.HiddenNeuronsCount.Length + 1];
            for (int i = 0; i < mAnnModelParameter.HiddenNeuronsCount.Length; i++)
            {
                neuronsCount[i] = mAnnModelParameter.HiddenNeuronsCount[i];
            }
            neuronsCount[mAnnModelParameter.HiddenNeuronsCount.Length] = outputsCount;

            mNetwork = new ActivationNetwork(actFunc, inputsCount, neuronsCount);
            BackPropagationLearning teacher = new BackPropagationLearning(mNetwork);
            ActivationLayer         layer   = mNetwork[0];

            teacher.LearningRate = mAnnModelParameter.LearningRate;
            teacher.Momentum     = mAnnModelParameter.LearningMomentum;

            List <double> arError      = new List <double>();
            int           solutionSize = datasets.InputData.Length;

            datasets.ForecastedData = new double[solutionSize][];
            int iteration = 1;

            while (!mNeedToStop)
            {
                double error = teacher.RunEpoch(datasets.InputData, datasets.OutputData);
                arError.Add(error);

                double learningError   = 0.0;
                double predictionError = 0.0;

                for (int i = 0, n = solutionSize; i < n; i++)
                {
                    datasets.ForecastedData[i] = (double[])mNetwork.Compute(datasets.InputData[i]).Clone();

                    if (i >= n - mAnnModelParameter.MaximumWindowSize)
                    {
                        predictionError += Math.Abs(datasets.OutputData[i][0] - datasets.ForecastedData[i][0]);
                    }
                    else
                    {
                        learningError += Math.Abs(datasets.OutputData[i][0] - datasets.ForecastedData[i][0]);
                    }
                }
                if (iteration >= mAnnModelParameter.Iterations)
                {
                    NeedToStop = true;
                }
                if (learningError <= mAnnModelParameter.DesiredError)
                {
                    NeedToStop = true;
                }
                if (ModelRunningEpoch != null)
                {
                    ModelRunningEpoch(this, new AnnModelRunEpochEventArgs(iteration, error));
                }
                iteration++;
            }

            LayerWeightCollection = new LayerWeight[mNetwork.LayersCount];

            LayerWeightCollection[0].Weight      = new double[layer.NeuronsCount][];
            LayerWeightCollection[0].ThreashHold = new double[layer.NeuronsCount][];
            for (int i = 0; i < layer.NeuronsCount; i++)
            {
                LayerWeightCollection[0].Weight[i]      = new double[layer.InputsCount];
                LayerWeightCollection[0].ThreashHold[i] = new double[layer.InputsCount];
                for (int j = 0; j < layer.InputsCount; j++)
                {
                    LayerWeightCollection[0].Weight[i][j]      = layer[i][j];
                    LayerWeightCollection[0].ThreashHold[i][j] = layer[i][j];
                }
            }

            layer = mNetwork[1];
            LayerWeightCollection[1].Weight      = new double[layer.NeuronsCount][];
            LayerWeightCollection[1].ThreashHold = new double[layer.NeuronsCount][];
            for (int i = 0; i < layer.NeuronsCount; i++)
            {
                LayerWeightCollection[1].Weight[i]      = new double[layer.InputsCount];
                LayerWeightCollection[1].ThreashHold[i] = new double[layer.InputsCount];
                for (int j = 0; j < layer.InputsCount; j++)
                {
                    LayerWeightCollection[1].Weight[i][j]      = layer[i][j];
                    LayerWeightCollection[1].ThreashHold[i][j] = layer[i][j];
                }
            }

            if (ModelFinishRunning != null)
            {
                ModelFinishRunning(this, new ComponentRunEventArgs(datasets));
            }
        }
        static void Main(string[] args)
        {
            //this below 3 lines will shuffle the data whenever i run the application
            List <string> lstFile = File.ReadAllLines(srFileName).ToList();

            lstFile = lstFile.OrderBy(a => Guid.NewGuid()).ToList();

            File.WriteAllLines(srFileName, lstFile);

            int irNumberOfExamples = File.ReadAllLines(srFileName).Count();

            //the first array holds all of the instances
            double[][] input   = new double[irNumberOfExamples][];
            double[][] output  = new double[irNumberOfExamples][];
            double[][] output2 = new double[irNumberOfExamples][];

            List <double> lstOutPutClasses = new List <double>();

            NumberFormatInfo formatProvider = new NumberFormatInfo();

            formatProvider.NumberDecimalSeparator = ".";
            formatProvider.NumberGroupSeparator   = ",";

            foreach (var vrPerLine in File.ReadAllLines(srFileName))
            {
                var vrOutPut = Convert.ToDouble(vrPerLine.Split(',').Last(), formatProvider);

                if (lstOutPutClasses.Contains(vrOutPut) == false)
                {
                    lstOutPutClasses.Add(vrOutPut);
                }
            }

            int irCounter = 0;

            foreach (var vrPerLine in File.ReadAllLines(srFileName))
            {
                input[irCounter] = vrPerLine.Split(',').SkipLast(1).
                                   Select(pr => Convert.ToDouble(pr.Replace("I", "0.0").Replace("M", "0.5").Replace("F", "1.0"), formatProvider)).ToArray();

                output2[irCounter] = new double[] { Convert.ToDouble(vrPerLine.Split(',').Last()) };

                output[irCounter] = new double[lstOutPutClasses.Count];

                var vrCurrentOutClass = Convert.ToDouble(vrPerLine.Split(',').Last(), formatProvider);

                output[irCounter][lstOutPutClasses.IndexOf(vrCurrentOutClass)] = 1;

                irCounter++;
            }



            int irFinalClassCount = lstOutPutClasses.Count;

            double learningRate       = 0.1;
            int    irNumberOfFeatures = input[0].Length;

            int[] numberOfNeurons = new int[] { 100, 100, irFinalClassCount };

            ThresholdFunction function = new ThresholdFunction();

            ActivationNetwork network3 = new ActivationNetwork(
                new SigmoidFunction(2),
                irNumberOfFeatures,
                12,                 // two inputs in the network
                irFinalClassCount); // one neuron in the second layer
                                    // create teacher
            BackPropagationLearning bpteacher = new BackPropagationLearning(network3);

            // loop

            bpteacher.LearningRate = 0.1;
            bpteacher.Momentum     = 0.5;

            for (int i = 0; i < 200000; i++)
            {
                double error = bpteacher.RunEpoch(input, output);

                var vrAcc = calculateAcurracy(network3, input, output);

                Console.WriteLine("BackPropagationLearning -> " + i + ", Error = " + error.ToString("N2") + "\t\t accuracy: " + vrAcc);
            }



            // create activation network
            ActivationNetwork network = new ActivationNetwork(
                function,
                irNumberOfFeatures,
                irFinalClassCount); // one neuron in the second layer

            //double initialStep = 0.125;
            //double sigmoidAlphaValue = 2.0;

            //// create neural network
            //ActivationNetwork neuralNetwork = new ActivationNetwork(new SigmoidFunction(sigmoidAlphaValue), irNumberOfFeatures, 100, irFinalClassCount);

            //// create teacher
            //ParallelResilientBackpropagationLearning neuralTeacher = new ParallelResilientBackpropagationLearning(neuralNetwork);

            //// set learning rate and momentum
            //neuralTeacher.Reset(initialStep);

            //for (int i = 0; i < 5000; i++)
            //{
            //    double error = neuralTeacher.RunEpoch(input, output);

            //        Console.WriteLine("Supervised -> " + i + ", Error = " + error);

            //}

            var Layers = network.Layers.Length;

            //int irCounter_2 = 0;
            //BackPropagationLearning teacher2 = new BackPropagationLearning(network);
            //// loop
            //while (true)
            //{
            //    // run epoch of learning procedure
            //    double error = teacher2.RunEpoch(input, output);
            //    // check error value to see if we need to stop

            //    Console.WriteLine("current iteration: " + irCounter_2.ToString("N0") + "error rate: " + error.ToString("N3"));
            //    // ...
            //    irCounter_2++;
            //}

            ActivationNeuron neuron = network.Layers[0].Neurons[0] as ActivationNeuron;
            // create teacher
            DeltaRuleLearning teacher = new DeltaRuleLearning(network);

            // set learning rate
            teacher.LearningRate = learningRate;

            // iterations
            int iteration = 1;

            // statistic files
            StreamWriter errorsFile  = null;
            StreamWriter weightsFile = null;

            // check if we need to save statistics to files
            if (saveStatisticsToFiles)
            {
                // open files
                errorsFile            = File.CreateText("errors.csv");
                weightsFile           = File.CreateText("weights.csv");
                weightsFile.AutoFlush = true;
            }

            // erros list
            ArrayList errorsList = new ArrayList();

            // loop
            while (!needToStop)
            {
                // save current weights
                if (weightsFile != null)
                {
                    for (int i = 0; i < irNumberOfFeatures; i++)
                    {
                        weightsFile.Write(neuron.Weights[i] + ",");
                    }
                    weightsFile.WriteLine(neuron.Threshold);
                }

                // run epoch of learning procedure
                double error = teacher.RunEpoch(input, output);

                errorsList.Add(error);

                // show current iteration
                Console.WriteLine("current iteration: " + iteration.ToString("N0") + "error rate: " + error.ToString("N3"));


                // save current error
                if (errorsFile != null)
                {
                    errorsFile.WriteLine(error);
                }

                // stop if no error
                if (error == 0)
                {
                    break;
                }

                iteration++;
            }

            Console.ReadLine();
        }