人工神经网络知识、激活函数、正则化、优化技术、Batch Normalization、Layer Normalization

版权声明:本文为博主原创文章,转载请注明出处~谢谢! https://blog.csdn.net/SMith7412/article/details/88396674

目录:

1、神经网络基础概念
2、激活函数
3、深度学习中的正则化
4、深度模型中的优化技术
5、batch norm层
6、Layer Normalization

1、神经网络基础概念

前言

对于人工智能,相比大家都经常会听到。各大新闻媒体每天都对一些人工智能项目进行报道,且人工智能如何如何。今天我们就来学习一下人工智能中用到最重要之一的深度学习知识。我们会对神经网络进行介绍,接下来我们就开始吧!

1.1 感知机

介绍神经网络之前,我们介绍一种被称为“感知器”的⼈⼯神经元。下图是一个单层的感知机, 也是我们最常用的神经网络组成单元。感知器是如何⼯作的呢?⼀个感知器接受⼏个⼆进制输⼊,x1,x2,…,并产⽣⼀个⼆进制输出:
在这里插入图片描述
⽰例中的感知器有三个输⼊,x1,x2,x3。通常可以有更多或更少输⼊。引⼊权重,w1,w2,w3,表⽰相应输⼊对于输出重要性的实数。神经元的输出,0或者1,则由分配权重后的总和∑j wjxj⼩于或者⼤于⼀些阈值决定。和权重⼀样, 阈值是⼀个实数,⼀个神经元的参数。⽤更精确的代数形式:
在这里插入图片描述
这就是⼀个感知器所要做的所有事情!
我们来简化感知器的数学描述:
第⼀个变动是把∑j wjxj改写成点乘,w·x ≡∑j wjxj,这⾥w和x对应权重和输⼊的向量。第⼆个变动是把阈值移到不等式的另⼀边,并⽤感知器的偏置b ≡−threshold代替。 ⽤偏置⽽不是阈值,那么感知器的规则可以重写为:
在这里插入图片描述
这样,感知器就可以完成计算基本的逻辑功能了。不过,单层感知器不能完成像异或这样的运算,而多个感知器一起工作,具有强大的功能。

1.2神经网络的基本构架:

在这里插入图片描述
这个⽹络中最左边的称为输⼊层,其中的神经元称为输⼊神经元。最右边的,即输出层包含有输出神经元,在图片中,输出层只有⼀个神经元。中间层,既然这层中的神经元既不是输⼊也不是输出,则被称为隐藏层。上⾯的⽹络仅有⼀个隐藏层,但有些⽹络有多个隐藏层。对于构建复杂的系统,神经网络也会非常复杂,包含很多网络层,而且每一层的神经元个数也会不太一样。
在这里插入图片描述
在神经⽹络中,以上⼀层的输出作为下⼀层的输⼊。这种⽹络被称为前馈神经⽹络。这意味着⽹络中是没有回路的——信息总是向前传播,从不反向回馈。

参考来自:《神经⽹络与深度学习》 一书,作者:(美)MichaelNielsen

对于人工神经网络,一种常见的多层结构的前馈网络(Multilayer Feedforward Network)由三部分组成,

输入层(Input layer),众多神经元(Neuron)接受大量非线形输入消息。输入的消息称为输入向量。
输出层(Output layer),消息在神经元链接中传输、分析、权衡,形成输出结果。输出的消息称为输出向量。
隐藏层(Hidden layer),简称“隐层”,是输入层和输出层之间众多神经元和链接组成的各个层面。隐层可以有一层或多层。隐层的节点(神经元)数目不定,但数目越多神经网络的非线性越显著,从而神经网络的强健性(robustness)(控制系统在一定结构、大小等的参数摄动下,维持某些性能的特性)更显著。习惯上会选输入节点1.2至1.5倍的节点。
这种网络一般称为感知器(对单隐藏层)或多层感知器(对多隐藏层),神经网络的类型已经演变出很多种,这种分层的结构也并不是对所有的神经网络都适用。

2、激活函数

所谓激活函数,就是在神经网络的神经元上运行的函数,负责将神经元的输入映射到输出端。激活函数有线性的和非线性的。激活函数是用来加入非线性因素的,因为线性模型的表达能力不够。

