AI知识点(1)–激活函数

  • 2019 年 12 月 31 日
  • 笔记

2019年第 84 篇文章,总第 108 篇文章 本文大约 5000 字,阅读大约需要 15 分钟

AI知识点(AI Knowledge)系列第一篇文章–激活函数。

本文主要的目录如下:

  • 激活函数的定义
  • 为什么需要激活函数
  • 常见的激活函数

1. 激活函数的定义

激活函数是神经网络中非常重要的一个内容,神经网络是受到生物神经网络的启发,在生物神经网络中也存在着激活函数,而且激活函数决定了神经元之间是否要传递信号,而在人工的神经网络中,激活函数的作用则主要是给网络添加非线性因素,使得网络可以逼近任意复杂的函数,一个简单的神经元如下图所说,其中 f 表示的就是激活函数。

如果是从数学上来定义的话,在ICML2016的一篇论文 Noisy Activation Functions中,作者将激活函数定义为一个几乎处处可微的 h : R → R 。

另外还有以下的一些概念:a.饱和当一个激活函数h(x)满足

时我们称之为右饱和

当一个激活函数h(x)满足

时我们称之为左饱和

当一个激活函数既满足左饱和又满足右饱和时,我们称之为饱和

b.硬饱和与软饱和对任意的 x,如果存在常数 c,当?>?时恒有 ℎ′(?)=0 则称其为右硬饱和,当x<c时恒 有ℎ′(?)=0 则称其为左硬饱和

若既满足左硬饱和,又满足右硬饱和,则称这种激活函数为硬饱和

但如果只有在极限状态下偏导数等于0的函数,称之为软饱和


2. 为什么需要激活函数

事实上这个问题应该是问为什么需要非线性的激活函数,因为目前常用的都是非线性激活函数,原因如下:

  1. 激活函数是可以讲当前特征空间通过一定的线性映射转换到另一个空间,让数据能够更好的被分类;
  2. 但神经网络中,基本的函数 y=wx+b 就是一个线性函数,如果激活函数还是线性函数,那么线性的组合还是线性,和单独一个线性分类器没有差别,是无法逼近任意函数,而实际生活中的很多问题都不是简单的线性分类问题;
  3. 非线性激活函数可以引入非线性因素,让神经网络具有更强大的能力,可以真正做到逼近和表示任意的复杂的函数,解决更多复杂的问题,可以学习解决很多类型的问题,比如图像、文本、视频、音频等,这也是现在深度学习被全面应用到很多传统的机器学习问题的基础之一

3. 常见的激活函数

3.1 常见的激活函数定义和其图像

3.1.1 Sigmoid 激活函数

函数的公式定义, 其值域是 (0, 1)

导数为:

优点

  1. Sigmoid函数的输出映射在 (0,1) 之间,单调连续,输出范围有限,优化稳定,可以用作输出层。
  2. 求导容易。

缺点

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

因为不以 0 为中心,接下来介绍的就是以 0 为中心的一个激活函数。

3.1.2 Tanh 激活函数

公式定义如下所示,值域是 (-1, 1)

其图像如下所示:

导数为:

在实践中,Tanh 函数的使用优先性高于 Sigmoid 函数

优点:1.比 Sigmoid函数收敛速度更快。2.相比 Sigmoid 函数,其输出以0为中心。缺点:

由于饱和性产生的梯度消失问题依然存在。

SigmoidTanh 都存在梯度消失问题,所以又有新的一个激活函数,这个激活函数变得非常常用,并且有了更堵哦的改进版。

3.1.3 ReLU 激活函数

函数的公式定义如下所示,值域是 [0, +∞)

其图像如下所示:

导数是:

ReLU 激活函数,即修正线性单元函数,相比前两个激活函数,由于其特点使得它变成目前最常用的激活函数。

优点

  1. 收敛速度更快;
  2. 相比 sigmoidtanh,计算速度更快
  3. 有效缓解了梯度消失的问题
  4. 在没有无监督与训练的时候,也能有较好的表现
  5. 提供了神经网络的稀疏表达能力

缺点

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

