导言
早期的深度学习受到了神经科学的启发,它们之间有着非常密切的联系,当我们说深度学习时,其实是指深度神经网络的学习。因此在介绍深度学习技术之前,首先要了解神经网络的相关知识。
本章将从神经网络模型出发,介绍3种经典的神经网络模型结构,分别是M-P神经元模型、感知机模型和多层感知机模型。以此为基础,重点讲解输入层、隐藏层、输出层、权值、偏置和激活函数等概念,理解并掌握这些概念对后续学习深度学习非常重要。
其次,在掌握神经网络模型结构的基础上,进入神经网络的训练,这既是本章的重点,也是难点。为此需要了解必要的算法知识,包括前向传播、梯度下降和反向传播算法。有了这些预备知识,读者可以清晰地理解神经网络的整个训练流程。
最后,神经网络在训练过程中常常会产生过拟合的问题,我们会介绍过拟合产生的原因及常用的解决办法,这里介绍正则化和Dropout两种解决方法。
2.1神经网络模型介绍
神经网络(Neural Networks,NN)是一种模仿人类神经元之间信息传递的数学算法模型。本节将介绍3种经典的神经网络模型结构,分别是M-P神经元模型、感知机模型和多层感知机模型。
2.1.1 M-P神经元模型
1943年,心理学家沃伦·麦卡洛克(Warren McCulloch)和数理逻辑学家沃尔特·皮兹(Walter Pitts)建立了神经网络的数学模型,称为M-P模型(以二人的名字命名,又称M-P神经元模型),该模型其实是按照生物神经元的结构和工作原理构造出来的一个抽象和简化了的数学模型。图2.1所示为一个最简单的M-P神经元模型。
结合图2.1,对于某一个神经元j,它可能同时接受了许多个输入信号,用表示,而这些输入信号对神经元的影响是不同的,用权值表示,为阈值(Threshold)。为神经元j的输出,函数称为激活函数(Activation Function)。当输入信号被送往神经元时,会被分别乘以固定的权重(例如,),神经元会计算传送过来的信号总和,只有当这个总和超过了阈值时,神经元才会被激活,否则不会被激活。
图2.1 M-P神经元模型
M-P模型的工作原理可以解释为以下3个步骤:
(1)模型接受N个输入。
(2)将输入与权值参数进行加权求和并经过激活函数激活。
(3)将激活结果作为结果输出。
但是由于M-P模型缺乏学习机制,因此,以M-P模型为基础,学者们开发出了后来的感知机模型,这也是最简单的神经网络模型。
2.1.2 感知机模型
感知机(Perceptron)模型是由美国心理学家弗兰克·罗森布拉特(Frank Rosenblatt)于1957年提出的一种具有单层计算单元的神经网络。它其实就是基于M-P模型的结构开发的。图2.2展示了感知机模型的拓扑结构,它由两层神经元组成,输入层接收外界信号,输出层是许多个并列的M-P神经元,这些M-P神经元被称为处理单元或计算单元。相较于M-P神经元模型,感知机模型其实就是输入、输出两层神经元之间的简单全连接。
图2.2 感知机的拓扑结构图
1.感知机学习机制
Rosenblatt教授给出了感知机模型的学习机制,其过程可以概括如下。
(1)对权值参数进行初始化
(2)将训练集的一个输入值传递到输入层,通过感知机计算输出值(0或1)
(3)比较感知机计算的输出值和真实的输出值是否相同,若输出值小于期望值,则向输出值更大的方向增加相应的权重;若输出值大于期望值,则向输出值更小的方向减少相应的权重。
(4)对训练集中下一个输入值重复步骤(2)和步骤(3),直到感知机计算不再出错。
2.感知机运行原理
以一个接收两个输入信号的感知机为例,介绍感知机的运行原理。假设,是输入信号,,是权重,控制输入信号的重要性,y是输出信号,在感知机中,只有两种输出,其中,0代表“不传递信号”,1代表“传递信号”。当输入信号被送往神经元时,分别乘以各自的权重,然后加总,如果总和超过阈值,则y的输出为1,否则为0。上述内容可以用如式(2.1)表示。
进一步,如果将表示为-b,那么式(2.1)可以改写为式(2.2)。
通常把b称为偏置(Bias),作用是调节神经元被激活的容易程度。式(2.2)可以改写成更加简洁的形式,用函数表示y的输出动作(超过0输出1,否则输出0),于是式(2.2)改写成式(2.3)和式(2.4)。
在式(2.3)中,输入信号的总和会被函数转换,转换后的值就是输出y。式(2.4)表示的函数,当输入超过0时,输出1,否则输出0。因此,式(2.2)、式(2.3)和式(2.4)做的是相同的事情。其中函数就是激活函数,将在2.2节详细讲解有关激活函数的知识。
3.感知机模型的局限性
这种只有输入层和输出层的感知机模型在发展几年后遇到了一些局限,它仅对线性问题具有分类能力。为什么感知机只可以解决线性问题?这是由它本身模型设定决定的,根据式(2.2),当参数,和b已知时,式(2.2)表示的感知机会生成由直线分割开的两个空间,其中一个空间输出1,另一个空间输出0,而该直线就是二维输入样本空间上的一条分界线。它只能表示由一条直线分割的空间,而对由曲线分割而成的非线性空间却无能为力。为了解决单层感知机模型遇到的局限,人们提出了多层感知机模型。
2.1.3 多层感知机模型
多层感知机模型(Multilayer Perceptron,MLP),就是在输入层和输出层之间加入了若干 隐藏层,以形成能够将样本正确分类的凸域,使得神经网络对非线性情况的拟合程度大大增强。具有一个单隐层的多层感知机的拓扑结构如图2.3所示,我们把最左边一列称为输入层,最右边一列称为输出层,中间一列称为隐藏层,其中隐藏层的神经元是肉眼无法看到的。另外,本书把输入层到输出层依次称为第0层、第1层和第2层,因此在图2.3中,第0层对应输入层,第1层对应隐藏层,第2层对应输出层。图2.3的网络虽然一共由3层神经元组成,但实质上只有2层神经元有权重,因此我们习惯将其称为二层网络。
图2.3也被称为 全连接神经网络,全连接是指神经网络模型中相邻两层单元之间的连接方式,使用全连接方式时,网络当前层的单元与网络上一层的每个单元都存在连接。
图2.3具有一个单隐层的多层感知机的拓扑结构
在多层感知机中,信号是如何传递的呢?在图2.3所示的二层感知机中,信号先在第0层和第1层的神经元之间传送和接收,然后在第1层和第2层之间传送和接收,具体过程如下。
(1)第0层的3个神经元接收输入信号,并将信号发送至第1层神经元。
(2)第1层神经元将信号发送至第2层神经元,然后第2层神经元给出最后的输出。
随着隐藏层的增加,多层感知机模型可以解决更复杂的分类问题。多层感知机虽然是非常理想的分类器,但是它的实现充满难度和挑战。面临的问题是隐藏层的权值无法训练,因为对于隐藏层的各个节点,它们并不存在期望的输出值,所以使用单层感知机模型的学习机制来训练多层感知机模型是无效的。
直到20世纪80年代,戴维·鲁梅尔哈特(David E.Rumellhart)和詹姆斯·麦克莱兰(James L.McCelland)在1986年发表的《并行分布式处理》,对具有非线性连续变换函数的多层感知机的误差反向传播(Error Back Propagation,BP)算法进行了详尽的分析,才实现了对多层感知机的训练。将在2.3节详细介绍。
2.2 激活函数
激活函数就是指非线性变换。例如在2.1.2节,式(2.4)表示的激活函数以阈值为界,一旦输入超过阈值,就切换输出,这样的函数称为“阶跃函数”,因此,可以说感知机使用了阶跃函数作为激活函数。
激活函数在神经网络中具有非常重要的作用,如果没有激活函数,多层的神经网络是没有意义的。这是因为,在进行层之间的连接时,实际上是在做一个线性组合,到下一层时依然是上一层节点的线性组合,而线性组合的线性组合依然是线性组合,这实际上与只用单层神经网络是没有区别的。所以,如果对线性组合的结果施加一个非线性变换,就为神经网络各层之间的连接方式提供了一种非线性的变换方法,而非线性变换打破了“线性组合的线性组合”这样一种循环,多层神经网络相比于单层网络有了更丰富的函数形式。
为了保证神经网络的灵活性和计算的复杂度,激活函数的设置一般不会太复杂,本节主要介绍Sigmoid、tanh和Relu三个常用的激活函数,还有很多其他的函数,例如leaky relu、elu、crelu、selu、relu6、softplus、softsign等,在此不做介绍。
2.2.1 sigmoid激活函数
sigmoid激活函数的定义如下所示。
其导数为
图2.4为sigmoid激活函数的图像及其导数,从图2.4中可以看出,sigmoid函数是以S形分布输出为的数。
图2.4 sigmoid激活函数及其导数
TensorFlow通过函数tf.nn.sigmoid(x.name=None)实现sigmoid激活函数,使用示例如下。
import tensorflow as tf
二维张量
t = tf.constant([[1,2],[2,0]],tf.float32)
sigmoid激活
result = tf.nn.sigmoid(t)
创建会话
session = tf.Session
打印结果
print(session.run(result))
输出:
[[ 0.73105860.880797]
[ 0.8807970.5]]
2.2.2 tanh激活函数
tanh激活函数的定义如下。
其导数为
图2.5为tanh激活函数及其导数的图像,可以看到tanh是一个双曲正切函数,取值为。
图2.5 tanh激活函数及其导数
TensorFlow通过函数tf.nn.tanh(x,name=None)实现tanh激活函数,使用示例如下。
import tensorflow as tf
二维张量
t = tf.constant([[1,2],[2,0]],tf.float32)
tanh激活
result = tf.nn.tanh(t)
创建会话
session = tf.Session
打印结果
print(session.run(result))
输出:
[[ 0.76159420.9640276]
[ 0.96402760.]]
2.2.3 Relu激活函数
Relu激活函数的定义如下:
其导数为
图2.6为Relu激活函数及其导数的图像,可以看到Relu函数的取值范围是,其导数取值范围为。
图2.6 Relu激活函数及其导数
TensorFlow通过函数tf.nn.relu(x,name=None)实现Relu激活函数,使用示例如下。
import tensorflow as tf
二维张量
t = tf.constant([[1,2],[2,0]],tf.float32)
relu激活
result = tf.nn.relu(t)
创建会话
session = tf.Session
打印结果
print(session.run(result))
输出:
[[ 1.2.]
[ 2.0.]]
相比于sigmoid函数和tanh函数,Relu函数被证明可以提供更好的结果。如图2.6所示,Relu函数在正半轴和负半轴都是线性的,仅把零点当作拐点,ReLu有非常好的计算性质,它在正负半轴的一阶导数都是常数,并且认为负数没有信息,这会产生稀疏特征,带来稳定的输出结果(因为所有的负数都变成同样一个形式,不再区分)。进一步讲,在非参数统计学中,这是一种特殊的样条函数形式,只要有足够多的函数的线性组合,它就可以任意逼近任何充分光滑的、线性的或者非线性的函数,也就是说,相应的全连接层的函数形式可以是非常的非线性,这就是ReLu的神奇之处。