65.9K
CodeProject 正在变化。 阅读更多。
Home

模糊逻辑 vs.Adaline 神经网络

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.30/5 (8投票s)

2003年10月30日

8分钟阅读

viewsIcon

100300

downloadIcon

1597

一项实验,旨在探究是否可以使用模糊逻辑来复制 Adaline 网络的行为。

引言

今年早些时候,我写了一系列关于神经网络的文章,并附带了类库,老实说,它们编写起来很费力。它们需要时间和开发时间,也需要训练时间,而且即使它们能够正确完成分配的任务,灵活性也不是很高。最近,我一直在研究模糊逻辑和其他一些东西,脑海中一直有一个挥之不去的问题:模糊逻辑是否能够做到神经网络能做到的事情,而且开发起来是否会更简单、更快、更灵活?我不知道这些问题的答案,所以一段时间以来,我一直设法回避它们。

最近,我一直在大力研究 PathFinder 项目,这个项目只是在尝试一些想法,并构建一个框架来开始实现我一直在阅读的一些东西。PathFinder 项目可以在 CodeProject 上找到,链接在此:此处。PathFinder 项目中提出的想法源自复杂性理论的一个分支,称为涌现,许多人可能认为它们本质上是相同的,但这不涉及对定义的争论。涌现和复杂性理论的核心思想之一是简单规则如何导致复杂的行为模式。但这会对编程产生什么影响?如果有的话?以及你如何才能在首先实现它?最后一个问题可能是我在 CodeProject 上所做所有工作的驱动力,而且很可能会在未来继续如此。我的意思是,给文章起个听起来很酷的标题,在文章末尾列出一份令人印象深刻的参考文献列表,这都很好,但我是一名程序员,这里是一个编程网站,老实说,如果我无法实现它并证明它是一个可行的想法,那么它对我来说价值不大。

于是,我发现自己一直在琢磨简单的规则以及代码在低级别包含其行为规则而不是被高层逻辑框架强加的想法。我原以为如果我只在低级别使用简单的接口类,我就能实现这一点。所以我写了它,在写作过程中,我意识到虽然它有效,但它可能并不完全符合人们对模糊逻辑的定义,所以委婉地说,我稍微“弯曲”了一些规则。如果直说,我可以说我根本不在乎它们,完全忽略它们,但更注重实现,我认为我有一个值得长期尝试的想法,看看它会发展成什么样子。

Adaline 神经网络

关于 Adaline 网络的完整文章可以在此处找到。但我会在这里简要介绍一下它的功能,这将为理解文章其余部分的内容提供所需的信息。

Adaline 神经网络是一个具有两个输入节点和一个输出节点的网络。基本上,给定一个训练文件样本,如下所示:

0 0.0527202529146896 0.0353495702312093 -1
1 0.616699623696832 0.198049677162454 -1

这是训练文件中的前两项。第一个数字只是项的编号,可以忽略。然后是两个数字,后面跟着 -1 或 1。网络的工作方式是将这两个数字放入节点,然后调用 run 函数。run 函数的输出将被放入另一个称为输出节点的节点中。这将是一个 -1 或 1 的值。现在,输出节点的值将与训练行末尾的数字进行比较。这个数字代表期望的输出,输出的含义取决于我们如何设置训练文件。例如,上面的两个值都是 -1,这意味着第二个数字小于第一个数字;如果第一个数字小于第二个,则训练文件中的输出值为 1。

此时,我们将忽略网络如何计算这些值的具体细节,而是专注于它的功能。基本上,我们给 Adaline 网络一条规则。这条规则是:如果第一个数字大于第二个数字,我们希望输出为 -1;如果第一个数字不大于第二个数字,我们希望输出为 1。网络通过数学计算出规则的事实,目前并不重要。关键是,如果设置训练文件的人没有完全理解规则,他们就会完全搞乱文件,毁掉网络工作的任何机会。

对于神经网络来说,网络计算输入规则所需的时间称为训练阶段,如果我们想更改规则,就必须重新训练网络,并确保训练文件手动正确。

模糊处理方法