relu 激活函数实际上在小于0的一边,还是存在梯度消失问题,所以有了几个改进版本的函数。

3.1.4 LReLU、PReLU和RReLU

LReLU

第一个改进版的 relu 函数,即 leaky relu,LReLU,函数定义如下所示:

f(x) = max(ax, x)

a=0.1

导数如下:

Leaky ReLU 的概念是:当 x < 0 时,它得到 0.1 的正梯度。

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

PReLU

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

其公式定义和 LReLU 一样,但这里的参数 a 是一个超参数,不需要自定义,而是自适应从数据中学习,也就是可以进行反向传播,这让神经元可以选择负区域最好的梯度

RReLU

公式定义如下所示:

$$a_{ji} sim U(l,u),l<u;;and;;l,uin [0,1)="" $$="" 就是给定范围内取样的随机变量,但在测试中是固定的,该激活函数在一定程度上可以起到正则效果。

在论文《Empirical Evaluation of Rectified Activations in Convolution Network》,作者对比了ReLU激活函数和其三个改进版本 LReLUPReLURReLU 在数据集 CIFAR-10CIFAR-100NDSB 中相同网络模型的性能。

想了解的可以具体看看这篇论文,当然在实际应用中,初次训练可以选择 ReLU 激活函数,然后可以再尝试这三个改进版来看看对比的结果

3.1.5 ELU

公式定义:

导数如下:

优点

1.ELU减少了正常梯度与单位自然梯度之间的差距,从而加快了学习。2.在负的限制条件下能够更有鲁棒性。

缺点

  1. 由于包含指数运算,所以计算时间更长;
  2. 无法避免梯度爆炸问题;
  3. 神经网络不学习 α 值。

ELU 激活函数可以参考 ICLR 2016的论文《FAST AND ACCURATE DEEP NETWORK LEARNING BY EXPONENTIAL LINEAR UNITS (ELUS)》。

3.1.6 Swish

这个函数也叫做自门控激活函数,来自2017年谷歌的论文《Swish: a Self-Gated Activation Function》:https://arxiv.org/abs/1710.05941v1

公式定义如下所示

其图像如下所示:

从图中可以看到,在 x<0 的部分和 ReLU 激活函数是不同的,会有一段 x 增大,但输出值下降的区域;

所以 Swish 函数具备单侧有界的特性,它是平滑、非单调的。

具体的介绍可以参考文章–Swish 激活函数的性能优于 ReLU 函数。

3.1.7 Softplus 和 Softsign

Softplus 的公式定义:

Softsign 的公式定义:

这两个激活函数的使用较少,可以参考 Tensorflow 提供的 api–激活函数相关TensorFlow的官方文档

3.1.8 Softmax(归一化指数函数)

公式定义:

该函数主要用于多分类神经网络的输出层。

3.1.9 SELU 和 GELU

这两个激活函数实际上都是最近提出或者最近才使用较多的激活函数,详细介绍可以查看文章–从ReLU到GELU,一文概览神经网络的激活函数,这里简单给出公式定义和优缺点。

SELU,即扩展型指数线性单元激活函数,其公式如下所示:

优点

  • 内部归一化的速度比外部归一化快,这意味着网络能更快收敛;
  • 不可能出现梯度消失或爆炸问题,见 SELU 论文附录的定理 2 和 3。

缺点

  • 这个激活函数相对较新——需要更多论文比较性地探索其在 CNN 和 RNN 等架构中应用。
  • 这里有一篇使用 SELU 的 CNN 论文:https://arxiv.org/pdf/1905.01338.pdf

GELU,即高斯误差线性单元激活函数是2016年提出的,但在最近的 Transformer 模型(谷歌的 BERT 和 OpenAI 的 GPT-2)中得到了应用,其公式如下所示:

优点

  • 似乎是 NLP 领域的当前最佳;尤其在 Transformer 模型中表现最好;
  • 能避免梯度消失问题。

缺点

  • 尽管是 2016 年提出的,但在实际应用中还是一个相当新颖的激活函数。

