2014-01-06 3 views
5

Обновление 1/6/2014: Я обновил вопрос, чтобы попытаться решить нелинейное уравнение. Как многие из вас указали, мне не нужна дополнительная сложность (скрытый слой, сигмоидная функция и т. Д.), Чтобы решить нелинейную проблему.Использование нейронной сети для решения формулы Y = X * X + b

Кроме того, я понимаю, что мог бы решить даже нелинейные проблемы, подобные этому, используя другие средства, помимо нейронных сетей. Я не пытаюсь написать наиболее эффективный код или наименьшее количество кода. Это чисто для меня, чтобы лучше изучить нейронные сети.

Я создал свою собственную реализацию распространенной нейронной сети с обратной связью.

Он отлично работает при обучении для решения простых операций XOR.

Однако теперь я хочу приспособить его & Обучить его, чтобы решить формулы Y = X * X + B, но я не получаю ожидаемых результатов. После обучения сеть не вычисляет правильные ответы. Нейронные сети хорошо подходят для решения таких уравнений алгебры? Я понимаю, что мой пример тривиален. Я просто пытаюсь узнать больше о нейронных сетях и их возможностях.

Мой скрытый слой использует функцию активации сигмоида, а мой выходной уровень использует функцию идентификации.

Если бы вы смогли проанализировать мой код и указать какие-либо ошибки, я был бы вам признателен.

Вот мой полный код (C# .NET):

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

namespace NeuralNetwork 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine("Training Network..."); 

      Random r = new Random(); 
      var network = new NeuralNetwork(1, 5, 1); 
      for (int i = 0; i < 100000; i++) 
      { 
       int x = i % 15; 
       int y = x * x + 10; 
       network.Train(x); 
       network.BackPropagate(y); 
      } 

      //Below should output 20, but instead outputs garbage 
      Console.WriteLine("0 * 0 + 10 = " + network.Compute(0)[0]); 

      //Below should output 110, but instead outputs garbage 
      Console.WriteLine("10 * 10 + 10 = " + network.Compute(10)[0]); 

      //Below should output 410, but instead outputs garbage 
      Console.WriteLine("20 * 20 + 10 = " + network.Compute(20)[0]); 
     } 
    } 

    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 static double HyperTanFunction(double x) 
     { 
      if (x < -10.0) return -1.0; 
      else if (x > 10.0) return 1.0; 
      else return Math.Tanh(x); 
     } 

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

     public static double IdentityFunction(double x) 
     { 
      return x; 
     } 

     public static double IdentityDerivative() 
     { 
      return 1; 
     } 
    } 

    public class Neuron 
    { 
     public bool IsInput { get { return InputSynapses.Count == 0; } } 
     public bool IsHidden { get { return InputSynapses.Count != 0 && OutputSynapses.Count != 0; } } 
     public bool IsOutput { get { return OutputSynapses.Count == 0; } } 
     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() 
     { 
      var d = InputSynapses.Sum(a => a.Weight * a.InputNeuron.Value) + Bias; 
      return Value = IsHidden ? NeuralNetwork.SigmoidFunction(d) : NeuralNetwork.IdentityFunction(d); 
     } 

     public virtual double CalculateDerivative() 
     { 
      var d = Value; 
      return IsHidden ? NeuralNetwork.SigmoidDerivative(d) : NeuralNetwork.IdentityDerivative(); 
     } 

     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(); 
     } 
    } 
} 

ответ

1

вы используете сигмовидной в качестве выходного funnction который в в диапазоне [0-1] но целевое значение двойной диапазон [0 - MAX_INT]., Я думаю, что это основная resaon почему вы получаете NAN я обновляю ваш код и пытаюсь нормализовать значение в диапазоне от [0-1], , и я могу получить такой результат, который я ожидаю

Я думаю, что я приближаюсь к истине, я не знаю, почему этот ответ получает голос вниз enter image description here

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