1、线性激活函数:这是一种简单的线性函数,公式为:f(x) = x。基本上,输入到输出过程中不经过修改。
在这里插入图片描述
2、非线性激活函数:用于分离非线性可分的数据,是最常用的激活函数。非线性方程控制输入到输出的映射。非线性激活函数有 Sigmoid、Tanh、ReLU、LReLU、PReLU、Swish 等。下文中将详细介绍这些激活函数。

Sigmoid函数

Sigmoid又叫作 Logistic 激活函数,它将实数值压缩进 0 到 1 的区间内,还可以在预测概率的输出层中使用。该函数将大的
负数转换成 0,将大的正数转换成 1。数学公式为:
在这里插入图片描述

下图展示了 Sigmoid 函数及其导数:
Sigmoid 激活函数
在这里插入图片描述
Sigmoid 导数
在这里插入图片描述
Sigmoid 函数的三个主要缺陷:

  1. 梯度消失:注意:Sigmoid 函数趋近 0 和 1 的时候变化率会变得平坦,也就是说,Sigmoid 的梯度趋近于 0。神经网络使用 Sigmoid 激活函数进行反向传播时,输出接近 0 或 1 的神经元其梯度趋近于 0。这些神经元叫作饱和神经元。因此,这些神经元的权重不会更新。此外,与此类神经元相连的神经元的权重也更新得很慢。该问题叫作梯度消失。因此,想象一下,如果一个大型神经网络包含 Sigmoid 神经元,而其中很多个都处于饱和状态,那么该网络无法执行反向传播。

  2. 不以零为中心:Sigmoid 输出不以零为中心的。

  3. 计算成本高昂:exp() 函数与其他非线性激活函数相比,计算成本高昂。

下一个要讨论的非线性激活函数解决了 Sigmoid 函数中值域期望不为 0 的问题。

Tanh 函数

数学公式:
在这里插入图片描述

Tanh 激活函数
在这里插入图片描述
Tanh 导数
在这里插入图片描述
Tanh 激活函数又叫作双曲正切激活函数(hyperbolic tangent activation function)。与 Sigmoid 函数类似,Tanh 函数也使用真值,但 Tanh 函数将其压缩至-1 到 1 的区间内。与 Sigmoid 不同,Tanh 函数的输出以零为中心,因为区间在-1 到 1 之间。你可以将 Tanh 函数想象成两个 Sigmoid 函数放在一起。在实践中,Tanh 函数的使用优先性高于 Sigmoid 函数。负数输入被当作负值,零输入值的映射接近零,正数输入被当作正值。唯一的缺点是:

  1. Tanh 函数也会有梯度消失的问题,因此在饱和时也会「杀死」梯度。

为了解决梯度消失问题,我们来讨论另一个非线性激活函数——修正线性单元(rectified linear unit,ReLU),该函数明显优于前面两个函数,是现在使用最广泛的函数。

修正线性单元(ReLU)

ReLU 激活函数
在这里插入图片描述
ReLU 导数
在这里插入图片描述
从上图可以看到,ReLU 是从底部开始半修正的一种函数。数学公式为: f(x) = max(0, x)

当输入 x<0 时,输出为 0,当 x> 0 时,输出为 x。该激活函数使网络更快速地收敛。它不会饱和,即它可以对抗梯度消失问题,至少在正区域(x> 0 时)可以这样,因此神经元至少在一半区域中不会把所有零进行反向传播。由于使用了简单的阈值化(thresholding),ReLU 计算效率很高。但是 ReLU 神经元也存在一些缺点:

1、不以零为中心:和 Sigmoid 激活函数类似,ReLU 函数的输出不以零为中心。

2、前向传导(forward pass)过程中,如果 x < 0,则神经元保持非激活状态,且在后向传导(backward pass)中「杀死」梯度。这样权重无法得到更新,网络无法学习。当 x = 0 时,该点的梯度未定义,但是这个问题在实现中得到了解决,通过采用左侧或右侧的梯度的方式。

为了解决 ReLU 激活函数中的梯度消失问题,当 x < 0 时,我们使用 Leaky ReLU——该函数试图修复 dead ReLU 问题。下面我们就来详细了解 Leaky ReLU。

Leaky ReLU

Leaky ReLU 激活函数
在这里插入图片描述
该函数试图缓解 dead ReLU 问题。数学公式为: f(x) = max(0.1x, x)

Leaky ReLU 的概念是:当 x < 0 时,它得到 0.1 的正梯度。该函数一定程度上缓解了 dead ReLU 问题,但是使用该函数的结果并不连贯。尽管它具备 ReLU 激活函数的所有特征,如计算高效、快速收敛、在正区域内不会饱和。

