感知神经网络--教学

原文,所有图片,代码来源,源代码的下载都可以到下列的链接:

http://blog.refu.co/?p=935

原文作者是:

Lefteris


这个教程通过第一个发明的神经网络结构----感知神经网络来给读者介绍神经网络的概念。感知神经网络(perception neural networks)的提出可以追溯到1945年。感知神经网络与现在的神经网络比有许多的缺陷,但是对于想要学习这个领域的人来说,这是一个很好的起点。如果你需要可以直接拿代码来看看(作者在原文中提供了代码的下载),但是更明智的做法是去理解感知器是如何工作的以及这背后的理论知识。

教程前提知识
读者对C/C++有基本了解
读者会使用任何流行的C编译器去编译以及运行程序

教程目的
读者会了解到神经网络的概念
读者会了解到感知器(perception)是如何工作的
读者应用感知器去解决一个简单的问题----区分不同的RGB颜色

希望本教程对那些想学习神经网络的人有帮助。一点点的历史,一点点的人工神经网络与生物上的神经网络的关系,以及很多的C++代码的例子将会是你即将看到的。我不能说这个教程的代码最好地实现了一个感知器,但这些代码已经足够说明问题以及给那些感兴趣的人一个简单的对感知器的代码实现。

首先让我们看看什么是神经网络!神经网络是一个抽象的数学模型,这个数学模型基于大脑工作的方式。比如说们的大脑,它有10^11 神经元(neuron),这些神经元组成了一个强大的大规模并行计算机器。这些神经元通过突触(synapse)进行交流,如图1所示。每个神经元有很多树枝状突(dentrite),这些是接受器(receptor),用来接受其他的突触以及接收其他神经元传来的信号。此外,每个神经元有一个轴突(axon),用来向其他神经元传递信号。从图一可以看到,这个信号传递的过程是以电化学的方式完成的,更加深入的解释已经超出本教程的范围了。如果想更深入的了解大脑如何工作,我推荐一本书 Neuroscience, Exploring the brain by Mark F. Bear, Barry W.Connors and Michael A. Paradiso。这本书用一种让非医药的学生,甚至是我都能明白的方式对此做了很好的解释。
A neuron
图片1:神经元

人工神经网络与生物学的神经网络之间的关联是神经元以及神经元之间的连接。 此外,他们是非常不同的两种机器。人工神经网络(ANN)是由McCulloch 和 Pitts首先提出的,当时叫做感知器(perceptron)。感知器的结构非常简单。它的基本形式就是有一个神经元组成如图2所示。很多个输入通过突触与神经元相连,每个突触对应于一个权重(w1至w4)。这些权重决定了每个连接的重要性,就是说,这些权重决定了所对应的连接对于这个神经元最后输出的结果作出多少贡献。所以,一个神经元的作用就是输出所有输入的加权和(即用输入乘以相应的权重,在把这些结果加起来)。然后,神经元会把这个加权和输入到一个激励函数(an activation function)中,以便得到一个归一化和平滑的结果。
The perceptron
图2:感知器
经常用到的激励函数有:

阈函数(the threshold function)
如果x>=0,f(x)=1。否则,f(x)=0。

s形函数(the Sigmoid function)
f(x)=1/(1+e^-x)

双曲正切函数(the hyperbolic tangent function)
f(x)=(e^2x-1)/(e^2x+1)

如我们之前所说,感知器计算输入的加权和,那么它是如何学习的呢?它怎么知道每个输入的模式对应哪个输出?答案就是,它并不知道!你,或者其他人要作为一个老师,一个监督者去教它,也因此这是一个有监督的学习。每个输入都与一个目标输出关联起来。感知器要做的就是找到联系输入和目标输出的那个函数。这可以通过一个简单的规则来完成:
W(n) = W(n+1) + η(d(n)-y(n))*x(n)     规则一
上式中,W(n) 是旧的权重向量,W(n+1)是新的权重向量,η是由用户定义的常数,叫做学习步长。d(n)是目标向量,y(n)是神经网络的实际输出,x(n)就是相应的输入啦!

这就是感知器背后的理论知识啦。但是谁喜欢理论知识?我们想要看到的是代码,对吗?现在就让我们看看代码吧。我们将要解决一个简单的问题。
int ourInput[] = {
    //RED GREEN BLUE CLASS
    0, 0, 255, CLASS_BLUE,
    0, 0, 192, CLASS_BLUE,
    243, 80, 59, CLASS_RED,
    255, 0, 77, CLASS_RED,
    77, 93, 190, CLASS_BLUE,
    255, 98, 89, CLASS_RED,
    208, 0, 49, CLASS_RED,
    67, 15, 210, CLASS_BLUE,
    82, 117, 174, CLASS_BLUE,
    168, 42, 89, CLASS_RED,
    248, 80, 68, CLASS_RED,
    128, 80, 255, CLASS_BLUE,
    228, 105, 116, CLASS_RED
    };


