Click here to Skip to main content
15,891,033 members
Articles / Web Development / ASP.NET

Clog: Client Logging, Silverlight Edition

Rate me:
Please Sign up or sign in to vote.
4.84/5 (55 votes)
16 Apr 2009CPOL14 min read 276.8K   3.1K   112  
A customizable log provider system that allows you to harness your existing logging system to log client side messages to your server. Includes a Silverlight interface and Log Viewer.
#region File and License Information
/* Based on code from http://www.c-sharpcorner.com/uploadfile/rmcochran/ai_oop_neuralnet06192006090112am/ai_oop_neuralnet.aspx */
/*
<File>
	<Copyright>Copyright � 2007, Daniel Vaughan. All rights reserved.</Copyright>
	<License see="prj:///Documentation/License.txt"/>
	<Owner Name="Daniel Vaughan" Email="dbvaughan@gmail.com"/>
	<CreationDate>2008-12-27 18:11:45Z</CreationDate>
	<LastSubmissionDate>$Date: $</LastSubmissionDate>
	<Version>$Revision: $</Version>
</File>
*/
#endregion

using System;
using System.Collections.Generic;
using System.Linq;

namespace DanielVaughan.AI.NeuralNetworking
{
	/// <summary>
	/// An artificial neural network.
	/// </summary>
	[Serializable]
	public partial class NeuralNetwork
	{
		double trueLevel = .99;
		double falseLevel = .01;
		double middleLevel = .5;

		NeuralLayer InputLayer { get; set; }
		NeuralLayer HiddenLayer { get; set; }
		NeuralLayer OutputLayer { get; set; }
		//NeuralLayer ContextLayer { get; set; }

		readonly object networkLock = new object();

		TrainingSet totalTrainingSet;

		/// <summary>
		/// Sets the input value at the specified index to be the value of either
		/// the true level or false level.
		/// </summary>
		/// <param name="neuronIndex">Index of the neuron.</param>
		/// <param name="inputValue">if set to <c>true</c> the input layer
		/// at the specified index will be set to the value of the trueLevel value 
		/// (a high double value less than 1),
		/// otherwise it will be set to the falseLevel value 
		/// (a low double value greater than 0).</param>
		public void SetInputValue(int neuronIndex, bool inputValue)
		{
			lock (networkLock)
			{
				InputLayer[neuronIndex].Output = inputValue ? trueLevel : falseLevel;
			}
		}

		/// <summary>
		/// Gets the output value at the specified index.
		/// </summary>
		/// <param name="neuronIndex">Index of the neuron.</param>
		/// <returns>The value of the output.</returns>
		public double GetOutputValue(int neuronIndex)
		{
			lock (networkLock)
			{
				return OutputLayer[neuronIndex].Output;
			}
		}

		/// <summary>
		/// Gets the output layer or sets the input layer at the specified index with a value
		/// representing either <code>true</code> or <code>false</code>.
		/// </summary>
		/// <value></value>
		public bool this[int neuronIndex]
		{
			get
			{
				lock (networkLock)
				{
					return OutputLayer[neuronIndex].Output > middleLevel;
				}
			}
			set
			{
				lock (networkLock)
				{
					InputLayer[neuronIndex].Output = value ? trueLevel : falseLevel;
				}
			}
		}

		/// <summary>
		/// Sets the input to the neural network as booleans.
		/// </summary>
		/// <value>The input as booleans.</value>
		public IEnumerable<bool> InputAsBooleans
		{
			set
			{
				ArgumentValidator.AssertNotNull(value, "value");
				int count = 0;
				foreach (bool neuronValue in value)
				{
					InputLayer[count].Output = neuronValue ? trueLevel : falseLevel;
					count++;
				}
			}
		}

		/// <summary>
		/// Sets the raw input doubles prior to pulsing.
		/// </summary>
		/// <value>The input.</value>
		public IEnumerable<double> Input
		{
			set
			{
				lock (networkLock)
				{
					ArgumentValidator.AssertNotNull(value, "value");

					int count = 0;
					foreach (var neuronValue in value)
					{
						InputLayer[count].Output = neuronValue;
						count++;
					}
				}
			}
		}

		/// <summary>
		/// Gets the output as booleans.
		/// </summary>
		/// <value>The output as booleans.</value>
		public IEnumerable<bool> OutputAsBooleans
		{
			get
			{
				foreach (var neuron in OutputLayer)
				{
					yield return neuron.Output > middleLevel;
				}
			}
		}

