神经网络入门 第二部分

来源:互联网 发布:软件介绍ppt 编辑:程序博客网 时间:2024/04/20 00:54

【原文:http://blog.sina.com.cn/s/blog_6a67b5c50100tspe.html】

【翻译】AI:神经网络入门 第二部分

 

英文原文链接:http://www.codeproject.com/KB/recipes/Backprop_ANN.aspx

作者:Sacha Barber

翻译:本站(http://hi.baidu.com/ebfok)原创

说明:翻译力求保持原貌,删去了一些无关紧要的内容;水平有限,错误难免;转载请注明出处。

-------------------------------------------------------------------------------------

什么是XOR问题,如下面的真值表所示:

神经网络入门 <wbr>第二部分

新的神经网络是什么样的

能解决XOR问题的新的神经网络看起来就像是一个单层网络。我们面对的仍然是输入/权值/输出。新东西是隐含层。

神经网络入门 <wbr>第二部分

通过使用输入和权值我们能计算出给定节点的激活状态。对隐含层来说这很容易办到,因为它与输入层是直接相连的。

输出层与输入层是隔离的,所以为了计算出输出节点的激活状态,需要利用隐含层的输出,也就是输出层节点的输入。

上面的整个过程可以看成是从一层到下一层的前向传播过程。

这和单层网络仍是类似的,任何给定节点的激活状态也仍按下面的方法计算:

神经网络入门 <wbr>第二部分

wi  weight(i), Ii input(i)

学习的类型

有两种学习类型:加强型和监督型

加强型学习

在加强型学习中,当训练时,一组输入提交到神经网络,输出是0.75,期望输出是1.0

误差(1.0 - 0.75)被用来训练。

当有2个输出,总误差是2个输出误差的和,这等于是说“所有输出上的总误差是1.76

注意这是说你错得有多么严重,而不是说你错再什么方向。

使用这种方法是用也得不到结果的。

监督型学习

监督型学习中网络被提供更多的信息。不只是告诉网络错得有多严重,而且还告诉错再什么方向。

学习算法

训练神经网络的步骤如下:

  • 随机生成权值(和偏置)
  • 测试训练集中的数据,看误差有多大
  • 微调权值,以便改善输出
  • 尝试新的训练集或者重复训练原来的训练集
  • 重复以上过程直到得到精确的输出

本文就是按以上步骤来解决XOR问题的,这也被叫做“反向传播”(BPBackProp

反向传播利用输出误差来调节输出层的权值,不仅如此,还能计算上一层的误差,并用这个误差来调整那里的权值,余类推。

采用S函数作为非线性传递函数是个技巧,之所以使用S函数,是因为它是可微分的。

神经网络入门 <wbr>第二部分

S函数完美地可微分,所以有

神经网络入门 <wbr>第二部分

delta_outputs[i] = outputs[i] * (1.0 - outputs[i]) * (targets[i] - outputs[i])

正是使用这种算法才使得权值增量能在网络中反向传播。

值得注意的地方

存在着这样的凹部,两边十分陡峭,而往底部则倾斜得较轻微,梯度下降时,时间浪费在在凹部的两边上上下下的过程中。(想想球吧!)

神经网络入门 <wbr>第二部分

所以应该怎么办呢?可以加个动量项,就能抵消上面的那种来回往复的运动,并且加强任何一致的方向,这样就能更加快速的下降到谷底。

神经网络入门 <wbr>第二部分

开始训练

从下面这段代码开始:

/// 主训练过程。期望输出值以参数形式传入。神经网络通过微调权值而更新。加入了动量项以确保训练/// 朝正确的方向进行。我设法避免出现上面所说的凹部。

/// 参数:一个 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

神经网络入门 <wbr>第二部分

值得人们花点时间研究下的主要的类有:

  • NN_Trainer_XOR : 训练神经网络以解决XOR问题
  • TrainerEventArgs : 训练事件参数,用于GUI
  • NeuralNetwork : 可调的神经网络
  • NeuralNetworkEventArgs : 训练事件参数,用于GUI
  • SigmoidActivationFunction :S型激活函数

程序演示

神经网络入门 <wbr>第二部分

由图可见,XOR问题几乎被解决了,但是不能达到100%的精度

训练结果

 

 

神经网络入门 <wbr>第二部分

 

神经网络入门 <wbr>第二部分

神经网络入门 <wbr>第二部分

 

神经网络入门 <wbr>第二部分

神经网络入门 <wbr>第二部分


0 0
原创粉丝点击