Leaky ReLU 可以得到更多扩展。不让 x 乘常数项,而是让 x 乘超参数,这看起来比 Leaky ReLU 效果要好。该扩展就是 Parametric ReLU。

Parametric ReLU

PReLU 函数的数学公式为:
在这里插入图片描述
其中是超参数。这里引入了一个随机的超参数,它可以被学习,因为你可以对它进行反向传播。这使神经元能够选择负区域最好的梯度,有了这种能力,它们可以变成 ReLU 或 Leaky ReLU。

总之,最好使用 ReLU,但是你可以使用 Leaky ReLU 或 Parametric ReLU 实验一下,看看它们是否更适合你的问题。

Swish

Swish 激活函数
在这里插入图片描述
该函数又叫作自门控激活函数,它近期由谷歌的研究者发布,数学公式为:
在这里插入图片描述
根据论文(https://arxiv.org/abs/1710.05941v1),Swish 激活函数的性能优于 ReLU 函数。
根据上图,我们可以观察到在 x 轴的负区域曲线的形状与 ReLU 激活函数不同,因此,Swish 激活函数的输出可能下降,即使在输入值增大的情况下。大多数激活函数是单调的,即输入值增大的情况下,输出值不可能下降。而 Swish 函数为 0 时具备单侧有界(one-sided boundedness)的特性,它是平滑、非单调的。更改一行代码再来查看它的性能,似乎也挺有意思。

这一部分来自机器之心:https://www.jiqizhixin.com/articles/2017-11-02-26
原文链接:https://www.learnopencv.com/understanding-activation-functions-in-deep-learning/

3、深度学习中的正则化

正则化技术是保证算法泛化能力的有效工具,因此算法正则化的研究成为机器学习中主要的研究主题。此外,正则化还是训练参数数量大于训练数据集的深度学习模型的关键步骤。正则化可以避免算法过拟合,过拟合通常发生在算法学习的输入数据无法反应真实的分布且存在一些噪声的情况。过去数年,研究者提出和开发了多种适合机器学习算法的正则化方法,如数据增强、L2 正则化(权重衰减)、L1 正则化、Dropout、Drop Connect、随机池化和早停等。

数据增强

数据增强是提升算法性能、满足深度学习模型对大量数据的需求的重要工具。数据增强通过向训练数据添加转换或扰动来人工增加训练数据集。数据增强技术如水平或垂直翻转图像、裁剪、色彩变换、扩展和旋转通常应用在视觉表象和图像分类中。

L1 和 L2 正则化

L1 和 L2 正则化是最常用的正则化方法。L1 正则化向目标函数添加正则化项,以减少参数的绝对值总和;而 L2 正则化中,添加正则化项的目的在于减少参数平方的总和。根据之前的研究,L1 正则化中的很多参数向量是稀疏向量,因为很多模型导致参数趋近于 0,因此它常用于特征选择设置中。

机器学习中最常用的正则化方法是对权重施加 L2 范数约束。

标准正则化代价函数如下:
在这里插入图片描述
其中正则化项 R(w) 是:
在这里插入图片描述
另一种惩罚权重的绝对值总和的方法是 L1 正则化:
在这里插入图片描述
对于想深入理解L1、L2 正则化的同学,推荐参考:https://zhuanlan.zhihu.com/p/29360425

Dropout

Dropout 指暂时丢弃一部分神经元及其连接。随机丢弃神经元可以防止过拟合,同时指数级、高效地连接不同网络架构。神经元被丢弃的概率为 1 − p,减少神经元之间的共适应。隐藏层通常以 0.5 的概率丢弃神经元。使用完整网络(每个节点的输出权重为 p)对所有 2^n 个 dropout 神经元的样本平均值进行近似计算。Dropout 显著降低了过拟合,同时通过避免在训练数据上的训练节点提高了算法的学习速度。

Drop Connect

Drop Connect 是另一种减少算法过拟合的正则化策略,是 Dropout 的一般化。在 Drop Connect 的过程中需要将网络架构权重的一个随机选择子集设置为零,取代了在 Dropout 中对每个层随机选择激活函数的子集设置为零的做法。由于每个单元接收来自过去层单元的随机子集的输入,Drop Connect 和 Dropout 都可以获得有限的泛化性能。Drop Connect 和 Dropout 相似的地方在于它涉及在模型中引入稀疏性,不同之处在于它引入的是权重的稀疏性而不是层的输出向量的稀疏性。

早停法(stop early)

早停法可以限制模型最小化代价函数所需的训练迭代次数。早停法通常用于防止训练中过度表达的模型泛化性能差。如果迭代次数太少,算法容易欠拟合(方差较小,偏差较大),而迭代次数太多,算法容易过拟合(方差较大,偏差较小)。早停法通过确定迭代次数解决这个问题,不需要对特定值进行手动设置。

对于正则化,大家可以参考吴恩达的视频,改善深层神经网络:超参数调试、正则化以及优化 这一节,讲的很好!

4、深度模型中的优化技术

基于随机梯度下降的优化算法是机器学习和深度学习中的核心优化算法。该领域中的许多问题都可以看作是最大化和最小化一个参数化的损失函数,在大多数情况下损失函数本身是可微的,由于问题数据规模极大,所以一般情况下获得二阶信息是很难的,存储相应的二阶信息也是消耗非常大的一件事,所以梯度下降,这样一种仅仅要求一阶偏导数的优化算法在这些问题上很有效。而在深度学习领域,即使数据集和网络模型架构完全相同,使用不同的优化算法,也可能得到相差非常大的最终结果,此外,在数据收集和采样进行训练的时候可能会有比较严重的噪声影响,简单的梯度下降方法往往无法奏效,因此,为了弥补朴素梯度下降的种种缺陷,就需要一系列对梯度下降系列优化算法的的改进,也就因此诞生了SGD with momentum, Adagrad,RMSprop,Adam等一系列变种算法。

算法介绍

朴素SGD及mini-batch SGD

朴素SGD即最基本的最速下降法,使用一个梯度步作为方向,步长作为一个可调控因子随时调整,那么可简单写为 在这里插入图片描述
在深度学习的实践当中,通常选择学习率是一个根据迭代次数逐渐衰减的量,即给定一个初始学习率然后让它随时迭代次 数逐渐衰减,或者是训练到一定迭代次数后进行衰减。朴素的SGD的问题就是其收敛速度非常慢,而且容易陷入局部最优点和鞍点,很难从其中逃出。同时,由于学习率在实践中往往是根据经验来调整,而一个合适的学习率调整策略对整个问题的优化过程是十分重要的,所以如何选择这样合适的学习率更是SGD的最大难点。

​ 在深度学习环境下,我们有非常多的训练数据,朴素的想法是对每一个数据使用SGD更新一次,这样能获得很好的对数据的泛化能力,但是与之而相对的,如果数据的分布极不均衡,数据中有很多的噪声,那么这样的策略将会“带偏”我们的模型,因此,一个自然而然的想法就是每次使用一批数据(batch)来计算梯度,然后将梯度平均之后再使用SGD去更新参数,通过平均一批样本的梯度结果来减少震荡和其他影响,这就是所谓的mini-batch SGD的基本思想。在实际操作中,batch的大小一般根据计算资源的存储能力,训练时间开销,泛化能力要求综合来定,batch越小泛化能力越强,但时间开销就大且容易发生震荡,batch越大训练速度越快但是可能丧失一定的泛化能力,所以一般使用权衡两边的mini-batch。

SGD with momentum

上文中提到朴素SGD收敛速度很慢且容易震荡,借用物理中动量的概念,我们希望结合历史的梯度信息和当前梯度信息来共同指导更新,通俗来讲,就是遇到陡坡时,希望运动得更快,遇到复杂的沟壑时,希望借助之前的惯性尽快冲出,遇到突然变化的情况,也希望由于惯性的作用方向不要变化太大。借由以上直觉和概念,就产生带有动量的梯度下降,即SGD with momentum,其表达式为:
在这里插入图片描述
这里 \beta_1 是一个加权因子,一般取0.9,这个形式其实就是对历史的梯度信息做因子为 \beta_1 的指数加权平均,然后结合当前的梯度信息构成下一步更新的方向,由于这个因子大于0.5,这就意味着下降方向主要是此前累积的下降方向,然后略微偏向当前时刻的梯度方向。这样的一种改进,使得参数中那些梯度方向变化不大的维度可以加速更新,同时减少梯度方向变化较大的维度上的更新幅度,由此产生了加速收敛和减小震荡的效果。

Adagrad

​ 之前我们提到的优化算法都是对整个模型的所有参数,以相同的学习率去更新,但是深度学习模型是非常大的,往往有上亿个参数,采用统一的学习率是一种很简单粗暴的策略。而在不同的任务中,不同的网络层的参数所需要的更新频率往往有所区别。对于那些更新不频繁的参数,我们了解到的信息较少,所以希望每次更新时单次步长更大,能够多学习到一些知识,同时对于那些更新非常频繁的参数,我们已经累积了大量关于它的学习经验和知识,所以希望采用较小的步长,不要被一部分样本影响过大,能够学到更稳定的参数值。由此,我们需要一个量来衡量历史更新频率,直观的想法就是二阶动量,即某一维上,迄今为止所有梯度值的平方和,可以写作:
在这里插入图片描述
对于以前更新频繁的参数,其二阶动量对应的分量就比较大,所以对应的学习率就较小,反之就较大。Adagrad也可以说是进入所谓“自适应学习率”的时代。

RMSprop

对于Adagrad,有一个很明显的问题,就是V_t 是一个只会累积增加的量,即是单调递增的,这在稀疏数据场景下表现非常好,但是对于稠密的数据集,这会导致学习率在训练的中后期单调递减至0,对于后续的训练样本,由于学习率已经接近于0,所以模型很难学到新的必要的知识。因此,我们需要对Adagrad做一定的修正,借鉴momentum中对历史信息的处理方式,我们对于二阶动量也采用指数加权平均的方法来处理,不累积全部的历史梯度,而只关注最近某一时间窗口内的梯度累积量,由此便得到了RMSprop:
在这里插入图片描述

Adam

在上面的方法中我们讲到了基于一阶动量和二阶动量的改进方法,那么如果将他们结合起来呢,Adam就是这样一种结合两者的改进优化算法,也是整个SGD系列的集大成者,既包含来自momentum的累积历史梯度对方向的修正,又包含来自RMSprop的对于学习率的修正,最终的完整表达式如下:
在这里插入图片描述
对于优化技术,大家还是可以参考吴恩达的视频,改善深层神经网络:超参数调试、正则化以及优化 这一节,讲的很好!

这部分内容参考:https://zhuanlan.zhihu.com/p/54915217

5、batch norm层

内容来自于:https://www.cnblogs.com/guoyaohua/p/8724433.html
原论文下载:https://blog.csdn.net/clearch/article/details/80266622

Batch Normalization作为最近一年来DL的重要成果,已经广泛被证明其有效性和重要性。虽然有些细节处理还解释不清其理论原因,但是实践证明好用才是真的好,别忘了DL从Hinton对深层网络做Pre-Train开始就是一个经验领先于理论分析的偏经验的一门学问。本文是对论文《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》的导读。

机器学习领域有个很重要的假设:IID独立同分布假设,就是假设训练数据和测试数据是满足相同分布的,这是通过训练数据获得的模型能够在测试集获得好的效果的一个基本保障。那BatchNorm的作用是什么呢?BatchNorm就是在深度神经网络训练过程中使得每一层神经网络的输入保持相同分布的。

接下来一步一步的理解什么是BN。

为什么深度神经网络随着网络深度加深,训练起来越困难,收敛越来越慢?这是个在DL领域很接近本质的好问题。很多论文都是解决这个问题的,比如ReLU激活函数,再比如Residual Network,BN本质上也是解释并从某个不同的角度来解决这个问题的。

一、“Internal Covariate Shift”问题

从论文名字可以看出,BN是用来解决“Internal Covariate Shift”问题的,那么首先得理解什么是“Internal Covariate Shift”?

论文首先说明Mini-Batch SGD相对于One Example SGD的两个优势:梯度更新方向更准确;并行计算速度快;(为什么要说这些?因为BatchNorm是基于Mini-Batch SGD的,所以先夸下Mini-Batch SGD,当然也是大实话);然后吐槽下SGD训练的缺点:超参数调起来很麻烦。(作者隐含意思是用BN就能解决很多SGD的缺点)

接着引入covariate shift的概念:如果ML系统实例集合<X,Y>中的输入值X的分布老是变,这不符合IID假设,网络模型很难稳定的学规律,这不得引入迁移学习才能搞定吗,我们的ML系统还得去学习怎么迎合这种分布变化啊。对于深度学习这种包含很多隐层的网络结构,在训练过程中,因为各层参数不停在变化,所以每个隐层都会面临covariate shift的问题,也就是在训练过程中,隐层的输入分布老是变来变去,这就是所谓的“Internal Covariate Shift”,Internal指的是深层网络的隐层,是发生在网络内部的事情,而不是covariate shift问题只发生在输入层。

然后提出了BatchNorm的基本思想:能不能让每个隐层节点的激活输入分布固定下来呢?这样就避免了“Internal Covariate Shift”问题了。

BN不是凭空拍脑袋拍出来的好点子,它是有启发来源的:之前的研究表明如果在图像处理中对输入图像进行白化(Whiten)操作的话——所谓白化,就是对输入数据分布变换到0均值,单位方差的正态分布——那么神经网络会较快收敛,那么BN作者就开始推论了:图像是深度神经网络的输入层,做白化能加快收敛,那么其实对于深度网络来说,其中某个隐层的神经元是下一层的输入,意思是其实深度神经网络的每一个隐层都是输入层,不过是相对下一层来说而已,那么能不能对每个隐层都做白化呢?这就是启发BN产生的原初想法,而BN也确实就是这么做的,可以理解为对深层神经网络每个隐层神经元的激活值做简化版本的白化操作。

二、BatchNorm的本质思想

BN的基本思想其实相当直观:因为深层神经网络在做非线性变换前的激活输入值(就是那个x=WU+B,U是输入)随着网络深度加深或者在训练过程中,其分布逐渐发生偏移或者变动,之所以训练收敛慢,一般是整体分布逐渐往非线性函数的取值区间的上下限两端靠近(对于Sigmoid函数来说,意味着激活输入值WU+B是大的负值或正值),所以这导致反向传播时低层神经网络的梯度消失,这是训练深层神经网络收敛越来越慢的本质原因,而BN就是通过一定的规范化手段,把每层神经网络任意神经元这个输入值的分布强行拉回到均值为0方差为1的标准正态分布,其实就是把越来越偏的分布强制拉回比较标准的分布,这样使得激活输入值落在非线性函数对输入比较敏感的区域,这样输入的小变化就会导致损失函数较大的变化,意思是这样让梯度变大,避免梯度消失问题产生,而且梯度变大意味着学习收敛速度快,能大大加快训练速度。

THAT’S IT。其实一句话就是:对于每个隐层神经元,把逐渐向非线性函数映射后向取值区间极限饱和区靠拢的输入分布强制拉回到均值为0方差为1的比较标准的正态分布,使得非线性变换函数的输入值落入对输入比较敏感的区域,以此避免梯度消失问题。因为梯度一直都能保持比较大的状态,所以很明显对神经网络的参数调整效率比较高,就是变动大,就是说向损失函数最优值迈动的步子大,也就是说收敛地快。BN说到底就是这么个机制,方法很简单,道理很深刻。

上面说得还是显得抽象,下面更形象地表达下这种调整到底代表什么含义。
  在这里插入图片描述
  假设某个隐层神经元原先的激活输入x取值符合正态分布,正态分布均值是-2,方差是0.5,对应上图中最左端的浅蓝色曲线,通过BN后转换为均值为0,方差是1的正态分布(对应上图中的深蓝色图形),意味着什么,意味着输入x的取值正态分布整体右移2(均值的变化),图形曲线更平缓了(方差增大的变化)。这个图的意思是,BN其实就是把每个隐层神经元的激活输入分布从偏离均值为0方差为1的正态分布通过平移均值压缩或者扩大曲线尖锐程度,调整为均值为0方差为1的正态分布。

那么把激活输入x调整到这个正态分布有什么用?首先我们看下均值为0,方差为1的标准正态分布代表什么含义:

在这里插入图片描述
这意味着在一个标准差范围内,也就是说64%的概率x其值落在[-1,1]的范围内,在两个标准差范围内,也就是说95%的概率x其值落在了[-2,2]的范围内。那么这又意味着什么?我们知道,激活值x=WU+B,U是真正的输入,x是某个神经元的激活值,假设非线性函数是sigmoid,那么看下sigmoid(x)其图形:
在这里插入图片描述
及sigmoid(x)的导数为:G’=f(x)*(1-f(x)),因为f(x)=sigmoid(x)在0到1之间,所以G’在0到0.25之间,其对应的图如下:
在这里插入图片描述
假设没有经过BN调整前x的原先正态分布均值是-6,方差是1,那么意味着95%的值落在了[-8,-4]之间,那么对应的Sigmoid(x)函数的值明显接近于0,这是典型的梯度饱和区,在这个区域里梯度变化很慢,为什么是梯度饱和区?请看下sigmoid(x)如果取值接近0或者接近于1的时候对应导数函数取值,接近于0,意味着梯度变化很小甚至消失。而假设经过BN后,均值是0,方差是1,那么意味着95%的x值落在了[-2,2]区间内,很明显这一段是sigmoid(x)函数接近于线性变换的区域,意味着x的小变化会导致非线性函数值较大的变化,也即是梯度变化较大,对应导数函数图中明显大于0的区域,就是梯度非饱和区。

从上面几个图应该看出来BN在干什么了吧?其实就是把隐层神经元激活输入x=WU+B从变化不拘一格的正态分布通过BN操作拉回到了均值为0,方差为1的正态分布,即原始正态分布中心左移或者右移到以0为均值,拉伸或者缩减形态形成以1为方差的图形。什么意思?就是说经过BN后,目前大部分Activation的值落入非线性函数的线性区内,其对应的导数远离导数饱和区,这样来加速训练收敛过程。

但是很明显,看到这里,稍微了解神经网络的读者一般会提出一个疑问:如果都通过BN,那么不就跟把非线性函数替换成线性函数效果相同了?这意味着什么?我们知道,如果是多层的线性函数变换其实这个深层是没有意义的,因为多层线性网络跟一层线性网络是等价的。这意味着网络的表达能力下降了,这也意味着深度的意义就没有了。所以BN为了保证非线性的获得,对变换后的满足均值为0方差为1的x又进行了scale加上shift操作(y=scale*x+shift),每个神经元增加了两个参数scale和shift参数,这两个参数是通过训练学习到的,意思是通过scale和shift把这个值从标准正态分布左移或者右移一点并长胖一点或者变瘦一点,每个实例挪动的程度不一样,这样等价于非线性函数的值从正中心周围的线性区往非线性区动了动。核心思想应该是想找到一个线性和非线性的较好平衡点,既能享受非线性的较强表达能力的好处,又避免太靠非线性区两头使得网络收敛速度太慢。当然,这是我的理解,论文作者并未明确这样说。但是很明显这里的scale和shift操作是会有争议的,因为按照论文作者论文里写的理想状态,就会又通过scale和shift操作把变换后的x调整回未变换的状态,那不是饶了一圈又绕回去原始的“Internal Covariate Shift”问题里去了吗,感觉论文作者并未能够清楚地解释scale和shift操作的理论原因。

三、训练阶段如何做BatchNorm

上面是对BN的抽象分析和解释,具体在Mini-Batch SGD下做BN怎么做?其实论文里面这块写得很清楚也容易理解。为了保证这篇文章完整性,这里简单说明下。

假设对于一个深层神经网络来说,其中两层结构如下:
在这里插入图片描述
要对每个隐层神经元的激活值做BN,可以想象成每个隐层又加上了一层BN操作层,它位于X=WU+B激活值获得之后,非线性函数变换之前,其图示如下:
在这里插入图片描述
对于Mini-Batch SGD来说,一次训练过程里面包含m个训练实例,其具体BN操作就是对于隐层内每个神经元的激活值来说,进行如下变换:

在这里插入图片描述
要注意,这里t层某个神经元的x(k)不是指原始输入,就是说不是t-1层每个神经元的输出,而是t层这个神经元的线性激活x=WU+B,这里的U才是t-1层神经元的输出。变换的意思是:某个神经元对应的原始的激活x通过减去mini-Batch内m个实例获得的m个激活x求得的均值E(x)并除以求得的方差Var(x)来进行转换。

上文说过经过这个变换后某个神经元的激活x形成了均值为0,方差为1的正态分布,目的是把值往后续要进行的非线性变换的线性区拉动,增大导数值,增强反向传播信息流动性,加快训练收敛速度但是这样会导致网络表达能力下降,为了防止这一点,每个神经元增加两个调节参数(scale和shift),这两个参数是通过训练来学习到的,用来对变换后的激活反变换,使得网络表达能力增强,即对变换后的激活进行如下的scale和shift操作,这其实是变换的反操作
  在这里插入图片描述
  BN其具体操作流程,如论文中描述的一样:
  在这里插入图片描述
  过程非常清楚,就是上述公式的流程化描述,这里不解释了,直接应该能看懂。

四、BatchNorm的推理(Inference)过程

BN在训练的时候可以根据Mini-Batch里的若干训练实例进行激活数值调整,但是在推理(inference)的过程中,很明显输入就只有一个实例,看不到Mini-Batch其它实例,那么这时候怎么对输入做BN呢?因为很明显一个实例是没法算实例集合求出的均值和方差的。这可如何是好?

既然没有从Mini-Batch数据里可以得到的统计量,那就想其它办法来获得这个统计量,就是均值和方差。可以用从所有训练实例中获得的统计量来代替Mini-Batch里面m个训练实例获得的均值和方差统计量,因为本来就打算用全局的统计量,只是因为计算量等太大所以才会用Mini-Batch这种简化方式的,那么在推理的时候直接用全局统计量即可。

决定了获得统计量的数据范围,那么接下来的问题是如何获得均值和方差的问题。很简单,因为每次做Mini-Batch训练时,都会有那个Mini-Batch里m个训练实例获得的均值和方差,现在要全局统计量,只要把每个Mini-Batch的均值和方差统计量记住,然后对这些均值和方差求其对应的数学期望即可得出全局统计量,即:
  在这里插入图片描述
  有了均值和方差,每个隐层神经元也已经有对应训练好的Scaling参数和Shift参数,就可以在推导的时候对每个神经元的激活数据计算NB进行变换了,在推理过程中进行BN采取如下方式:
  在这里插入图片描述
  这个公式其实和训练时
  在这里插入图片描述
  是等价的,通过简单的合并计算推导就可以得出这个结论。那么为啥要写成这个变换形式呢?我猜作者这么写的意思是:在实际运行的时候,按照这种变体形式可以减少计算量,为啥呢?因为对于每个隐层节点来说:
  在这里插入图片描述
  都是固定值,这样这两个值可以事先算好存起来,在推理的时候直接用就行了,这样比原始的公式每一步骤都现算少了除法的运算过程,乍一看也没少多少计算量,但是如果隐层节点个数多的话节省的计算量就比较多了。

五、BatchNorm的好处

BatchNorm为什么NB呢,关键还是效果好。
①不仅仅极大提升了训练速度,收敛过程大大加快;
②还能增加分类效果,一种解释是这是类似于Dropout的一种防止过拟合的正则化表达方式,所以不用Dropout也能达到相当的效果;
③另外调参过程也简单多了,对于初始化要求没那么高,而且可以使用大的学习率等。
总而言之,经过这么简单的变换,带来的好处多得很,这也是为何现在BN这么快流行起来的原因。

6、Layer Normalization

来自:https://blog.csdn.net/zhangjunhit/article/details/53169308

主要是针对 batch normalization 存在的问题 提出了 Layer Normalization 进行改进的。
这里首先来回顾一下 batch normalization :
对于前馈神经网络第 l 隐层,神经元的输入为 a, 激活函数为 f, 激活函数输出为 h。权值 w 通过 SGD学习得到。 如下面的公式所示:
在这里插入图片描述
深度学习中的一个挑战就是对于上面公式中 一层的权值 w 的梯度 高度依赖于前一层神经元的输出,特别是当这些输出的改变高度相关的时候。(梯度容易受样本数据的影响,导致权值难以快速的收敛,一会向东,一会向西,走来走去,走了半天也没走多少路啊,这样走到全局最优值要走到哪天。这个问题有个名字,叫 covariate shift)。 针对此问题 [Ioffe and Szegedy, 2015] 提出了 Batch normalization 来降低这个 covariate shift 的影响。对于每个隐层的神经元,我们在所有的训练样本上归一化该神经元的输入。
在这里插入图片描述
在整个训练样本上计算均值方差,然后对神经元的输入进行归一化。由于对整个训练样本计算均值方差不太有效率(对于训练来说),所以提出了 在最小训练批次上估计 均值方差。 current mini-batch 。 这个约束导致Batch normalization 难以应用于 recurrent neural networks。

3 Layer normalization
针对前面提到的 Batch normalization 的问题,我们提出了 Layer normalization。

注意到一层输出的改变会产生下一层输入的高相关性改变,特别是当使用 ReLU,其输出改变很大。那么我们可以通过固定一层神经元的输入均值和方差来降低 covariate shift 的影响。
在这里插入图片描述
上面公式中 H 是 一层神经元的个数。这里一层网络 共享一个均值和方差,不同训练样本对应不同的均值和方差,这是和 Batch normalization 的最大区别。

Layer normalization 对于recurrent neural networks 的帮助最大。
Layer normalization 对于 Convolutional Networks 作用不是很大,后续研究可以提高其作用。

猜你喜欢

转载自blog.csdn.net/SMith7412/article/details/88396674