神经网络异或学习

Neural network XOR learning

我正在努力测试我的神经网络是否正常工作,我已经尝试使用 XOR,因为这是简单的测试用例。

XOR 是一个好的测试用例还是我应该使用其他东西?

我已经在 Ada 中设置了我的神经网络代码,并且我已经在 this tutorial 之后建模。我的神经网络(2 输入、3 隐藏、1 输出)无法学习 XOR。以下代码有什么问题?

with Ada.Text_IO;use Ada.Text_IO;
with Ada.Float_Text_IO;use Ada.Float_Text_IO;
with Ada.Numerics.Generic_Elementary_Functions;


procedure Main is

   Learning_Rate : Float := 0.5;

   function Sigmoid(X : Float) return Float is
      package Math is new Ada.Numerics.Generic_Elementary_Functions(Float); use Math;
      e : constant Float := 2.7;
   begin
      return 1.0 / (1.0 + e**(-X));
   end;

   function Sigmoid_Derivative (X : Float) return Float is
   begin
      return Sigmoid(X) * (1.0 - Sigmoid(X));
   end;


   type Float_Array is array (Positive range <>) of Float;
   type Node;
   type Node is record
      S : Float := 0.0; --Summation
      Y : Float := 0.0; --Output
      W : Float_Array(1..10) := (others => 0.0); --Weigths
      D : Float := 0.0; --Delta error
   end record;
   type Layer is array (Positive range <>) of Node;



   --Forward calculations

   procedure Calculate_Summation (N : in out Node; L : in Layer) is
   begin
      N.S := 0.0;
      for Index in L'Range loop
         N.S := N.S + L(Index).Y * N.W(Index);
      end loop;
   end;

   procedure Calculate_Summation (Destination : in out Layer; Source : in Layer) is
   begin
      for N of Destination loop
         Calculate_Summation(N, Source);
      end loop;
   end;

   procedure Calculate_Output (L : in out Layer) is
   begin
      for N of L loop
         N.Y := Sigmoid(N.S);
      end loop;
   end;


   --Backpropogation

   procedure Calculate_Delta (L : in out Layer; N : in Node ) is
   begin
      for Index in L'Range loop
         L(Index).D := L(Index).D + N.D * N.W(Index);
      end loop;
   end;

   procedure Calculate_Delta (Destination : in out Layer; Source : in Layer) is
   begin
      for N of Source loop
         Calculate_Delta(Destination, N);
      end loop;
   end Calculate_Delta;


   function Calculate_Delta_Weight(D, S, X : Float) return Float is
   begin
      return Learning_Rate * D * Sigmoid_Derivative(S) * X;
   end;


   --Weight adjustment

   procedure Calculate_Weight(N : in out Node; L : in Layer) is
   begin
      for Index in L'Range loop
         N.W(Index) := N.W(Index) + Calculate_Delta_Weight(N.D, N.S, L(Index).Y);
      end loop;
      N.D := 0.0;
   end;

   procedure Calculate_Weight(Destination : in out Layer; Source : in Layer) is
   begin
      for N of Destination loop
         Calculate_Weight(N, Source);
      end loop;
   end;

   LI : Layer(1..2);
   LH : Layer(1..3);
   LO : Layer(1..1);

   procedure Learn (A, B, Target : Float) is
   begin

      LI(1).Y := A;
      LI(2).Y := B;

      Calculate_Summation( Source => LI, Destination => LH );
      Calculate_Output(LH);

      Calculate_Summation( Source => LH, Destination => LO );
      Calculate_Output(LO);

      LO(1).D := Target - LO(1).Y;

      Put("A,B,T ="); Put(A, 3,3,0);Put(B, 3,3,0);Put(Target, 3,3,0);
      Put("     Y ="); Put(LO(1).Y, 3,3,0);
      Put("     D ="); Put(LO(1).D, 3,3,0);

      Calculate_Delta(Source => LO, Destination => LH);

      Calculate_Weight(Source => LH, Destination => LO);
      Calculate_Weight(Source => LI, Destination => LH);

   end;


begin

   for I in 1..1000 loop
      Learn(1.0, 1.0, 0.0);New_Line;
      Learn(1.0, 0.0, 1.0);New_Line;
      Learn(0.0, 1.0, 1.0);New_Line;
      Learn(0.0, 0.0, 0.0);New_Line;
      New_Line;
   end loop;
end Main;

最后的输出是:

A,B,T =  1.000  1.000  0.000     Y =  0.497     D = -0.497
A,B,T =  1.000  0.000  1.000     Y =  0.495     D =  0.505
A,B,T =  0.000  1.000  1.000     Y =  0.494     D =  0.506
A,B,T =  0.000  0.000  0.000     Y =  0.505     D = -0.505

其中 Y 是神经网络的输出,T 是想要的目标。

一些建议:

  • 考虑将程序的一部分拆分成一个包。
  • 考虑以所需的精度声明您自己的浮点类型。
  • 考虑将 Node 设为判别类型,并将层的输入数量作为判别式。
  • 运行 一个简单的纸上测试用例,并验证您的实现得到的结果是否与您手动解决问题时得到的结果相同。

这些建议都不一定能解决您的问题,但希望它们能让您更轻松地找到解决方案。

XOR 是神经网络的一个很好的测试用例,因为它不能由感知器解决。反向传播是一种简单的梯度下降技术,具有许多众所周知的缺陷。大多数现代 NN 训练使用二阶导数信息,从而实现更稳健和快速的训练。

首先,你的权重应该被初始化,最好是随机值。例如,Ada.Numerics.Float_Random.Random( foo );
其次,如果添加偏置输入(常数输入,例如 1.0),您的网络应该会学得更好

有了这个,D 应该开始向 0.0 收敛。

在这种情况下,您可以通过打印网络中的所有 inputs/outputs 和权重(包括隐藏层)来帮助自己。在您的情况下,会出现一个不应该存在的模式(所有权重均为 0.0 的结果)