我们从简单的想法开始:好的,我们有两个数字,在某个时刻,我们希望这些数字能够了解将要应用于它们的规则。我们如何将规则应用于这些数字,以便理论上我们可以将不同的规则应用于不同的数字,甚至不同的类对象?好吧,我们从一个接口开始,

public interface IFuzzyBasicComparisonRules
{
   bool IsGreaterThan
   {
      get;
      set;
   }

   bool IsLessThan
   {
     get;
     set;
   }

   bool IsEqual
   {
     get;
     set;
   }
}

IFuzzyBasicComparisonRules 接口的工作原理是:任何我们希望继承的类都可以继承它。使用接口的原因是因为目前我们不知道接口将用于哪个类,也不知道比较规则是否会用于同类型对象之间的比较。我认为我应该明确指出,接口实现的东西本身并不是规则,因为在这个处理简单数字的非常低的级别上,它会涉及太多的逻辑弯曲才能让类正常工作。其思想是,在某个时候,一个类将使用 FuzzyDouble 类,并根据对象内设置的规则来处理 Fuzzy Double。所以,此时,我们只是在设置类型应该遵守的规则。

对于这个项目,该接口在 FuzzyDouble 类中实现,该类与 FuzzyNumber 类的实现方式不同,因为它没有标准的模糊逻辑代码来表示数字未知和具有成员值。它被视为 double 类型的包装器,并且可以执行 double 可以执行的任何操作,并增加了 IFuzzyBasicComaparisonRules 接口的实现。

FuzzyDouble 类实现如下:

public class FuzzyDouble : IFuzzyBasicComparisonRules
{
    private bool bGreaterThan;
    private bool bLessThan;
    private bool bEqual;