		/// <summary>
		/// Gets the outputs of the output layer.
		/// </summary>
		/// <value>The output.</value>
		public IEnumerable<double> Output
		{
			get
			{
				var result = from neuron in OutputLayer
				             select neuron.Output;
				return result.ToList();
			}
		}

		/// <summary>
		/// Gets the output error level.
		/// </summary>
		/// <param name="index">The index.</param>
		/// <returns>A value representing the error level of the output layer
		/// at the specified index.</returns>
		public double GetOutputError(int index)
		{
			var result = OutputLayer[index].Error;
			return result;
		}

		/// <summary>
		/// Gets or sets how rapidly the network learns. That is, how much affect
		/// new input has on the network.
		/// </summary>
		/// <value>The learning rate.</value>
		public double LearningRate { get; set; }

		public NeuralNetwork()
		{
			LearningRate = 0.3;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="NeuralNetwork"/> class.
		/// </summary>
		/// <param name="inputNeuronCount">The number of neuron to have in the input layer.</param>
		/// <param name="hiddenNeuronCount">The number of neuron to have in the hidden layer.</param>
		/// <param name="outputNeuronCount">The number of neuron to have in the output layer.</param>
		public NeuralNetwork(int inputNeuronCount, int hiddenNeuronCount, int outputNeuronCount) : this()
		{
			Initialize(inputNeuronCount, hiddenNeuronCount, outputNeuronCount);
		}

		/// <summary>
		/// Applies the input.
		/// </summary>
		public void Pulse()
		{
			lock (networkLock)
			{
				HiddenLayer.Pulse();
				OutputLayer.Pulse();
			}
		}

		void ApplyLearning()
		{
			lock (networkLock)
			{
				HiddenLayer.ApplyLearning(this);
				OutputLayer.ApplyLearning(this);
			}
		}

		void InitializeLearning()
		{
			lock (networkLock)
			{
				HiddenLayer.InitializeLearning(this);
				OutputLayer.InitializeLearning(this);
			}
		}

		/// <summary>
		/// Trains the network using the specified training set.
		/// </summary>
		/// <param name="trainingSet">The training set.</param>
		/// <param name="iterations">The number of training iterations to perform.</param>
		public void Train(TrainingSet trainingSet, int iterations)
		{
			Train(trainingSet, TrainingType.BackPropagation, iterations);
		}

		/// <summary>
		/// Trains the network using the specified input and output values.
		/// </summary>
		/// <param name="input">The input.</param>
		/// <param name="expectedOutput">The expected output.</param>
		/// <param name="iterations">The iterations.</param>
		public void Train(bool[][] input, bool[][] expectedOutput, int iterations)
		{
			ArgumentValidator.AssertNotNull(input, "input");
			ArgumentValidator.AssertNotNull(expectedOutput, "expectedOutput");
			ArgumentValidator.AssertGreaterThan(iterations, 0, "iterations");

			double[][] inputDoubles = ConvertToDoubleArray(input);
			double[][] expectedDoubles = ConvertToDoubleArray(expectedOutput);

			var mappings = new List<KeyValuePair<LayerStimulus, LayerStimulus>>();
			for (int i = 0; i < inputDoubles.Length; i++)
			{
				mappings.Add(new KeyValuePair<LayerStimulus, LayerStimulus>(
					new LayerStimulus(inputDoubles[i]), 
					new LayerStimulus(expectedDoubles[i])));
			}
			var trainingSet = new TrainingSet(mappings);
			Train(trainingSet, TrainingType.BackPropagation, iterations);
		}

		double[][] ConvertToDoubleArray(bool[][] input)
		{
			var inputDoubles = new double[input.Length][];
			for (int i = 0; i < input.Length; i++)
			{
				bool[] bools = input[i];
				inputDoubles[i] = new double[bools.Length];
				for (int j = 0; j < bools.Length; j++)
				{
					inputDoubles[i][j] = bools[j] ? trueLevel : falseLevel;
				}
			}
			return inputDoubles;
		}

		void Initialize(int inputNeuronCount, int hiddenNeuronCount, int outputNeuronCount)
		{
			var random = new Random();

			InputLayer = new NeuralLayer();
			HiddenLayer = new NeuralLayer();
			OutputLayer = new NeuralLayer();
			
			for (int i = 0; i < inputNeuronCount; i++)
			{
				InputLayer.Add(new Neuron());
			}

			for (int i = 0; i < hiddenNeuronCount; i++)
			{
				HiddenLayer.Add(new Neuron());
			}

			for (int i = 0; i < outputNeuronCount; i++)
			{
				OutputLayer.Add(new Neuron());
			}

			/* Connect input layer to hidden layer. */
			for (int i = 0; i < HiddenLayer.Count; i++)
			{
				for (int j = 0; j < InputLayer.Count; j++)
				{
					double nextRandom = random.NextDouble();
					HiddenLayer[i].Inputs.Add(InputLayer[j], new NeuralBias(nextRandom));
				}
			}

			/* Connect output layer to hidden layer. */
			for (int i = 0; i < OutputLayer.Count; i++)
			{
				for (int j = 0; j < HiddenLayer.Count; j++)
				{
					OutputLayer[i].Inputs.Add(HiddenLayer[j], new NeuralBias(random.NextDouble()));
				}
			}

//			/* Connect hidden layer to context layer. */
//			for (int i = 0; i < network.HiddenLayer.Count; i++)
//			{
//				for (int j = 0; j < network.ContextLayer.Count; j++)
//				{
//					network.HiddenLayer[i].Inputs.Add(network.ContextLayer[j], new NeuralBias(random.NextDouble()));
//				}
//			}
		}

		void CalculateErrors(double[] desiredResults)
		{
			/* Calcualte output error values. */
			for (int i = 0; i < OutputLayer.Count; i++)
			{
				var outputNeuron = OutputLayer[i];
				double output = outputNeuron.Output;

				double derivative = CalculateSigmoidDerivative(output);
				outputNeuron.Error = (desiredResults[i] - output) * derivative;
			}

			/* Calculate hidden layer error values. */
			for (int i = 0; i < HiddenLayer.Count; i++)
			{
				var hiddenNeuron = HiddenLayer[i];
				double output = hiddenNeuron.Output;

				double error = 0;
				for (int j = 0; j < OutputLayer.Count; j++)
				{
					var outputNeuron = OutputLayer[j];
					error += outputNeuron.Error * outputNeuron.Inputs[hiddenNeuron].Weight * CalculateSigmoidDerivative(output);
				}

				hiddenNeuron.Error = error;
			}
		}

		double CalculateSigmoidDerivative(double value)
		{
			return value * (1.0F - value);
		}

		void PrepareInputLayerForPulse(double[] input)
		{
			if (input.Length != InputLayer.Count)
			{
				/* TODO: Make localizable resource. */
				throw new ArgumentException(string.Format("Expecting {0} inputs for this network", 
					InputLayer.Count)); 
			}

			/* Initialize data. */
			for (int i = 0; i < InputLayer.Count; i++)
			{
				InputLayer[i].Output = input[i];
			}
		}

		void CalculateAndAppendTransformation()
		{
			/* Adjust output layer weight change. */
			for (int j = 0; j < OutputLayer.Count; j++)
			{
				var outputNeuron = OutputLayer[j];

				for (int i = 0; i < HiddenLayer.Count; i++)
				{
					var hiddenNeuron = HiddenLayer[i];
					outputNeuron.Inputs[hiddenNeuron].WeightDelta += outputNeuron.Error * hiddenNeuron.Output;
				}

				outputNeuron.Bias.WeightDelta += outputNeuron.Error * outputNeuron.Bias.Weight;
			}

			/* Adjust hidden layer weight change. */
			for (int j = 0; j < HiddenLayer.Count; j++)
			{
				var hiddenNeuron = HiddenLayer[j];

				for (int i = 0; i < InputLayer.Count; i++)
				{
					var inputNode = InputLayer[i];
					hiddenNeuron.Inputs[inputNode].WeightDelta += hiddenNeuron.Error * inputNode.Output;
				}

				hiddenNeuron.Bias.WeightDelta += hiddenNeuron.Error * hiddenNeuron.Bias.Weight;
			}
		}

		void TrainUsingBackPropogation(double[] input, double[] desiredResult)
		{
			PrepareInputLayerForPulse(input);
			Pulse();
			CalculateErrors(desiredResult);
			CalculateAndAppendTransformation();
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Engineer
Switzerland Switzerland
Daniel is a former senior engineer in Technology and Research at the Office of the CTO at Microsoft, working on next generation systems.

Previously Daniel was a nine-time Microsoft MVP and co-founder of Outcoder, a Swiss software and consulting company.

Daniel is the author of Windows Phone 8 Unleashed and Windows Phone 7.5 Unleashed, both published by SAMS.

Daniel is the developer behind several acclaimed mobile apps including Surfy Browser for Android and Windows Phone. Daniel is the creator of a number of popular open-source projects, most notably Codon.

Would you like Daniel to bring value to your organisation? Please contact

Blog | Twitter


Xamarin Experts
Windows 10 Experts

Comments and Discussions