www.pudn.com > neuroocr_src.zip > BackPropagationLearning.cs
// AForge Neural Net Library
//
// Copyright © Andrew Kirillov, 2005
// andrew.kirillov@gmail.com
//
namespace AForge.NeuralNet.Learning
{
using System;
///
/// Back Propagation learning
///
public class BackPropagationLearning : ISupervisedLearning
{
private Network net; // network to learn
private float learningRate = 0.1f;
private float momentum = 0.0f;
private float learningLimit = 0.1f;
private bool converged = false;
private float[][] errors;
private float[][][] deltas;
private float[][] thresholdDeltas;
// Learning Rate property
public float LearningRate
{
get { return learningRate; }
set { learningRate = value; }
}
// Momentum property
public float Momentum
{
get { return momentum; }
set { momentum = value; }
}
// Learning Limit property
public float LearningLimit
{
get { return learningLimit; }
set { learningLimit = value; }
}
// Is converged property
public bool IsConverged
{
get { return converged; }
}
// Constructor
public BackPropagationLearning(Network net)
{
this.net = net;
// create error and deltas arrays
errors = new float[net.LayersCount][];
deltas = new float[net.LayersCount][][];
thresholdDeltas = new float[net.LayersCount][];
for (int i = 0; i < net.LayersCount; i++)
{
Layer layer = net[i];
errors[i] = new float[layer.NeuronsCount];
deltas[i] = new float[layer.NeuronsCount][];
thresholdDeltas[i] = new float[layer.NeuronsCount];
for (int j = 0; j < layer.NeuronsCount; j++)
{
deltas[i][j] = new float[layer.InputsCount];
}
}
}
// Perform learning epoch and return errors sum
public float LearnEpoch(float[][] input, float[][] output)
{
int i, n = input.Length;
float error = 0.0f;
// for all training patterns
for (i = 0; i < n; i++)
{
error += Learn(input[i], output[i]);
}
// determine if we converged
converged = (error < learningLimit);
// return error
return error;
}
// Perform one learning iteration and return network error
public float Learn(float[] input, float[] output)
{
// compute the network
float[] nout = net.Compute(input);
// calculate network error
float error = CalculateError(output);
// calculate weights updates
CalculateUpdates(input);
// update the network
UpdateNetwork();
// return error level
return error;
}
// Calculate network errors
private float CalculateError(float[] desiredOutput)
{
Layer layer, layerNext;
float[] err, errNext;
float error = 0, e;
float output, sum;
int i, j, k, n, m, layersCount = net.LayersCount;
// assume, that all neurons of the network have
// the same activation function
IActivationFunction function = net[0][0].ActivationFunction;
// calculate error for the last layer
layer = net[layersCount - 1];
err = errors[layersCount - 1];
for (i = 0, n = layer.NeuronsCount; i < n; i++)
{
output = layer[i].Output;
// error of the neuron
e = desiredOutput[i] - output;
// error multiplied with first derivative
err[i] = e * function.OutputPrime2(output);
// squre the error and sum it
error += (e * e);
}
// calculate error for other layers
for (j = layersCount - 2; j >= 0; j--)
{
layer = net[j];
layerNext = net[j + 1];
err = errors[j];
errNext = errors[j + 1];
// for all neurons of the layer
for (i = 0, n = layer.NeuronsCount; i < n; i++)
{
sum = 0.0f;
// for all neurons of the next layer
for (k = 0, m = layerNext.NeuronsCount; k < m; k++)
{
sum += errNext[k] * layerNext[k][i];
}
err[i] = sum * function.OutputPrime2(layer[i].Output);
}
}
// return squared error of the last layer
return error;
}
// Calculate synapse (neurons weights) updates
private void CalculateUpdates(float[] input)
{
Neuron neuron;
Layer layer, layerPrev;
float[][] lDeltas;
float[] err, del, tdel;
float e;
int i, j, k, n, m, l;
// 1 - for the first layer
layer = net[0];
lDeltas = deltas[0];
err = errors[0];
tdel = thresholdDeltas[0];
// for each neuron of the layer
for (i = 0, n = layer.NeuronsCount; i < n; i++)
{
neuron = layer[i];
del = lDeltas[i];
e = err[i];
// for each synapse of the neuron
for (j = 0, m = neuron.InputsCount; j < m; j++)
{
// calculate weight update
del[j] = learningRate * (
momentum * del[j] +
(1.0f - momentum) * e * input[j]
);
}
// calculate treshold update
tdel[i] = learningRate * (
momentum * tdel[i] +
(1.0f - momentum) * e
);
}
// 2 - for all other layers
for (k = 1, l = net.LayersCount; k < l; k++)
{
layerPrev = net[k - 1];
layer = net[k];
lDeltas = deltas[k];
err = errors[k];
tdel = thresholdDeltas[k];
// for each neuron of the layer
for (i = 0, n = layer.NeuronsCount; i < n; i++)
{
neuron = layer[i];
del = lDeltas[i];
e = err[i];
// for each synapse of the neuron
for (j = 0, m = neuron.InputsCount; j < m; j++)
{
// calculate weight update
del[j] = learningRate * (
momentum * del[j] +
(1.0f - momentum) * e * layerPrev[j].Output
);
}
// calculate treshold update
tdel[i] = learningRate * (
momentum * tdel[i] +
(1.0f - momentum) * e
);
}
}
}
// Update weights of network
private void UpdateNetwork()
{
Neuron neuron;
Layer layer;
float[][] lDeltas;
float[] del, tdel;
int i, j, k, n, m, s;
// for each layer of the network
for (i = 0, n = net.LayersCount; i < n; i++)
{
layer = net[i];
lDeltas = deltas[i];
tdel = thresholdDeltas[i];
// for each neuron of the layer
for (j = 0, m = layer.NeuronsCount; j < m; j++)
{
neuron = layer[j];
del = lDeltas[j];
// for each weight of the neuron
for (k = 0, s = neuron.InputsCount; k < s; k++)
{
// update weight
neuron[k] += del[k];
}
// update treshold
neuron.Threshold -= tdel[j];
}
}
}
}
}