    private double dNumber;

它具有用于实现接口的私有成员,以及一个包含类将持有的值的私有 double

接口实现如下:

#region IFuzzyBasicComparisonRules Members

public bool IsGreaterThan
{
    get
    {
        // TODO: Add FuzzyBasicComaparisonRules.IsGreaterThan
        // getter implementation
        return bGreaterThan;
    }
    set
    {
        // TODO: Add FuzzyBasicComparisonRules.IsGreaterThan
        // setter implementation
        bGreaterThan = value;
    }
}

public bool IsLessThan
{
    get
    {
        // TODO: Add FuzzyBasicComparisonRules.IsLessThan
        // getter implementation
        return bLessThan;
    }
    set
    {
        // TODO: Add FuzzyBasicComparisonRules.IsLessThan
        // setter implementation
        bLessThan = value;
    }
}

public bool IsEqual
{
    get
    {
        // TODO: Add FuzzyBasicComparisonRules.IsEqual
        // getter implementation
        return bEqual;
    }
    set
    {
        // TODO: Add FuzzyBasicComparisonRules.IsEqual
        // setter implementation
        bEqual = value;
    }
}

#endregion

它返回实现规则,该规则是 truefalse,具体取决于所选规则。如果您查看上面的图片,它显示了测试应用程序的规则页面,其中包含两条规则:一条规则是左边的数字大于右边的数字,另一条规则是右边的数字大于左边的数字。取决于选中哪个选项,测试结果也会改变。

表单的控制代码如下:

for( int i=0; i<patterns.Count; i++ )
{
   if( this.leftCheckBox.Checked == true )
   {
      ( ( FuzzyDouble )( 
          ( FuzzyPattern )patterns[ i ] ).InSet[ 0 ] ).IsGreaterThan = true;
      ( ( FuzzyDouble )( 
          ( FuzzyPattern )patterns[ i ] ).InSet[ 1 ] ).IsLessThan = true;
   }
   else
   {
      ( ( FuzzyDouble )( 
          ( FuzzyPattern )patterns[ i ] ).InSet[ 0 ] ).IsLessThan = true;
      ( ( FuzzyDouble )( 
          ( FuzzyPattern )patterns[ i ] ).InSet[ 1 ] ).IsGreaterThan = true;
   }
}

richTextBox.AppendText( "Applying the rules\n" );

bool bLeftIsGreater = ( ( FuzzyDouble )( 
   ( FuzzyPattern )patterns[ 0 ] ).InSet[ 0 ] ).IsGreaterThan;
bool bRightIsGreater = ( ( FuzzyDouble )( 
   ( FuzzyPattern )patterns[ 0 ] ).InSet[ 1 ] ).IsGreaterThan;

FuzzyDouble leftValue = null;
FuzzyDouble rightValue = null;

for( int i=0; i<patterns.Count; i++ )
{
   leftValue = ( ( FuzzyDoublePattern )patterns[ i ] ).InputValue( 0 );
   rightValue = ( ( FuzzyDoublePattern )patterns[ i ] ).InputValue( 1 );

   if( bLeftIsGreater == true )
   {
      if( leftValue > rightValue )
      {
         richTextBox.AppendText( "The left value is " + 
           "greater than the right value, left :- " 
           + leftValue.Number.ToString() + ", right :- " 
           + rightValue.Number.ToString() + ", Output value = 1\n" );
      }
      else
      {
         richTextBox.AppendText( "The left value is not " +
           "greater than the right value, left :- " 
           + leftValue.Number.ToString() + ", right :- " 
           + rightValue.Number.ToString() + ", 
           Output value = -1\n" );
      }
   }
   else
   {
      if( rightValue > leftValue )
      {
          richTextBox.AppendText( "The right value is " + 
             "greater than the left value, right :- " 
             + rightValue.Number.ToString() + ", left :- " 
             + leftValue.Number.ToString() + ", 
             Output value = 1\n" );
      }
      else
      {
          richTextBox.AppendText( "The right value is " + 
            "not greater than the left value, right :- " 
            + rightValue.Number.ToString() + ", left :- " 
            + leftValue.Number.ToString() + ", 
            Output value = -1\n" );
      }
   }
}

此代码来自 OnStartTest 函数,第一个 for 循环是为了配合测试代码,在实际应用中,规则很可能不会在实现它们的代码之前立即设置。

在测试训练文件之前,它会被加载到一个 Fuzzy Double Pattern 数组中,这个数组的加载方式与 Adaline 网络加载数据进行处理的方式相同。一旦我们进入第二个 for 循环,我们就会从数组中提取值并测试我们正在使用的规则。请注意,此时我们可以测试每个单独的值是否符合其规则,但由于唯一的选项是为所有值设置一个规则,因此这样做意义不大。然后代码会简单地测试这些值是否遵循应用的规则,并将结果输出到主选项卡页上的文本框中。

最后

通过一种模糊逻辑,可以复制 Adaline 网络的功能,而无需不断地训练程序,并且可以以更快、更灵活的方式实现。可以毫无问题地完全更改此程序的规则,这在使用神经网络时是根本不可能实现的。

总的来说,我认为这个想法具有一定的潜力,值得进一步研究,主要是通过继续研究是否有可能使用这种技术来复制其他类型的神经网络的行为。

参考文献

  • Tom Archer (2001) Inside C#, Microsoft Press
  • Jeffery Richter (2002) Applied Microsoft .NET Framework Programming, Microsoft Press
  • Charles Peltzold (2002) Programming Microsoft Windows With C#, Microsoft Press
  • Robinson et al (2001) Professional C#, Wrox
  • Robert Callan, (1999) The Essence Of Neural Networks, Prentice Hall
  • Timothy Masters (1993) Practical Neural Network Recipes In C++, Morgan Kaufmann (Academic Press)
  • Joey Rogers (1997) Object-Orientated Neural Networks in C++, Academic Press
  • Simon Haykin (1999) Neural Networks A Comprehensive Foundation, Prentice Hall
  • Bernd Oestereich (2002) Developing Software With UML Object-Orientated Analysis And Design In Practice Addison Wesley
  • R Beale & T Jackson (1990) Neural Computing An Introduction, Institute Of Physics Publishing
  • Bart Kosko (1994) Fuzzy Thinking, Flamingo
  • Buckley & Eslami (2002) An Introduction To Fuzzy Logic And Fuzzy Sets, Physica-Verlag
© . All rights reserved.