神经网络最全面的总结,零基础可学,资源来自于CSDN各大热门文章,去其糟粕,取其精华!
目录
1 什么是神经网络
人工神经网络(artificial neural network,缩写ANN),简称神经网络(neural network,缩写NN)或类神经网络,是一种模仿生物神经网络(动物的中枢神经系统,特别是大脑)的结构和功能的数学模型或计算模型,用于对函数进行估计或近似。
神经网络主要由:输入层,隐藏层,输出层构成。当隐藏层只有一层时,该网络为两层神经网络,由于输入层未做任何变换,可以不看做单独的一层。实际中,网络输入层的每个神经元代表了一个特征,输出层个数代表了分类标签的个数(在做二分类时,如果采用sigmoid分类器,输出层的神经元个数为1个;如果采用softmax分类器,输出层神经元个数为2个;如果是多分类问题,即输出类别>=3时,输出层神经元为类别个数),而隐藏层层数以及隐藏层神经元是由人工设定。一个基本的两层神经网络可见下图(注意:说神经网络多少层数的时候一般不包括输入层。 在神经网络中的激活主要讲的是梯度的更新的激活):
2 神经元模型
MP神经元模型接收来自n个其他神经元传递过来的输入信号(x1~xn),这些输入信号通过带权重(θ或ω来表示权重,上图采用θ)的连接(Connection)进行传递,然后神经元(图示阈值为b)收到的总输入(所有输入和权重的乘积的和)与神经元的阈值b比较,并经由激活函数(Activation Function,又称响应函数)处理之后产生神经元的输出。
3 激活函数
3.1 定义
激活函数(Activation Function)是一种添加到人工神经网络中的函数,旨在帮助网络学习数据中的复杂模式。类似于人类大脑中基于神经元的模型,激活函数最终决定了要发射给下一个神经元的内容。
在人工神经网络中,激活函数扮演了非常重要的角色,其主要作用是对所有的隐藏层和输出层添加一个非线性的操作,使得神经网络的输出更为复杂、表达能力更强。通常都是这样解释:不使用激活函数的话,神经网络的每层都只是做线性变换,多层输入叠加后也还是线性变换。因为线性模型的表达能力通常不够,所以这时候就体现了激活函数的作用了,激活函数可以引入非线性因素。
在神经网络中,激活函数决定来自给定输入集的节点的输出,其中非线性激活函数允许网络复制复杂的非线性行为。正如绝大多数神经网络借助某种形式的梯度下降进行优化,激活函数需要是可微分(或者至少是几乎完全可微分的)。此外,复杂的激活函数也许产生一些梯度消失或爆炸的问题。因此,神经网络倾向于部署若干个特定的激活函数(identity、sigmoid、ReLU 及其变体)。
3.2 分类
激活函数能分成两类——饱和激活函数和非饱和激活函数。
3.3 Sigmoid函数
3.3.1 公式
3.3.2 特点
它能够把输入的连续实值变换为0和1之间的输出,特别的,如果是非常大的负数,那么输出就是0;如果是非常大的正数,输出就是1。
Sigmoid函数是深度学习领域开始时使用频率最高的activation function。它是便于求导的平滑函数,其导数为
,这是优点。
3.3.3 适用条件
- Sigmoid 函数的输出范围是 0 到 1。由于输出值限定在 0 到 1,因此它对每个神经元的输出进行了归一化;
- 用于将预测概率作为输出的模型。由于概率的取值范围是 0 到 1,因此 Sigmoid 函数非常合适;
- 梯度平滑,避免「跳跃」的输出值;
- 函数是可微的。这意味着可以找到任意两个点的 sigmoid 曲线的斜率;
- 明确的预测,即非常接近 1 或 0。
3.3.4 缺点
- 容易出现gradient vanishing梯度消失
优化神经网络的方法是Back Propagation,即导数的后向传递:先计算输出层对应的 loss,然后将 loss 以导数的形式不断向上一层网络传递,修正相应的参数,达到降低loss的目的。 Sigmoid函数在深度网络中常常会导致导数逐渐变为0,使得参数无法被更新,神经网络无法被优化。原因在于两点:
-
- 在上图中容易看出,当
中
较大或较小时,导数接近0,而后向传递的数学依据是微积分求导的链式法则,当前层的导数需要之前各层导数的乘积,几个小数的相乘,结果会很接近0。 - Sigmoid导数的最大值是0.25,这意味着导数在每一层至少会被压缩为原来的1/4,通过两层后被变为1/16,…,通过10层后为1/1048576。请注意这里是“至少”,导数达到最大值这种情况还是很少见的。
- 在上图中容易看出,当
- 函数输出并不是zero-centered
Sigmoid函数的输出值恒大于0,这会导致模型训练的收敛速度变慢。举例来讲,对
,如果所有
均为正数或负数,那么其对的导数(导数就是x)总是正数或负数,这会导致如下图红色箭头所示的阶梯式更新,这显然并非一个好的优化路径。深度学习往往需要大量时间来处理大量数据,模型的收敛速度是尤为重要的。所以,总体上来讲,训练深度学习网络尽量使用zero-centered数据 (可以经过数据预处理实现) 和zero-centered输出。
不是zero-centered产生的一个结果就是:如果数据进入神经元的时候是正的
,那么 w 计算出的梯度也会始终都是正的。当然了,如果你是按batch去训练,那么那个batch可能得到不同的信号,所以这个问题还是可以缓解一下的。因此,非0均值这个问题虽然会产生一些不好的影响,不过跟上面提到的 kill gradients 问题相比还是要好很多的。
- 幂运算相对来讲比较耗时
相对于前两项,这其实并不是一个大问题,我们目前是具备相应计算能力的,但面对深度学习中庞大的计算量,最好是能省则省
3.4 tanh函数
3.4.1 公式
tanh读作Hyperbolic Tangent,如上图所示,它解决了zero-centered的输出问题,然而,gradient vanishing的问题和幂运算的问题仍然存在。
tanh 是一个双曲正切函数。tanh 函数和 sigmoid 函数的曲线相对相似。但是它比 sigmoid 函数更有一些优势。
首先,当输入较大或较小时,输出几乎是平滑的并且梯度较小,这不利于权重更新。二者的区别在于输出间隔,tanh 的输出间隔为 1,并且整个函数以 0 为中心,比 sigmoid 函数更好;
在 tanh 图中,负输入将被强映射为负,而零输入被映射为接近零。
注意:在一般的二元分类问题中,tanh 函数用于隐藏层,而 sigmoid 函数用于输出层,但这并不是固定的,需要根据特定问题进行调整。
3.5 ReLU函数
3.5.1 公式
全称是Rectified Linear Unit,中文名字:修正线性单元。
3.5.2优点
- 解决了gradient vanishing问题 (在正区间)
- Sigmoid和Tanh激活函数均需要计算指数, 复杂度高, 而ReLU只需要一个阈值即可得到激活值。ReLU 函数中只存在线性关系,因此它的计算速度比 sigmoid 和 tanh 更快。计算速度非常快,只需要判断输入是否大于0
- 收敛速度远快于sigmoid和tanh
- ReLU的非饱和性可以有效地解决梯度消失的问题, 提供相对宽的激活边界
- ReLU的单侧抑制提供了网络的稀疏表达能力
3.5.3 注意
- ReLU 函数的输出为 0 或正数,不是zero-centered
- Dead ReLU Problem,指的是某些神经元可能永远不会被激活,导致相应的参数永远不能被更新。这是由于函数导致负梯度在经过该ReLU单元时被置为0, 且在之后也不被任何数据激活, 即流经该神经元的梯度永远为0, 不对任何数据产生响应。 当输入为负时,ReLU 完全失效,在正向传播过程中,这不是问题。有些区域很敏感,有些则不敏感。但是在反向传播过程中,如果输入负数,则梯度将完全为零,sigmoid 函数和 tanh 函数也具有相同的问题。有两个主要原因可能导致这种情况产生: (1) 非常不幸的参数初始化,这种情况比较少见; (2) learning rate太高导致在训练过程中参数更新太大,会导致超过一定比例的神经元不可逆死亡, 进而参数梯度无法更新, 整个训练过程失败。解决方法是可以采用Xavier初始化方法,以及避免将learning rate设置太大或使用adagrad等自动调节learning rate的算法。
尽管存在这两个问题,ReLU目前仍是最常用的activation function,在搭建人工神经网络的时候推荐优先尝试!
3.6 Leaky ReLU
3.6.1 公式
人们为了解决Dead ReLU Problem,提出了将ReLU的前半段设为0.01x而非0。
3.6.2 优点
- Leaky ReLU 通过把 x 的非常小的线性分量给予负输入(0.01x)来调整负值的零梯度(zero gradients)问题;
- leak 有助于扩大 ReLU 函数的范围,通常 a 的值为 0.01 左右;
- Leaky ReLU 的函数范围是(负无穷到正无穷)。
注意:从理论上讲,Leaky ReLU 具有 ReLU 的所有优点,而且 Dead ReLU 不会有任何问题,但在实际操作中,尚未完全证明 Leaky ReLU 总是比 ReLU 更好。
3.7 PReLU(Parametric ReLU)
3.7.1 公式
其中
可由back propagation学出来。
看一下 PReLU 的公式:参数α通常为 0 到 1 之间的数字,并且通常相对较小。
- 如果 a_i= 0,则 f 变为 ReLU
- 如果 a_i> 0,则 f 变为 leaky ReLU
- 如果 a_i 是可学习的参数,则 f 变为 PReLU
3.7.2 优点
- 在负值域,PReLU 的斜率较小,这也可以避免 Dead ReLU 问题。
- 与 ELU 相比,PReLU 在负值域是线性运算。尽管斜率很小,但不会趋于0。
4 梯度算法
4.1 梯度
一个向量,导数+变化最快的方向
对w0点进行求导,求得梯度为:
更新w
当Δ w \Delta wΔw>0, 意味着w将增大,反之w将减小。训练模型的过程就是一个不断寻找最小损失值,也就是损失函数全局最优解的过程,通过不断地更新w,寻找函数最小值,由于是寻找最小值,是一个向下寻找的过程,所以称为梯度下降算法。
总结:梯度就是函数参数的变化趋势,若只有一个变量时,就是导数
4.2 梯度消失和梯度爆炸
4.2.1 简介
在反向传播过程中需要对激活函数进行求导,如果导数大于1,那么随着网络层数的增加梯度更新将会朝着指数爆炸的方式增加这就是梯度爆炸。同样如果导数小于1,那么随着网络层数的增加梯度更新信息会朝着指数衰减的方式减少这就是梯度消失。因此,梯度消失、爆炸,其根本原因在于反向传播训练法则,属于先天不足。
4.2.2 原因
1、直接原因
(1)梯度消失
- 隐藏层的层数过多
- 采用了不合适的激活函数(更容易产生梯度消失,但是也有可能产生梯度爆炸)
(2)梯度爆炸
- 隐藏层的层数过多
- 权重的初始化值过大
2、根本原因
(1)隐藏层的层数过多
从深层网络角度来讲,不同的层学习的速度差异很大,表现为网络中靠近输出的层学习的情况很好,靠近输入的层学习的很慢,有时甚至训练了很久,前几层的权值和刚开始随机初始化的值差不多。因此,梯度消失、爆炸,其根本原因在于在于反向传播算法的不足。多个隐藏层的网络可能比单个隐藏层的更新速度慢了几个数量级。
(2)激活函数
BP算法基于梯度下降策略,以目标的负梯度方向对参数进行调整,计算梯度包含了是对激活函数进行求导,如果此部分大于1,那么层数增多的时候,最终的求出的梯度更新将以指数形式增加,即发生梯度爆炸,如果此部分小于1,那么随着层数增多,求出的梯度更新信息将会以指数形式衰减,即发生了梯度消失。
可见左边是sigmoid导数的图像,最大值0.25,如果使用sigmoid作为激活函数,其梯度是不可能超过0.25的,这样经过反向传播的链式求导之后,很容易发生梯度消失。所以说,sigmoid函数一般不适合用于神经网络中。
同理,tanh作为激活函数,它的导数如右图,可以看出,tanh比sigmoid要好一些,但是它的导数仍然是小于1的。也可能会发生梯度消失问题。
(3)初始权重过大
当网络初始权重比较大的情况下,当反向传播的链式相乘时,前面的网络层比后面的网络层梯度变化更快,最终的求出的梯度更新将以指数形式增加,将会导致梯度爆炸。所以,在一般的神经网络中,权重的初始化一般都利用高斯分布(正态分布)随机产生权重值。
4.2.3 解决办法
梯度消失和梯度爆炸问题都是因为网络太深,网络权值更新不稳定造成的,本质上是因为梯度反向传播中的连乘效应。对于更普遍的梯度消失问题,可以考虑一下以下方案解决:
1、用ReLU、Leaky-ReLU、P-ReLU、R-ReLU、Maxout等
详细的可以查看我前面的文章:常用的激活函数合集(详细版)_输入层 一般 用 什么激活函数-CSDN博客
(1)Relu激活函数
Relu思想也很简单,如果激活函数的导数为1,那么就不存在梯度消失爆炸的问题了,每层的网络都可以得到相同的更新速度,relu就这样应运而生。
relu的主要贡献在于:解决了梯度消失、爆炸的问题计算方便,计算速度快加速了网络的训练。
缺点:由于负数部分恒为0,会导致一些神经元无法激活(可通过设置小学习率部分解决)、输出不是以0为中心的。
(2)Leak-Relu、Elu等激活函数
Leak-Relu就是为了解决relu的0区间带来的影响;Elu激活函数也是为了解决relu的0区间带来的影响。
2、Batch Normalization
论文:https://arxiv.org/pdf/1502.03167v3.pdf
那么反向传播过程中权重的大小影响了梯度消失和爆炸,BN就是通过对每一层的输出规范为均值和方差一致的方法,消除了权重带来的放大缩小的影响,进而解决梯度消失和爆炸的问题,或者可以理解为BN将输出从饱和区拉到了非饱和区(比如Sigmoid函数)。
Batch Normalization作用
(1)允许较大的学习率
(2)减弱对初始化的强依赖性
(3)保持隐藏层中数值的均值、方差不变,让数值更稳定,为后面网络提供坚实的基础
(4)有轻微的正则化作用(相当于给隐藏层加入噪声,类似Dropout)
3、LSTM的结构设计也可以改善RNN中的梯度消失问题。
LSTM论文:https://arxiv.org/pdf/1909.09586v1.pdf、https://www.bioinf.jku.at/publications/older/2604.pdf
RNN论文:https://arxiv.org/pdf/1409.2329.pdf
在RNN网络结构中,由于使用Logistic或者Tanh函数,所以很容易导致梯度消失的问题,即在相隔很远的时刻时,前者对后者的影响几乎不存在了,LSTM的机制正是为了解决这种长期依赖问题。LSTM 有通过精心设计的称作为“门”的结构来去除或者增加信息到细胞状态的能力。门是一种让信息选择式通过的方法。他们包含一个 sigmoid 神经网络层和一个按位的乘法操作。
4、ResNet残差网络
参考网址:梯度消失与梯度爆炸产生原因及解决方法_如何解决梯度消失问题-CSDN博客
论文:https://arxiv.org/pdf/1512.03385v1.pdf
相比较以往的网络结构只是简单的堆叠,残差中有很多跨层连接结构,这样的结构在反向传播时具有很大的好处。
(1)深度网络的退化问题
从经验来看,网络的深度对模型的性能至关重要,当增加网络层数后,网络可以进行更加复杂的特征模式的提取,所以当模型更深时理论上可以取得更好的结果,从下图中也可以看出网络越深而效果越好的一个实践证据。但是更深的网络其性能一定会更好吗?实验发现深度网络出现了退化问题(Degradation problem):网络深度增加时,网络准确度出现饱和,甚至出现下降。这个现象可以在图3中直观看出来:56层的网络比20层网络效果还要差。这不会是过拟合问题,因为56层网络的训练误差同样高。我们知道深层网络存在着梯度消失或者爆炸的问题,这使得深度学习模型很难训练。但是现在已经存在一些技术手段如BatchNorm来缓解这个问题。因此,出现深度网络的退化问题是非常令人诧异的。
(2)残差学习
对于一个堆积层结构(几层堆积而成)当输入为 X 时其学习到的特征记为 H(x) ,现在我们希望其可以学习到残差 F(X)=H(X)-X ,这样其实原始的学习特征是 F(X)+X 。之所以这样是因为残差学习相比原始特征直接学习更容易。当残差为0时,此时堆积层仅仅做了恒等映射,至少网络性能不会下降,实际上残差不会为0,这也会使得堆积层在输入特征基础上学习到新的特征,从而拥有更好的性能。残差学习的结构如下图所示。这有点类似与电路中的“短路”,所以是一种短路连接(shortcut connection)。
为什么残差学习相对更容易,从直观上看残差学习需要学习的内容少,因为残差一般会比较小,学习难度小点。不过我们可以从数学的角度来分析这个问题,首先残差单元可以表示为:
其中x_l和 x_l+1 分别表示的是第 l 个残差单元的输入和输出,注意每个残差单元一般包含多层结构。 F是残差函数,表示学习到的残差,而 h(x)=x 表示恒等映射, f 是ReLU激活函数。基于上式,我们求得从浅层 l 到深层 L 的学习特征为:
利用链式规则,可以求得反向过程的梯度:
式子的第一个因子∂loss/∂x_l表示的损失函数到达 L 的梯度,小括号中的1表明短路机制可以无损地传播梯度,而另外一项残差梯度则需要经过带有weights的层,梯度不是直接传递过来的。残差梯度不会那么巧全为-1,而且就算其比较小,有1的存在也不会导致梯度消失。所以残差学习会更容易。要注意上面的推导并不是严格的证明。
5、预训练加微调
论文地址:https://www.cs.toronto.edu/~hinton/science.pdf
此方法来自Hinton在2006年发表的一篇论文,Hinton为了解决梯度的问题,提出采取无监督逐层训练方法,其基本思想是每次训练一层隐节点,训练时将上一层隐节点的输出作为输入,而本层隐节点的输出作为下一层隐节点的输入,此过程是逐层预训练(pre-training);在预训练完成后,再对整个网络进行“微调”(fine-tunning)。Hinton在训练深度信念网络(Deep Belief Networks)中使用了这个方法,在各层预训练完成后,再利用BP算法对整个网络进行训练。此思想相当于是先寻找局部最优,然后整合起来寻找全局最优,此方法有一定的好处,但是目前应用的不是很多了。
6、梯度剪切
梯度剪切这个方案主要是针对梯度爆炸提出的,其思想是设置一个梯度剪切阈值,然后更新梯度的时候,如果梯度超过这个阈值,那么就将其强制限制在这个范围之内。这可以防止梯度爆炸。
7、权重正则化
权重正则化(weithts regularization)是一种解决梯度爆炸的方式。正则化是通过对网络权重做正则限制过拟合,仔细看正则项在损失函数的形式:
其中 α 是指正则项系数,因此,如果发生梯度爆炸,权值的范数就会变的非常大,通过正则化项,可以部分限制梯度爆炸的发生。
- 权重正则化,L1和L2正则化
- L1正则化可以产生稀疏权值矩阵,即产生一个稀疏模型,可以用于特征选择,一定程度上,L1也可以防止过拟合
- L2正则化可以防止模型过拟合(overfitting)
4.2.4 影响
梯度消失发生时,接近于输出层的隐藏层由于其梯度相对正常,所以权值更新时也就相对正常,但是当越靠近输入层时,由于梯度消失现象,会导致靠近输入层的隐藏层权值更新缓慢或者更新停滞。这就导致在训练时,只等价于后面几层的浅层网络的学习。
当梯度爆炸发生时,初始的权值过大,靠近输入层的权值变化比靠近输出层的权值变化更快,就会引起梯度爆炸的问题。最终导致
(1)模型型不稳定,更新过程中的损失出现显著变化。
(2)训练过程中,模型损失变成 NaN。
5 神经网络模型
5.1 单层神经网络(感知机)
1、结构
如图所示,输入层接收输入信号之后传输给输出层,输出层即阈值逻辑单元(MP神经元)。通过感知机可以轻易地实现逻辑与、或、非运算。
通过感知机实现逻辑运算,在MP神经元模型中,有输出:
假设激活函数为阶跃函数sgn(x):
则逻辑运算实现如下:
- 逻辑“与”(x1∧x2):令权重ω1=ω2=1,阈值b=2,则y=f(1x1 + 1x2 -2),当且仅当x1=x2=1时,y=1;
- 逻辑“或”(x1∨x2):令权重ω1=ω2=1,阈值b=0.5,则y=f(1x1 + 1x2 -0.5),当x1 = 1 或 x2=1时,y=1;
- 逻辑“非”(﹁x1):令权重ω1=-0.6 ω2=0,阈值b=-0.5,则y=f(-0.6*x1 + 0.5),当x1=1时,y=0,当x1=0时,y=1。
我们通过制定权重和阈值得到了可以进行逻辑运算的感知机,那么如果给定训练数据集,同样我们可以通过学习得到相应地权重和阈值。
阈值b可以看做是一个输入固定为-1.0对应连接权重ωn+1的哑结点。通过这样定义阈值,则可以将学习权重和阈值简化为只学习权重。
感知机的学习规则很简单,对于训练样本(x,y),若感知机当前的输出为y',则感知机的权重调整如下:
其中,η为学习速率。若感知机对样本的预测正确的话,即y'=y,则感知机不发生任何变化。若其预测错误,则根据错误的程度进行相应权重的调整。
感知机中,只有输出层神经元进行激活函数的处理,也就是说感知机只有一层功能神经元(Functional Neuron),因此感知机的学习能力有限。实际上,通过感知机所实现的逻辑运算都是线性可分问题。
若两类模式是线性可分的,那么存在一个线性超平面能将其分开,则感知机的学习过程一定会收敛从而得到合适的权向量:
否则,感知机在学习的过程中会产生震荡,从而无法得到稳定的权向量,从而使得感知机无法求解。也就是说,感知机无法解决像是“异或XOR”(异或是非线性可分的问题)这样的非线性问题。
如上图中,左面三个是通过线性分割实现,而最右侧的异或则无法通过线性分割实现。
5.2 多层神经网络
其中
为输入层的值,
,表示第 k 层中,第 i 个神经元的激活值(该神经元的输出),
表示第 k 层的神经元个数。当 k=1时即为输入层,即
,而
为偏置项。
为了求最后的输出值
,我们需要计算隐藏层中每个神经元的激活值
。而隐藏层/输出层的每一个神经元,都是由上一层神经元经过类似逻辑回归计算而来。我们可以使用下图进行理解:
我们使用
来表示第 k 层的参数(边权),其中下标 j 表示第 k+1 层的第 j 个神经元,i 表示第 k 层的第 i 个神经元。于是我们可以计算出隐藏层的三个激活值:
再将隐藏层的三个激活值以及偏置项
用来计算出输出层神经元的激活值即为该神经网络的输出:
其中 g(z) 为非线性变换函数(激活函数)。
相关矩阵的维度:
- w[i]=[n[i], n[i-1]],维度是:n[i]行,n[i-1]列。从图中可知行数是本层神经元的数量,列数是前一层神经元的数量。
- b[i]=[n[i], 1],维度是:n[i]行,1列
- a[i]=z[i]=[n[i], 1],维度是:n[i]行,1列。由正向传播公式:a[i]=g[i](z[i]),可知a与z的维度是相同的。
- a[0]:输入层,a[i] :第 i+1 层的输入