AI:初学者神经网络(第 3 部分,共 3 部分)






4.90/5 (97投票s)
AI:神经网络导论(多层网络/通过微生物遗传算法训练)。
引言
本文是即将发布的系列文章中的第三篇。拟议的文章内容如下
- 第一部分:介绍感知器网络(单层神经网络)
- 第二部分:将介绍多层神经网络,以及反向传播训练方法,用于解决非线性分类问题,例如XOR逻辑门。这是感知器无法做到的。本文对此进行了进一步解释。
- 第三部分:介绍如何使用遗传算法(GA)训练多层神经网络来解决某些逻辑问题;如果您以前从未接触过遗传算法,那么我可能位于此处的另一篇文章可能是您开始学习基础知识的好地方。
摘要
本文将介绍如何使用微生物遗传算法来训练多层神经网络以解决XOR逻辑问题。
简要回顾(来自第一部分和第二部分)
在深入探讨这篇关于多层神经网络的新文章之前,让我们回顾一下几个关键概念。如果您还没有阅读第一部分或第二部分,也许您应该从那里开始。
第一部分:感知器配置(单层网络)
图4中的输入(x1,x2,x3..xm)和连接权重(w1,w2,w3..wm)通常是实数值,既有正值(+)也有负值(-)。如果某个xi的特征倾向于使感知器激发,则权重wi将为正;如果特征xi抑制了感知器,则权重wi将为负。
感知器本身由权重、求和处理器、激活函数和一个可调阈值处理器(以后称为偏置)组成。
为方便起见,通常的做法是将偏置视为另一个输入。下图说明了修改后的配置
偏置可以看作是感知器无论其输入如何都倾向于激发的特性(一种倾向于某种行为方式的特性)。图5所示的感知器配置网络在加权和>0时会激发,或者如果您喜欢数学解释的话。
第二部分:多层配置
将要解决XOR问题的多层网络看起来与单层网络相似。我们仍然处理输入/权重/输出。新的是增加了隐藏层。
如上文所述,有一个输入层、一个隐藏层和一个输出层。
通过使用输入和权重,我们可以计算给定节点的激活。隐藏层很容易做到这一点,因为它直接连接到实际的输入层。
然而,输出层对输入层一无所知,因为它不直接连接到输入层。因此,为了计算输出节点激活,我们需要利用隐藏层节点的输出来作为输出层节点的输入。
上述整个过程可以看作是从一层到下一层的正向传递。
这仍然像单层网络那样工作;任何给定节点的激活仍然按以下方式计算
其中wi是权重(i),Ii是输入(i)值。您看到它仍然是老一套,没有恶魔、烟雾或魔法。这是我们已经讲过的内容。
所以,这就是网络的结构。现在,我想您想知道如何着手训练它。
学习
神经网络本质上可以应用两种类型的学习:“强化学习”和“监督学习”。
强化学习
在强化学习中,在训练期间,将一组输入呈现给神经网络。当目标期望值为1.0时,输出为0.75。误差(1.0 - 0.75)用于训练(“错误0.25”)。如果有两个输出呢?然后将总误差相加得到一个数字(通常是平方误差之和)。例如,“所有输出的总误差为1.76”。请注意,这仅告诉您错误有多大,而没有告诉您错误的方向。使用此方法,我们可能永远无法获得结果,或者可能在“大海捞针”。
使用遗传算法训练多层神经网络提供了一种强化类型的训练安排,其中突变负责“稍微调整权重”。这正是本文的主题。
监督式
在监督学习中,神经网络会获得更多信息。不仅仅是“错了多少”,而是“错了哪个方向”,例如“大海捞针”,但您被告知“往北一点”“往西一点”。因此,在监督学习中,您获得并使用更多信息,这是神经网络学习算法的常规形式。
这种训练方法通常使用反向传播训练方法进行,我在第二部分中对此进行了介绍,因此,如果您是这三部分文章中的第一篇,并且反向传播方法特别感兴趣,那么您应该去那里看看。
现在是新内容
从现在开始,讨论的任何内容都直接与本文的代码相关。
我们要解决的问题是什么?嗯,这与第二部分的问题相同,就是简单的XOR逻辑问题。事实上,本文的内容确实只是对第一部分和第二部分所涵盖知识的增量构建,所以让我们继续前进。
为了方便只阅读本文的读者,XOR逻辑问题看起来如下真值表
请记住,使用单层(感知器),我们实际上无法实现XOR功能,因为它不是线性可分的。但使用多层网络,这是可以实现的。
因此,考虑到这一点,我们将如何实现这一点?嗯,我们将使用遗传算法(从现在开始称为GA)来繁殖神经网络种群,希望这些种群能够演化以提供XOR逻辑问题的解决方案;这大致就是基本思想。
那么,这一切看起来是什么样的?
从上图可以看出,我们将有一个包含神经网络种群的GA。其思想是,GA将调整种群中神经网络的权重,希望调整权重能够推动神经网络种群朝着解决XOR问题的方向发展。
那么,这如何转化为算法
微生物GA训练的基本操作如下
- 随机选择两个基因型
- 比较分数(适应度)以确定获胜者和失败者
- 沿着基因型前进,在每个位点(点)
因此,**只有**失败者会被改变,这样可以免费获得精英主义的一个版本;这确保了最优的个体保留在种群中。
- 以一定的概率,从获胜者复制到失败者(覆盖)
- 以一定的概率,突变失败者的该位点
就是这样。这就是完整的算法。
但是,在玩GA时,有一些**关键**问题需要注意
- 对于不同的问题域,基因型将不同
- 对于不同的问题域,适应度函数将不同
每当指定新问题时,这两个项目**必须**重新开发。例如,如果我们想找到一个人最喜欢的披萨配料,其基因型和适应度将与本文问题域使用的不同。
GA的这两个基本要素(针对本文的问题域)在下面进行了指定。
1. 基因型
对于本文,问题域表明我们有一个神经网络种群。因此,我创建了一个`NeuralNetwork`对象的单维数组。这可以从`GA_Trainer_XOR`对象中的构造函数代码中看到
//ANN's
private NeuralNetwork[] networks;
public GA_Trainer_XOR()
{
networks = new NeuralNetwork[POPULATION];
//create new ANN objects, random weights applied at start
for (int i = 0; i <= networks.GetUpperBound(0); i++)
{
networks[i] = new NeuralNetwork(2, 2, 1);
networks[i].Change +=
new NeuralNetwork.ChangeHandler(GA_Trainer_NN_Change);
}
}
2. 适应度函数
回想一下问题域描述,我们试图实现的真值表如下
那么,我们如何知道神经网络有多好(有多接近)?这相当简单。我们所做的是一次将所有输入呈现给神经网络,并保持一个累积误差值,该值按以下方式计算
在`NeuralNetwork`类中,有一个`getError(..)`方法如下
public double getError(double[] targets)
{
//storage for error
double error = 0.0;
//this calculation is based on something I read about weight space in
//Artificial Intellegence - A Modern Approach, 2nd edition.Prentice Hall
//2003. Stuart Rusell, Peter Norvig. Pg 741
error = Math.Sqrt(Math.Pow((targets[0] - outputs[0]), 2));
return error;
}
然后在`NN_Trainer_XOR`类中,有一个`Evaluate`方法,它接受一个代表要获取和评估(获取适应度)的种群成员的int
值。然后将此总体适应度返回给GA训练方法,以确定哪个神经网络应该成为获胜者,哪个神经网络应该成为失败者。
private double evaluate(int popMember)
{
double error = 0.0;
//loop through the entire training set
for (int i = 0; i <= train_set.GetUpperBound(0); i++)
{
//forward these new values through network
//forward weights through ANN
forwardWeights(popMember, getTrainSet(i));
double[] targetValues = getTargetValues(getTrainSet(i));
error += networks[popMember].getError(targetValues);
}
//if the Error term is < acceptableNNError value we have found
//a good configuration of weights for teh NeuralNetwork, so tell
//GA to stop looking
if (error < acceptableNNError)
{
bestConfiguration = popMember;
foundGoodANN = true;
}
//return error
return error;
}
那么,我们如何知道何时拥有训练好的神经网络?在这篇文章的代码中,我在`NN_Trainer_XOR`类中提供了一个固定限制值,当达到该值时,表示训练已产生配置最佳的神经网络。
但是,如果整个训练循环完成,但仍没有配置良好的神经网络,我将简单地返回最后一个训练周期获胜者的值作为总体配置最佳的神经网络。
这在下面的代码片段中显示;这应该与上面显示的`evaluate(..)`方法结合阅读
//check to see if there was a best configuration found, may not have done
//enough training to find a good NeuralNetwork configuration, so will simply
//have to return the WINNER
if (bestConfiguration == -1)
{
bestConfiguration = WINNER;
}
//return the best Neural network
return networks[bestConfiguration];
所以,最后是代码
嗯,本文的代码看起来像下面的类图(它是Visual Studio 2005、C#、.NET v2.0)
人们应该花时间查看的主要类是
GA_Trainer_XOR
:使用微生物GA训练神经网络来解决XOR问题。TrainerEventArgs
:训练事件参数,供GUI使用。NeuralNetwork
:可配置的神经网络。NeuralNetworkEventArgs
:训练事件参数,供GUI使用。SigmoidActivationFunction
:提供sigmoid激活函数的静态方法。
其余的是我构建的GUI,只是为了展示所有内容如何协同工作。
**注意**:演示项目包含所有代码,因此我在此不列出。另外请注意,这些类中的大多数与第二部分文章中的代码非常相似。我想让代码保持相似,以便那些已经看过第二部分的人能够识别通用模式。
代码演示
随附的演示应用程序有三个主要区域,如下所述
实时结果标签
可以看到,这几乎解决了XOR问题;尽管如此,它还是花费了近45000次迭代(周期)的训练循环。请记住,我们还必须将整个训练集呈现给网络,并且还要执行两次:一次找到获胜者,一次找到失败者。这是一项相当艰巨的工作,我相信您都会同意。这就是为什么神经网络通常不通过GA进行训练的原因;本文实际上是如何将GA应用于问题域的。因为GA训练需要45000个周期才能产生可接受的结果,但这并不意味着GA是无用的。远非如此,GA有其存在的价值,并且可以用于许多问题,例如
- 数独求解器(流行的游戏)
- 背包问题(尝试优化有限大小背包的使用,以尽可能多地装入物品)
- 最喜欢的披萨配料问题(尝试找出一个人最喜欢的披萨)
等等,基本上,如果您能够提出基因型和适应度函数,您应该能够让GA找出解决方案。GA还被用来生成整个语法树,以预测哪个语法更优。在我写这篇文章的时候,这个领域还有更多的研究;事实上,这里有一篇关于这个主题的好文章(基因表达编程),由Andrew Krillov撰写,就在CodeProject上,如果您想进一步阅读。
训练结果标签
同时查看目标/输出
查看错误
已训练结果标签
同时查看目标/输出
还可以使用“查看神经网络配置”按钮来查看神经网络的最终配置。
您觉得怎么样?
就这样;如果您喜欢这篇文章,请投票支持我。
关注点
我认为AI相当有趣,这就是为什么我花时间发布这些文章。所以,我希望其他人也觉得它有趣,并且它可能有助于进一步提高某人的知识,就像它提高我自己的知识一样。
任何想进一步了解AI方面内容,并且觉得本文内容有点基础的人,都应该查看Andrew Krillov在Andrew Krillov CP文章上的文章,因为他的文章更高级,而且非常好。
历史
- v1.1: 2006/12/27: 修改了`GA_Trainer_XOR`类,使其具有5的随机数种子。
- v1.0: 2006/12/11: 初始文章。
参考文献
- 人工智能第二版,Elaine Rich / Kevin Knight。McGraw Hill Inc。
- 人工智能,一种现代方法,Stuart Russell / Peter Norvig。Prentice Hall。