Sunday, January 5, 2014

Simple C# Artificial Neural Network

Artificial intelligence interests me, especially when modeled from or inspired by biology. Artificial neural networks are one such example:

"Artificial neural networks are computational models inspired by animals' central nervous systems (in particular the brain) that are capable of machine learning and pattern recognition. They are usually presented as systems of interconnected "neurons" that can compute values from inputs by feeding information through the network." - Wikipedia

I'm not going to try explain how artificial neural networks work. The topic is much too complex and there is already good documentation available elsewhere. If you are interested in learning more about artificial neural networks then I recommend the following article: Neural Network Back-Propagation Using C#. Most of the code in this post is based on the ideas presented in that article.

There are many different types of artificial neural networks. My implementation is a feed-forward, multi-layer, perceptron network which uses the back-propagation algorithm for learning. I believe this is one of the most common types of neural networks and is a good place to start for beginners. I'm still a beginner myself; I understand the basic concepts but the math is still slightly mysterious. Hopefully I can find time in the future to learn more about neural networks and artificial intelligence.

I tried to make the code as simple as possible. Code is below:

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

namespace NeuralNetwork
{
    class Program
    {
        static void Main(string[] args)
        {
            var network = new NeuralNetwork(2, 3, 1);

            Console.WriteLine("Training Network...");
            for (int i = 0; i < 100000; i++)
            {
                network.Train(0, 0);
                network.BackPropagate(1);

                network.Train(1, 0);
                network.BackPropagate(0);

                network.Train(0, 1);
                network.BackPropagate(0);

                network.Train(1, 1);
                network.BackPropagate(1);
            }

            double error;
            double output;

            output = network.Compute(0, 0)[0];
            error = network.CalculateError(1);
            Console.WriteLine("0 XOR 0 = " + output.ToString("F5") + ", Error = " + error.ToString("F5"));

            output = network.Compute(1, 0)[0];
            error = network.CalculateError(0);
            Console.WriteLine("1 XOR 0 = " + output.ToString("F5") + ", Error = " + error.ToString("F5"));

            output = network.Compute(0, 1)[0];
            error = network.CalculateError(0);
            Console.WriteLine("0 XOR 1 = " + output.ToString("F5") + ", Error = " + error.ToString("F5"));

            output = network.Compute(1, 1)[0];
            error = network.CalculateError(1);
            Console.WriteLine("1 XOR 1 = " + output.ToString("F5") + ", Error = " + error.ToString("F5"));
        }
    }

    public class NeuralNetwork
    {
        public double LearnRate { get; set; }
        public double Momentum { get; set; }
        public List<Neuron> InputLayer { get; set; }
        public List<Neuron> HiddenLayer { get; set; }
        public List<Neuron> OutputLayer { get; set; }
        static Random random = new Random();

        public NeuralNetwork(int inputSize, int hiddenSize, int outputSize)
        {
            LearnRate = .9;
            Momentum = .04;
            InputLayer = new List<Neuron>();
            HiddenLayer = new List<Neuron>();
            OutputLayer = new List<Neuron>();

            for (int i = 0; i < inputSize; i++)
                InputLayer.Add(new Neuron());

            for (int i = 0; i < hiddenSize; i++)
                HiddenLayer.Add(new Neuron(InputLayer));

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

        public void Train(params double[] inputs)
        {
            int i = 0;
            InputLayer.ForEach(a => a.Value = inputs[i++]);
            HiddenLayer.ForEach(a => a.CalculateValue());
            OutputLayer.ForEach(a => a.CalculateValue());
        }

        public double[] Compute(params double[] inputs)
        {
            Train(inputs);
            return OutputLayer.Select(a => a.Value).ToArray();
        }

        public double CalculateError(params double[] targets)
        {
            int i = 0;
            return OutputLayer.Sum(a => Math.Abs(a.CalculateError(targets[i++])));
        }

        public void BackPropagate(params double[] targets)
        {
            int i = 0;
            OutputLayer.ForEach(a => a.CalculateGradient(targets[i++]));
            HiddenLayer.ForEach(a => a.CalculateGradient());
            HiddenLayer.ForEach(a => a.UpdateWeights(LearnRate, Momentum));
            OutputLayer.ForEach(a => a.UpdateWeights(LearnRate, Momentum));
        }

        public static double NextRandom()
        {
            return 2 * random.NextDouble() - 1;
        }

        public static double SigmoidFunction(double x)
        {
            if (x < -45.0) return 0.0;
            else if (x > 45.0) return 1.0;
            return 1.0 / (1.0 + Math.Exp(-x));
        }

        public static double SigmoidDerivative(double f)
        {
            return f * (1 - f);
        }
    }

    public class Neuron
    {
        public List<Synapse> InputSynapses { get; set; }
        public List<Synapse> OutputSynapses { get; set; }
        public double Bias { get; set; }
        public double BiasDelta { get; set; }
        public double Gradient { get; set; }
        public double Value { get; set; }

        public Neuron()
        {
            InputSynapses = new List<Synapse>();
            OutputSynapses = new List<Synapse>();
            Bias = NeuralNetwork.NextRandom();
        }

