神经网络概述
神经网络有生物神经网络和人工神经网络两种。
生物神经网络指的是生物的大脑神经元、细胞、触点等组成的网络,用于产生生物的意识,帮助生物进行思考和行动。而我们说的神经网络一般是人工神经网络,故而将人工神经网络简称为神经网络。它是一种生物动物神经网络行为特征进行分布式并行信息处理的算法数学模型,依靠系统的复杂程度,通过调整内部大量节点之间相互连接的关系,从而达到处理信息的目的。
在生物神经网络中,每个神经元与其他神经元相连,当它受到刺激时就会向相连的神经元发送化学物质,从而改变神经元内的电位,当某个神经元的电位超过某一阀值后就会被激活,然后向其他神经元发送化学物质。深度学习正是借鉴了这样的结构,在神经网络中,每一个神经元接收输入x,通过带权重w的连接进行传递,将总输入信号与神经元阀值进行比较,通过激活函数判断是否激活,最终将激活后的计算结果y输出。而神经网络中的训练,训练的则是其中的权重w。
神经元模型
上图所示就是一个神经元模型,包含2个输入、1个输出以及2个计算功能。
神经网络的表示
我们将一个一个的神经元拼接起来,例如拼接成两层神经元,即输入层+输出层(M-P神经元)就构成了一个感知机。继续拼接成多层神经元就构成了神经网络。其中,输入层与输出层直接的所有神经元层我们都称之为隐藏层。
神经网络
一个完整的神经网络如上图所示,输入层与输出层都只有一层,中间的全部都是隐藏层,可以有多层。实际上,输出层有时也可以有多个,例如经典的GoogleNet,后续内容会具体介绍。
激活函数
激活函数是在人工神经网络的神经元上运行的函数,负责将神经元的输入映射到神经元的输出,说白了就是用来判断我们所计算的信息是否达到了后续传输的条件。
激活函数都是非线性的,其目的就是将非线性特性引入到神经网络中,在上述神经元模型中,我们将输入经过加权求和后,在输出前还被作用了一个非线性函数,这个非线性函数就是激活函数,其目的就是为了增加神经网络模型的非线性。
试想一下,如果不用激活函数,每一层输出都是上层输入的线性函数,那么无论神经网络有多少层输出都只是输入的线性组合,就算我们有几千层计算,无非也就是个矩阵相乘,和一层矩阵相乘所获得的信息差距并不大。因此,我们需要借助激活函数来引入非线性因素,使神经网络可以任意逼近任何非线性函数,从而让神经网络可以应用到众多非线性模型中,增加了神经网络模型的泛化能力。
PyTorch中内置了许多可以直接调用的激活函数,下面我们看几个常用的激活函数。
Sigmoid函数
Sigmoid函数是一个在生物学中常见的S型函数,也称为S型生长曲线。在信息科学中,由于其单调递增以及反函数单调递增等性质,Sigmoid函数常常被用作神经网络的阈值函数,将变量映射到0~1之间。函数公式如下(导数为1-f(x)的平方):
Sigmoid函数公式
我们借助PyTorch与Matplotlib画出Sigmoid函数的函数图像。
Sigmoid函数图像
可以看到,Sigmoid函数输出是(0, 1)开区间,能够把输入的连续实数值转换为0~1之间的输出。若输入接近负无穷,那么输出就越接近0,若输入接近正无穷,那么输出就越接近1。
由于Sigmoid函数需要进行指数运算,相对来说运行会较慢,并且函数输出不是以0为中心,使得权重更新的效率降低。在神经网络反向传播的过程中不利于权重的优化。通常我们称这类问题为梯度饱和或梯度弥散。因此在实际应用中,Sigmoid函数用的就比较少了,基本上只有在二元分类问题的输出层中才会使用到。
tanh函数
tanh是双曲线函数中的一个,为双曲正切函数。在数学中,双曲正切“Tanh”是由基本双曲函数双曲正弦和双曲余弦推导而来。函数公式如下(导数为1-f(x)的平方):
tanh函数公式
我们借助PyTorch与Matplotlib画出tanh函数的函数图像。
tanh函数图像
可以看到tanh函数的输出区间为(-1, 1)的开区间,并且整个函数是以0为中心的。与Sigmoid函数类似,当输入稍微远离坐标原点时,梯度就会很小,但相比于Sigmoid函数,tanh函数是以0为中心点的,因此可以起到归一化(均值为0)的效果。
ReLU函数
在实际应用中,对于二分类问题,一般我们会在隐藏层中使用tanh函数,输出层使用Sigmoid函数。不过随着ReLU函数的出现,我们基本上使用ReLU函数代替tanh函数来作为隐藏层的激活函数了。ReLU函数公式如下(大于0时导数为1,小于0时导数为0):
ReLU函数公式
我们借助PyTorch与Matplotlib画出ReLU函数的函数图像。与Sigmoid函数和tanh函数不同的是,ReLU函数在torch.nn.functional中。
ReLU函数图像
当输入大于0时,梯度始终为1,可以提高神经网络基于梯度算法的运算速度。ReLU函数只有线性关系(只需判断输入是否大于0),不管是前向传播还是反向传播都要比Sigmoid函数和tanh函数要快很多。但是当输入小于0时,梯度始终为0,也就是说ReLU函数是完全不被激活的。但在实际应用中,这个影响一般不是很大。
当然,为了解决这一缺陷应运而生了一个Leaky ReLU函数,保证当输入小于0时梯度仍不为0。其做法就是将ReLU前半段设为ax而不是0,一般我们设a=0.01。
理论上来讲,Leaky ReLU比ReLU更优,但在实际操作过程中还尚未被证实。因此ReLU函数目前仍是最常用的激活函数,在隐藏层中往往是优先推荐使用的。
前向传播与反向传播
前向传播
对于一个神经网络来说,把输入特征a[0]这个输入值作为我们的输入x,放入第一层并计算第一层的激活函数,用a[1]表示,本层中训练用W[1]和b[1]表示,这两个值与计算的结果z[1]都需要缓存下来,而计算的结果还需要通过激活函数生成激活后的a[1]作为最终第一层的输出值,这个值会作为第二层的输入传入第二层,第二层训练为W[2]和b[2],计算结果为z[2],经过激活函数生成激活后的a[2]作为第三层的输入传入第三层。以此类推,直至计算出最后L层的通过激活函数生成激活后的a[L],L层最终输出为y,即神经网络最终的预测值。前向传播其实就是我们的输入x,通过一系列的网络计算,得到预测值y的过程。在这个过程里我们缓存的值会在后面的反向传播中用到。
反向传播
反向传播就是对正向传播的一系列反向迭代,通过反向计算梯度,来优化我们需要训练的W和b。把δa[L]值进行求导得到δa[L-1],以此类推,直到我们得到δa[2]和δa[1]。反向传播步骤中也会输出δW[l]和δb[l]。这一步我们已经得到了权重的变化量,接下去就可以通过学习率来对训练的W和b进行更新:W=W-αδW,b=b-αδb。至此,反向传播就完成了。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4729/viewspace-3168340/ ,如需转载,请注明出处,否则将追究法律责任。