这是一个装着我们这个例子的输入(输入模式)的数组。他们是RGB颜色值以及相应的所属类别。只有两个类别,ClASS_RED如果红颜色占据主导的话,同样的,CLASS_BLUE如果蓝颜色占据主导的话。很简答吧?现在继续要建一个可以区分这两个类别的感知器。下面就是我们的感知器类。
enum activationFuncs {THRESHOLD = 1, SIGMOID, HYPERBOLIC_TANGENT};
    class Perceptron
    {
    private:
    std::vector<float> inputVector; //a vector holding the perceptron's inputs
    std::vector<float> weightsVector;//a vector holding the corresponding inputs weights.
    int activationFunction;
    public:
    Perceptron(int inputNumber,int function);//the constructor
    void inputAt(int inputPos,float inputValue);//the input population function
    float calculateNet();//the activation function type
    void adjustWeights(float teachingStep, float output, float target);
    float recall(float red,float green,float blue);//a recall for our example program
    };


这个类有输入,权重还有激励函数,这些我们上面都提过了。这个神经网络的初始权重向量是-0.5和0.5之间的随机数。因为我们的输入时RGB值,RGB值是在0到255之间的数,我们要对他们进行归一化,让它们变成在0到1之间的数。让我们看看代码是如何实现的。下面的代码是从主函数中抽取的一小段代码
    //let's create a perceptron with 3 inputs,
    //using the sigmoid as the activation function
    Perceptron ann(3,SIGMOID);
    float mse = 999;
    int epochs = 0;
    //The training of the neural network
    while(fabs(mse-LEASTMEANSQUAREERROR)>0.0001)
    {
    mse = 0;
    float error = 0;
    inputCounter = 0;
    //Run through all 13 input patterns, what we call an EPOCH
    for(int j= 0; j < inputPatterns; j++)
    {
    for(int k=0; k< 3; k++)//give the 3 RGB values to the network
    {
    ann.inputAt(k,normalize(ourInput[inputCounter]));
    inputCounter++;
    }
    //let's get the output of this particular RGB pattern
    output = ann.calculateNet();
    error += fabs(ourInput[inputCounter]-output); //let's add the error for this iteration to the total error
    //and let's adjust the weughts according to that error
    ann.adjustWeights(TEACHINGSTEP,output,ourInput[inputCounter]);
    inputCounter++;//next pattern
    }
 
    mse = error/inputPatterns; //Compute the mean square error for this epoch
    printf("The mean square error of %d epoch is %.4f \r\n",epochs,mse);
    epochs++;
    }

这就是感知器的训练过程了。当均方误差(mean square error)大于定义好的最小均方误差,我们就要再迭代程序,即让所有的输入模式再次走一遍程序。对于每个输入模式,我们用现在的权重去计算神经网络的输出。然后,我们计算实际输出与现在计算到输出之间的差别的绝对值。因而,我们就调整了权重向量根据上面提到的规则一。然后,我们接着进行下一个输入模式的计算。这个过程一直进行到均方误差达到某个值。

如果均方误差足够小,那么我们就说神经网络已经训练好了。因为我们举的这个例子的问题只有很少的输入,很容易解决,所以最小均方误差定为0.0001。均方误差设置的越小,感知器越能解决你提供的数据的分类问题。但这不是说,它能更好地解决这类问题。如果均方误差设置太小的话,这个感知器就过训练了。就是说这个感知器只能很好的解决你提供的数据的分类问题,其他新的输入模式将不能很好地被分类。如果真是这样,那么这个神经网络没有推广的能力,就是说你的神经网络不能正确地学到解决问题的方法。

好了,让我们看看如何用不同的输入调用这个神经网络。

int R,G, B;
    char reply = ' ';
    while(reply != 'N')
    {
    printf("Give a RED value (0-255)\n\r");
    cin>>R;
    printf("Give a GREEN value (0-255)\n\r");
    cin>>G;
    printf("Give a BLUE value (0-255)\n\r");
    cin>>B;
    result = ann.recall(normalize(R),normalize(G),normalize(B));
    if(result > 0.5)
    printf("The value you entered belongs to the BLUE CLASS\n\r");
    else
    printf("The value you entered belongs to the RED CLASS\n\r");
 
    printf("Do you want to continue with trying to recall values from the perceptron?");
    printf("\n\r Press any key for YES and 'N' for no, to exit the program\n\r");
    cin>>reply;
    }



你可以看到上述代码,用户可以连续地输入一些值,然后神经网络给一个回复。如果神经网络得到足够的训练,这个神经网络会正确地分类输入的颜色值,除了那些非常靠近蓝色和红色之间的边缘地带的那些颜色值。而这也是感知器的最重要的缺陷。它只能解决线性的分类问题,如图三所示。如果问题只是线性的分类问题,感知器很适用。但是对于非线性的问题,感知器就不适用了。
Linear separation
图3:线性分类

Marvin Minsky 写了一本书Perceptrons(1969),里面说到,感知器甚至不能解决就如异或问题(XOR problem)这样简单的问题,因为异或问题不是线性可分的。他的这本书导致了所谓人工智能寒冬(AI winter), 就是说让人工智能的研究远离神经网络。 感知器被狠狠的重击,被认为是无用之物。幸运的是,直到1986年,神经网络又回来了,并且成为了人工智能的主流研究。而这因为多层感知器(multi-layer perceptrons)以及反向传播(back-propagation)学习规则的出现。这填补了简单感知器的缺陷。你可以继续多层感知器的学习。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值