        public Neuron(List<Neuron> inputNeurons) : this()
        {
            foreach (var inputNeuron in inputNeurons)
            {
                var synapse = new Synapse(inputNeuron, this);
                inputNeuron.OutputSynapses.Add(synapse);
                InputSynapses.Add(synapse);
            }
        }

        public virtual double CalculateValue()
        {
            return Value = NeuralNetwork.SigmoidFunction(InputSynapses.Sum(a => a.Weight * a.InputNeuron.Value) + Bias);
        }

        public virtual double CalculateDerivative()
        {
            return NeuralNetwork.SigmoidDerivative(Value);
        }

        public double CalculateError(double target)
        {
            return target - Value;
        }

        public double CalculateGradient(double target)
        {
            return Gradient = CalculateError(target) * CalculateDerivative();
        }

        public double CalculateGradient()
        {
            return Gradient = OutputSynapses.Sum(a => a.OutputNeuron.Gradient * a.Weight) * CalculateDerivative();
        }

        public void UpdateWeights(double learnRate, double momentum)
        {
            var prevDelta = BiasDelta;
            BiasDelta = learnRate * Gradient; // * 1
            Bias += BiasDelta + momentum * prevDelta;

            foreach (var s in InputSynapses)
            {
                prevDelta = s.WeightDelta;
                s.WeightDelta = learnRate * Gradient * s.InputNeuron.Value;
                s.Weight += s.WeightDelta + momentum * prevDelta;
            }
        }
    }

    public class Synapse
    {
        public Neuron InputNeuron { get; set; }
        public Neuron OutputNeuron { get; set; }
        public double Weight { get; set; }
        public double WeightDelta { get; set; }
        
        public Synapse(Neuron inputNeuron, Neuron outputNeuron)
        {
            InputNeuron = inputNeuron;
            OutputNeuron = outputNeuron;
            Weight = NeuralNetwork.NextRandom();
        }
    }
}

5 comments:

  1. đồng tâm
    game mu
    cho thuê nhà trọ
    cho thuê phòng trọ
    nhac san cuc manh
    số điện thoại tư vấn pháp luật miễn phí
    văn phòng luật
    tổng đài tư vấn pháp luật
    dịch vụ thành lập công ty trọn gói
    lý thuyết trò chơi trong kinh tế học
    đức phật và nàng audio
    hồ sơ mật dinh độc lập audio
    đừng hoang tưởng về biển lớn ebook
    chiến thắng trò chơi cuộc sống ebook
    bước nhảy lượng tử
    ngồi khóc trên cây audio
    truy tìm ký ức audio
    mặt dày tâm đen audio
    thế giới như tôi thấy ebook

    “Thực chiến chính là cách tốt nhất để tiến bộ.” Phương pháp này có thể làm cho tu vi nhanh chóng tiến bộ, nếu cứ một mình khổ tu thì không biết bao giờ mới đột phá được. Lưu Phong lúc này đã phát hiện ra đạo lý này.

    “Tiếp tục” Lưu Phong hét lớn, hào khí can vân, nhuyễn kiếm trong tay phát ra ánh sáng kì dị, khi mờ khi tỏ, một đạo kiếm khí màu trắng thế như lôi đình oanh kích từ đầu mũi kiếm phóng ra bắn thẳng tới đạo nhân.

    “Không hay!” Đạo nhân không ngờ đối phương hiếu chiến như thế, chưa đứng vững, vội vàng hít sâu một hơi, tập trung toàn lực nghênh thủ.

    Hai đạo nhân ảnh lại xoắn lấy nhau giữa không trung, kiếm quang tung bay phấp phới, xung khí ngập trời, trong chốc lát lại trải qua mười chiêu nữa.

    Lúc mới giao đấu, song phương xem ra là bình thủ, thế nhưng càng đánh đạo nhân càng tỏ ra yếu thế, nhanh chóng lâm vào thế hạ phong, chỉ còn có thể chống đỡ. Còn Lưu Phong thì càng đánh càng hăng. Kiếm chiêu phát ra càng nhuần nhuyễn, liên miên bất tuyệt, dường như là vô hạn. Khả năng chiến đấu so với lúc trước dường như đã là một người hoàn toàn khác.


    “Choeng!”

    Song kiếm chạm nhau, song phương lùi lại một chút, lại tiếp tục lao vào nhau.

    ReplyDelete
  2. Aren't you teaching the neural network the XNOR rules instead of the XOR rules ? 0 XOR 0 = 0, 1 XOR 0 = 1, 0 XOR 1 = 1 and 1 XOR 1 = 0. So XOR results should be close to 0 1 1 0 yours are 1 0 0 1.

    ReplyDelete
  3. Oops yes I think you're right. My mistake

    ReplyDelete
  4. Oops yes I think you're right. My mistake

    ReplyDelete
    Replies
    1. No need to be sorry, just wanted to point it out. I mean it clearly shows that you can train the network what you want it to learn, even "false rules" :D

      Delete