3.2 常见的激活函数的性质

  1. 非线性:当激活函数是线性的,一个两层的神经网络就可以基本上逼近所有的函数。但如果激活函数是恒等激活函数的时候,即 ,就不满足这个性质,而且如果 MLP 使用的是恒等激活函数,那么其实整个网络跟单层神经网络是等价的;
  2. 可微性:当优化方法是基于梯度的时候,就体现了该性质;
  3. 单调性:当激活函数是单调的时候,单层网络能够保证是凸函数;
  4. :当激活函数满足这个性质的时候,如果参数的初始化是随机的较小值,那么神经网络的训练将会很高效;如果不满足这个性质,那么就需要详细地去设置初始值;
  5. 输出值的范围:当激活函数输出值是有限的时候,基于梯度的优化方法会更加稳定,因为特征的表示受有限权值的影响更显著;当激活函数的输出是无限的时候,模型的训练会更加高效,不过在这种情况小,一般需要更小的 Learning Rate。

3.3 如何选择激活函数

通常选择一个激活函数并不容易,需要考虑很多因素,最好的做法还是一一实验所有的激活函数,但需要保证其他因素相同。

一些技巧:(来自深度学习500问第三篇深度学习基础)

  1. 如果输出是 0、1 值(二分类问题),则输出层选择 sigmoid 函数,然后其它的所有单元都选择 Relu 函数。
  2. 如果在隐藏层上不确定使用哪个激活函数,那么通常会使用 Relu 激活函数。有时,也会使用 tanh 激活函数,但 Relu 的一个优点是:当是负值的时候,导数等于 0。
  3. Sigmoid 激活函数:除了输出层是一个二分类问题基本不会用它。
  4. Tanh 激活函数:tanh 是非常优秀的,几乎适合所有场合。
  5. ReLU 激活函数:最常用的默认函数,如果不确定用哪个激活函数,就使用 ReLu 或者 Leaky ReLu,再去尝试其他的激活函数。
  6. 如果遇到了一些死的神经元,我们可以使用 Leaky ReLU 函数。

3.4 激活函数以零为中心的问题

在介绍 Sigmoid 的缺点的时候说到它不是以 0 为中心,这个特点主要是影响收敛速度,因为它的输出值是恒为正的,那么在梯度下降,进行参数更新的时候,所有参数每次更新的方向都是同个方向,要不都是正方向,或者要不都是负方向,其更新就是一个 z 字形,如下图所示:

图片来自文章https://liam.page/2018/04/17/zero-centered-active-function/

借用文章 cs231n_激活函数 的例子:

假设我们有权值 w=[1,−1,1]],我们需要将权值更新为 w=[−1,1,−1] ,如果梯度是同时有正和有负的,我们可以只更新一次就可得到结果:w=[1,−1,1]+[−2,2,−2]=[−1,1,−1];但是如果梯度只能是正或者只能是负,则需要两次更新才能得到结果:w=[1,−1,1]+[−3,−3,−3]+[1,5,1]=[−1,1,−1] 。

所以需要选择以 0 为中心的激活函数,可以提高收敛速度。


参考文章

  1. The Activation Function in Deep Learning 浅谈深度学习中的激活函数
  2. 一文概览深度学习中的激活函数
  3. 深度学习500问第三篇深度学习基础–3.4激活函数
  4. Swish 激活函数的性能优于 ReLU 函数
  5. 《Empirical Evaluation of Rectified Activations in Convolution Network》:https://arxiv.org/abs/1505.00853
  6. 《FAST AND ACCURATE DEEP NETWORK LEARNING BY EXPONENTIAL LINEAR UNITS (ELUS)》:https://arxiv.org/pdf/1511.07289v5.pdf
  7. 《Swish: a Self-Gated Activation Function》:https://arxiv.org/abs/1710.05941v1
  8. 激活函数相关TensorFlow的官方文档
  9. 从ReLU到GELU,一文概览神经网络的激活函数
  10. SELU 论文:https://arxiv.org/pdf/1706.02515.pdf
  11. GELU 论文:https://arxiv.org/pdf/1606.08415.pdf
  12. 谈谈激活函数以零为中心的问题
  13. cs231n_激活函数