namespace NeuralNetwork 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine("Training Network..."); 

      Random r = new Random(); 
      var network = new NeuralNetwork(1, 3, 1); 
      for (int k = 0; k < 60; k++) 
      { 
       for (int i = 0; i < 1000; i++) 
       { 
        double x = i/1000.0;// r.Next(); 
        double y = 3 * x; 
        network.Train(x); 
        network.BackPropagate(y); 
       } 
       double output = network.Compute(0.2)[0]; 
       Console.WriteLine(output); 
      } 
      //Below should output 10, but instead outputs either a very large number or NaN 
      /* double output = network.Compute(3)[0]; 
      Console.WriteLine(output);*/ 
     } 
    } 

    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 = .2; 
      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 static double HyperTanFunction(double x) 
     { 
      if (x < -10.0) return -1.0; 
      else if (x > 10.0) return 1.0; 
      else return Math.Tanh(x); 
     } 

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

     public static double IdentityFunction(double x) 
     { 
      return x; 
     } 

     public static double IdentityDerivative() 
     { 
      return 1; 
     } 
    } 

    public class Neuron 
    { 
     public bool IsInput { get { return InputSynapses.Count == 0; } } 
     public bool IsHidden { get { return InputSynapses.Count != 0 && OutputSynapses.Count != 0; } } 
     public bool IsOutput { get { return OutputSynapses.Count == 0; } } 
     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() 
     { 
      var d = InputSynapses.Sum(a => a.Weight * a.InputNeuron.Value);// + Bias; 
      return Value = IsHidden ? NeuralNetwork.SigmoidFunction(d) : NeuralNetwork.IdentityFunction(d); 
     } 

     public virtual double CalculateDerivative() 
     { 
      var d = Value; 
      return IsHidden ? NeuralNetwork.SigmoidDerivative(d) : NeuralNetwork.IdentityDerivative(); 
     } 

     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(); 
     } 
    } 
} 
+0

Спасибо. Нормализация входов действительно помогла. Мне придется больше исследовать, почему это помогает. Однако теперь, когда я пересмотрел вопрос как нелинейную проблему, нормализация, похоже, больше не работает корректно. – craigrs84

+0

Я думаю, что это сигмоидальная функция, когда значение ввода велико, выходное значение скрытого слоя будет равно 0, так же как и градиент скрытого слоя, я нормализую вход в [0 - 1], результат в значительной степени объяснимый – michaeltang

0

Я не анализировал свой код, это слишком долго. Но я могу дать вам ответ на основной вопрос:

Да, нейронные сети хорошо подходят для таких проблем.

В самом деле, для f : R -> R в виде ax+b=y вы должны использовать один нейрон с линейной функцией активации. Трехслойной структуры не требуется, достаточно одного нейрона. Если в этом случае ваш код не работает, тогда у вас есть ошибка реализации, так как это простая задача линейной регрессии, решаемая с помощью градиентного спуска.

+0

Пожалуйста, оставьте комментарий для «-1» голос exaplining что неправильно в предоставленном ответ – lejlot

+0

Спасибо за информацию. Извините, это было не мной, что было подано. Имеет смысл, что этот тип решения проблем не требует многослойной и сигмоидной активации. Однако, если бы я переключил формулу алгебры от линейной функции на нечто вроде y = x * x + 1, то я бы потребовал сигмоидный плюс многослойный правильный? – craigrs84

+0

Да, как только вы перейдете к классу нелинейных функций, вам понадобится один скрытый слой нелинейных функций активации (как утверждает теория универсальной аппроксимации). – lejlot

1

Вам действительно не нужно использовать многоуровневую сеть для решения задач ax + b = y. Однозначный персептрон сделал бы трюк.

На самом деле, для решения этой проблемы вам даже не нужно выходить из строя реальной нейронной сети.Проверьте это сообщение в блоге:

http://dynamicnotions.blogspot.co.uk/2009/05/linear-regression-in-c.html

Смежные вопросы