神经网络入门 第二部分
标签:
杂谈 |
分类: 算法 |
|
英文原文链接:http://www.codeproject.com/KB/recipes/Backprop_ANN.aspx 作者:Sacha Barber 翻译:本站(http://hi.baidu.com/ebfok)原创 说明:翻译力求保持原貌,删去了一些无关紧要的内容;水平有限,错误难免;转载请注明出处。 ------------------------------------------------------------------------------------- 什么是XOR问题,如下面的真值表所示: http://www.codeproject.com/KB/recipes/Backprop_ANN/XOR.png 新的神经网络是什么样的 能解决XOR问题的新的神经网络看起来就像是一个单层网络。我们面对的仍然是输入/权值/输出。新东西是隐含层。 http://www.codeproject.com/KB/recipes/Backprop_ANN/Network.png 通过使用输入和权值我们能计算出给定节点的激活状态。对隐含层来说这很容易办到,因为它与输入层是直接相连的。 输出层与输入层是隔离的,所以为了计算出输出节点的激活状态,需要利用隐含层的输出,也就是输出层节点的输入。 上面的整个过程可以看成是从一层到下一层的前向传播过程。 这和单层网络仍是类似的,任何给定节点的激活状态也仍按下面的方法计算: http://www.codeproject.com/KB/recipes/Backprop_ANN/Activation.png wi 是 weight(i), Ii 是input(i) 学习的类型 有两种学习类型:加强型和监督型 加强型学习 在加强型学习中,当训练时,一组输入提交到神经网络,输出是0.75,期望输出是1.0。 误差(1.0 - 0.75)被用来训练。 当有2个输出,总误差是2个输出误差的和,这等于是说“所有输出上的总误差是1.76” 注意这是说你错得有多么严重,而不是说你错再什么方向。 使用这种方法是用也得不到结果的。 监督型学习 监督型学习中网络被提供更多的信息。不只是告诉网络错得有多严重,而且还告诉错再什么方向。 学习算法 训练神经网络的步骤如下:
本文就是按以上步骤来解决XOR问题的,这也被叫做“反向传播”(BP或BackProp) 反向传播利用输出误差来调节输出层的权值,不仅如此,还能计算上一层的误差,并用这个误差来调整那里的权值,余类推。 采用S函数作为非线性传递函数是个技巧,之所以使用S函数,是因为它是可微分的。 http://www.codeproject.com/KB/recipes/Backprop_ANN/sig1.png S函数完美地可微分,所以有 http://www.codeproject.com/KB/recipes/Backprop_ANN/sig2.png 即 delta_outputs[i] = outputs[i] * (1.0 - outputs[i]) * (targets[i] - outputs[i]) 正是使用这种算法才使得权值增量能在网络中反向传播。 值得注意的地方 存在着这样的凹部,两边十分陡峭,而往底部则倾斜得较轻微,梯度下降时,时间浪费在在凹部的两边上上下下的过程中。(想想球吧!) http://www.codeproject.com/KB/recipes/Backprop_ANN/valley.png 所以应该怎么办呢?可以加个动量项,就能抵消上面的那种来回往复的运动,并且加强任何一致的方向,这样就能更加快速的下降到谷底。 http://www.codeproject.com/KB/recipes/Backprop_ANN/momentum.png 开始训练 从下面这段代码开始: /// 主训练过程。期望输出值以参数形式传入。神经网络通过微调权值而更新。加入了动量项以确保训练/// 朝正确的方向进行。我设法避免出现上面所说的凹部。 /// 参数:一个 double[] 数组,包含了期望输出值 private void train_network(double[] target) { //得到动量值 double[] delta_hidden = new double[nn.NumberOfHidden + 1]; double[] delta_outputs = new double[nn.NumberOfOutputs]; // 得到输出层的delta值 for (int i = 0; i < nn.NumberOfOutputs; i++) { delta_outputs[i] = nn.Outputs[i] * (1.0 - nn.Outputs[i]) * (target[i] - nn.Outputs[i]); } //得到隐含层的delta值 for (int i = 0; i < nn.NumberOfHidden + 1; i++) { double error = 0.0; for (int j = 0; j < nn.NumberOfOutputs; j++) { error += nn.HiddenToOutputWeights[i, j] * delta_outputs[j]; } delta_hidden[i] = nn.Hidden[i] * (1.0 - nn.Hidden[i]) * error; } // 更新隐含层和输出层之间的权值 for (int i = 0; i < nn.NumberOfOutputs; i++) { for (int j = 0; j < nn.NumberOfHidden + 1; j++) { //使用动量项,确保朝着正确的方向移动 nn.HiddenToOutputWeights[j, i] += nn.LearningRate * delta_outputs[i] * nn.Hidden[j]; } } //更新输入层和隐含层之间的权值 for (int i = 0; i < nn.NumberOfHidden; i++) { for (int j = 0; j < nn.NumberOfInputs + 1; j++) { //使用动量项,确保朝着正确的方向移动 nn.InputToHiddenWeights[j, i] += nn.LearningRate * delta_hidden[i] * nn.Inputs[j]; } } } 最终的代码 本文中的代码如下面的类图所示(Visual Studio 2005 C#, .NET v2.0) http://www.codeproject.com/KB/recipes/Backprop_ANN/ClassDiagram1.png 值得人们花点时间研究下的主要的类有:
程序演示 http://www.codeproject.com/KB/recipes/Backprop_ANN/LiveResults.png 由图可见,XOR问题几乎被解决了,但是不能达到100%的精度 训练结果 http://www.codeproject.com/KB/recipes/Backprop_ANN/Training1.png http://www.codeproject.com/KB/recipes/Backprop_ANN/Training2.png http://www.codeproject.com/KB/recipes/Backprop_ANN/Trained1.png http://www.codeproject.com/KB/recipes/Backprop_ANN/Trained2.png http://www.codeproject.com/KB/recipes/Backprop_ANN/Config.png |
喜欢
0
赠金笔

加载中…