神经网络详解

一、缘起

原本想沿着 传统递归算法实现迷宫游戏 ——> 遗传算法实现迷宫游戏 ——> 神经网络实现迷宫游戏的思路,在本篇当中也写如何使用神经网络实现迷宫的,但是研究了一下, 感觉有些麻烦不太好弄,所以就选择了比较常见的方式,实现手写数字识别(所谓的MNIST)。

二、人工神经网络简介

从小至蚂蚁(没有查到具体数目,有的说蚂蚁大脑有25万个神经细胞,也有说是50万个),大至大象,蓝鲸等动物,大脑里面都存在着大量的神经元。人或动物的各种行为或者技能,都或多或少的是因为这些由数量庞大的神经元连接而成的神经网络组成。而人工神经网络就是仿造生物的大脑来运作的,所以先来了解一笑生物的大脑(神经网络,神经元)。

2.1 生物学神经网络

先来看一个表格(来自《游戏编程中的人工智能》一书中第七章第二节,表7.1):

动物 神经细胞数目(数量级)
蜗牛 10,000(=104)
蜜蜂 100,000(=105)
蜂雀 10, 000, 000(=107)
老鼠 100, 000, 000(=108)
人类 10, 000, 000, 000(=1010)
大象 100, 000, 000, 000(=1011)

从上表可以即便小如蜗牛也有数量庞大的神经细胞,自然界的动物需要感知环境,适应环境等等能力,就必须要有一套强大的“处理”系统来应对各种突发事件。

从人类和大象的神经细胞数量来看,是否可以推断,表现出来的智能强度,并不一定是和神经细胞的数量成正比的或者说并不是神经细胞越多就越聪明(纯属个人意见)。就好比人工神经网络,机器学习,深度学习等网络一样,并不是层数越多,神经元节点越多久越好的。

生物神经细胞如下图所示:
生物神经细胞

神经细胞之间的信号传递是通过电化学过程完成的,这些信号从一个神经细胞的轴突末梢通过突触(神经细胞轴突末梢与其他神经细胞体,树突相接触的环状或球状结构)传递给下一个神经细胞的树突,然后在从该神经细胞的树突进入细胞体,最后根据实际情况选择是否传递到下一个神经细胞。这里就需要说到神经细胞的两个状态兴奋和不兴奋(即抑制)。 神经细胞利用一种我们还不知道的方法把所有从树突进入到细胞体中的信号进行相加,如果信号总和达到某个阈值(注意:是“阈值”,yu,四声,而不是“阀值”哦,以前不知道,问了一下度娘,才知差别很大),就会激发神经细胞进入兴奋状态,这时电信号就会从当前神经细胞,通过其轴突传递向下一个神经细胞,反之则当前神经细胞就会处于抑制状态。

以上只是较为简单或单纯的神经细胞模型,在实际的大脑中电信号在神经细胞传递,不只是从一个细胞的轴突到另一个细胞的树突,还有其他的传递方向:

  • 轴突——树突——细胞体
  • 轴突——细胞体——树突
  • 树突——细胞体——轴突

对于生物学神经网络有兴趣的可以去网上查找相应的资料,这里只是做一个简单介绍,让我们对神经细胞的基本结构以及神经冲动(电信号)传递的基本方式有一个形象的理解。重点还是人工神经网络的说明。

2.2 人工神经网络——神经细胞

人工神经网络(ANN,Artificial Neuron Network)是模拟生物大脑的神经网络结构,它是由许多称为人工神经细胞(Artificial Neuron,也称人工神经元)的细小结构单元组成。 这里的人工神经细胞可以看作是生物神经细胞的简化版本或模型。
人工神经细胞

如上图所示,就是一个人工神经细胞的示意图,其中

  • x1 … xn:表示神经细胞的输入,也就是输入神经细胞的信号。
  • w1 … wn:表示每个输入的权重,就好比生物神经网络中每个轴突和树突的连接的粗细,强弱的差异。
  • b:偏置权重
  • threshold: 偏置(可以将 threshold * b 看作是前面提到的生物神经细胞的阈值)
  • 蓝色部分:细胞体。
  • 黄色球形是所有输入信号以的求和。
  • 红色部分是表示求和之后的信号的激励函数(即达到阈值就处于兴奋状态,反之抑制,当然作为人工神经细胞,其激励函数很多,阶跃(型)激励函数,sigmoid(s型)激励函数,双曲正切(tanh)激励函数,ReLu(Rectified Linear Units)激励函数等等)。

比较原始的感知机(如需了解什么是感知机,可问度娘)的数学表达式(或模型)如下:

output={01if∑jwjxj<thresholdif∑jwjxj≥thresholdoutput={0if∑jwjxj<threshold1if∑jwjxj≥threshold

从上面的表达式可以看出,在这里,threshold(阈值)也是神经网络的一个参数。更具体的来说,要使神经细胞处于兴奋状态(也就是上面表达式的输出一),就需要满足如下条件:

w1x1+w2x2+w3x3+⋯+wnxn≥tw1x1+w2x2+w3x3+⋯+wnxn≥t

注意: t: threshold(阈值)

网络在进行学习的过程中,人工神经网络(ANN)的所有权重都需要不断演化(进化),threshold(阈值)的数据也不应该例外,也需要做相应的演化,所以有必要将threshold(阈值)转变为权重的形式。 从上面的方程两边同时减去t得到如下形式:

w1x1+w2x2+w3x3+⋯+wnxn−t≥0w1x1+w2x2+w3x3+⋯+wnxn−t≥0

这个方程还可以用另一种形式写出来,如下:

w1x1+w2x2+w3x3+⋯+wnxn+tb≥0w1x1+w2x2+w3x3+⋯+wnxn+tb≥0

注意:其中 b 可以取 1 或 -1, 取 1时,threshold(阈值t)取负值就可以了。

也就是说,可以将b看作一个像w的权重,将t看作像x的输入,其方程可以进一步变为:

w1x1+w2x2+w3x3+⋯+wnxn+wtxb≥0w1x1+w2x2+w3x3+⋯+wnxn+wtxb≥0

2.3 人工神经网络——神经细胞层

动物大脑里的生物神经细胞和其他神经细胞是相互连接在一起的,从而形成了庞大而复杂的神经网络。同理要创建人工神经网络(ANN),人工神经细胞也需要像生物神经细胞那样连接在一起。一个神经细胞可以看成是一个点,大量的神经细胞,就意味着大量的点,要将这些点全部连接起来,可以有很多种连接形式,其中最容易理解并且也是应用也最广泛的是:把神经细胞一层一层的连接在一起,如下图所示:
前馈神经网络

这种类型的神经网络被称为:前馈网络(feedforward network)。这是因为网络的每一层神经细胞的输出都向前馈送(feed)到他们的下一层(如上图中的从左至右的顺序),直至获得整个网络的最终输出。

由上图可知,该网络一共有3层,输入层的每个输入都馈送到了隐含层,作为该层每一个神经细胞的输入; 然后从隐含层的每个神经细胞的输出又再次馈送到它的下一层(即输出层)。

上图中只画了一个隐含层,作为前馈网络,理论上可以有任意多个隐含层,但在处理大多数问题时,通常一个隐含就足够了,而有一些更简单的问题,甚至连隐含层都不需要,直接就是一个输入层和输出层。

注意:这里只是说的简单的全连接神经网络(也就是当前层的每一个神经细胞都的输入都包含前一层的所有神经细胞的输出),对于卷积网络(CNN),,递归网络(RNN), 生成对抗网络(GANs),深度学习,强化学习等,不在讨论的范围之内。

2.4 人工神经网络——演化

一个人工神经网络在创建之后,要能正常的工作,还是要进行一些演化(或者进化,或者学习),就像动物或者人进行学习或练习一样。对于人工神经网络来说,演化的过程就是不断的调整每一层,每一个神经细胞的输入权重。 能够调节神经网络所有神经细胞的输入权重的方式有很多,这里只说反向传播(bp:back propagation)法,下面就详细的说说什么是 反向传播法:

首先,我们要来了解一下,为什么网络需要演化,需要学习。答案当然就是:人工神经网络的输出结果与我们的预期不符,存在偏差。

其次,如何演化,如2.3节中的三层神经网络可知,一个神经网络可能会有很多层,每一层有很多神经细胞,每一个神经细胞都有很多输入,与这些输入对应的就是很多权重。如何才能每一个权重都被调整到呢,反向传播算法是这样做的,首先得到网络的输出层的输出与我们期望之间的误差,然后再将这个误差值反向传播到前一层(隐含层),如此往复,最后就是根据误差,学习率以及当前取值点的梯度来更新每层神经细胞的输入权重,这就是所谓的反向传播算法。而不断调整神经细胞的权重以便输出误差达到最小的过程叫做梯度下降(这是一个寻找极小值的过程,也就是寻找一个偏导数斜率最小的点)。

在百度中查了一下梯度的解释: 在单变量的实值函数的情况,梯度只是导数,或者,对于一个线性函数,也就是线的斜率。
梯度一词有时用于斜度,也就是一个曲面沿着给定方向的倾斜程度。可以通过取向量梯度和所研究的方向的点积来得到斜度。梯度的数值有时也被称为梯度。

所以寻找极小值也就是沿着梯度越来越低的方向不断搜寻,故而叫做梯度下降。

这里的梯度,就是前面提到的激活函数的导函数(不知道如何求导也没关系,因为就目前而言,常用的激活函数以及对应的导函数都可以在网上找到),比如前向传播时,使用的激活函数是sigmoid(s型)函数:

f(x)=11+e(−x)f(x)=11+e(−x)

其中:x:神经细胞所有输入(包括偏置输入)求和之后的值, f(x): 神经细胞的最终输出

其导函数为:

f(x)′=f(x)(1−f(x))f(x)′=f(x)(1−f(x))

换一种形式就是:

f(x)=x(1−x)f(x)=x(1−x)

其中:x:神经细胞的输出: f(x):当前神经细胞的梯度(参见上面对梯度的解释)

下图就是使用Excel绘制的sigmoid函数以及它的导数的波形图
sigmoid函数波形图
通过上面的公式,就将当前神经细胞的输出反向传播到了当前神经细胞的输入侧,而当前神经细胞的每一个输入,代表的都是反向传播方向的下一层神经细胞层的一个神经细胞。 要调整当前神经细胞的输入权重,就代表着,调整反向传播方向的下一层神经层的每一个神经细胞和当前神经细胞的连接权重。其调整幅度为:

ΔWnj=EnLO(n−1)jΔWnj=EnLO(n−1)j

其中: E: 当前神经细胞的反向传播到输入侧的误差, L:学习率, O:前一层某个神经细胞的输出,n:代表第几层神经细胞,j:代表第几个输入或者反向传播方向的下一层中的第几个神经细胞。

对于上公式中的E,在不同的神经层的计算方法略微不同(主要是输出层和隐含层的不同)

其通用计算公式为:

E=e o(1−o)E=e o(1−o)

其中: e: 神经细胞的输出误差, o(1 - o): 就是前面提到的使用sigmoid激活函数时神经细胞的梯度(f(x)=x(1-x))

这里的差异就在于 e的计算:

  • 对于输出层:e = 当前神经细胞的输出 - 预期输出
  • 对于隐含层:反向传播方向的上一层的所有神经细胞乘以与当前神经细胞的连接权重的累加和,其计算公式如下:

e=∑j=0j=ke(n+1)jw(n+1)je=∑j=0j=ke(n+1)jw(n+1)j

其中: j:表示反向传播方向的上一层的第几个神经细胞,n:表示第几层神经网络,n+1:表示在反向传播方向上当前层的上一层,e(n+1)j: 表示反向传播的上一层的第j个神经细胞的输出误差,w(n+1)j:表示当前神经细胞与反向传播方向的上一层的第j个神经细胞的连接权重

整体的反向传播算法的流程如下:

  • 反向传播误差:
    误差反向传播

  • 更新权重(正向传播)
    更新权重

上图中, df(e)dedf(e)de 就是对激活函数求导,如果使用的激活函数是sigmoid(s型函数),那么其就可以用上面的f(x)=x(1-x).

详细的信息(Principles of training multi-layer neural network using backpropagation)可以查看网站: http://galaxy.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html

当然还有另一种反向传播方式,和上面说到的不一样的地方是,每一层神经细胞层反向传播误差之后就计算该层每个神经细胞包含的每个输入对应的权重,然后再反向传播到下一层,再重复权重变化的计算,后面的例子当中就是使用的这种方法,目的是减少循环次数,加快训练速度。

三、总结与后续

神经网络的原理虽然看上去不难,但实现起来还是不太简单,这还是最简单的神经网络,如果是CNN,RNN,深度网络等等那就更加复杂了,且参数之多,也是难以想象的。

第三章的例子还是只比较粗糙的版本,后续还可以添加更多的功能,比如:

  • 将宏定义和网络层数等进行参数化,外部使用ini文件之类的配置文件,测试程序读取这些配置就可以构建和初始化神经网络。
  • 在神经网络类中添加成员函数来提取和设置所有神经细胞的输入权重,这样一个训练好的神经网络,就可以将权重提取出来,保存为一个配置文件,下次就可以直接读取配置文件来初始化权重,这样就不需要每次使用的时候都要先对网络进行演化。
  • 使用遗传算法来演化网络中神经细胞的权重,然后再使用反向传播来训练网络。

一个简单的神经网络的基本知识就是这些了,下一步就需要研究研究 深度学习之类的东东了。

五、完整代码

完整代码时放在开源中国上面,有兴趣的可以抓取来瞧一瞧。其地址如下:

http://git.oschina.net/xunawolanxue.com/digital_recognition_with_neuron_network

原文出处:https://blog.csdn.net/xuanwolanxue/article/details/71565934

猜你喜欢

转载自blog.csdn.net/Torres_10/article/details/82873009