激活函数小结:ReLU、ELU、Swish、GELU等
chencjiajy
已于 2024-02-25 21:07:52 修改
阅读量2.4k
收藏 15
点赞数 2
分类专栏: 深度学习 文章标签: 激活函数 深度学习
版权
开放原子开发者工作坊
文章已被社区收录
加入社区
深度学习
专栏收录该内容
36 篇文章0 订阅
订阅专栏
文章目录
Sigmoid
Tanh
ReLU
Leaky ReLU
PReLU
ELU
SoftPlus
Maxout
Mish
Swish
GELU
GLU
ReGLU
SwiGLU
GEGLU
资源
激活函数是神经网络中的非线性函数,为了增强网络的表示能力和学习能力,激活函数有以下几点性质:
连续且可导(允许少数点上不可导)的非线性函数。可导的激活函数可以直接利用数值优化的方法来学习网络参数。
激活函数及其导函数要尽可能的简单,有利于提高网络计算效率。
激活函数的导函数的值域要在一个合适的区间内(不能太大也不能太小),否则会影响训练的效率和稳定性。
Sigmoid
Sigmoid函数(也被称为Logistic函数)的表达式如下:
σ ( x ) = exp ( x ) exp ( x ) + exp ( 0 ) = 1 1 + e x p ( − x ) \sigma(x)=\frac{\exp (x)}{\exp (x)+\exp (0)} = \frac {1}{1+exp(-x)}
σ(x)=
exp(x)+exp(0)
exp(x)
=
1+exp(−x)
1
其导数为
d d x σ ( x ) = σ ( x ) ( 1 − σ ( x ) ) \frac{d}{d x} \sigma(x)=\sigma(x)(1-\sigma(x))
dx
d
σ(x)=σ(x)(1−σ(x))
其图像如下图,是一个S型曲线,所以Sigmoid函数可以看做一个“挤压”函数,把一个实数域的输入“挤压”到(0,1)。当输入值在0附近时,Sigmoid函数近似为线性函数;当输入值靠近两端时,对输入进行抑制;输入越小,越接近于0;输入越大,越接近于1。
from matplotlib import pyplot as plt
import numpy as np
import torch
from torch import nn
x = np.linspace(-6, 6, 600)
m0 = nn.Sigmoid()
output0 = m0(torch.Tensor(x))
plt.plot(x, output0, label='Sigmod')
plt.title("Sigmoid Activation Function")
plt.xlabel("x")
plt.ylabel("Activation")
plt.grid()
plt.legend()
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Sigmoid激活函数的缺点:
倾向于梯度消失
函数输出不是以0为中心,会使其后一层的神经元的输入发生偏置偏移(Bias Shift),进而使得梯度下降的收敛速度变慢,也就是会降低权重更新的效率
公式中包括指数运算,计算机运行较慢
Tanh
Tanh 函数也是一种S型函数,其定义为
t a n h ( x ) = exp ( x ) − exp ( − x ) exp ( x ) + exp ( − x ) tanh(x)=\frac{\exp (x) - \exp (-x)}{\exp (x)+\exp (-x)}
tanh(x)=
exp(x)+exp(−x)
exp(x)−exp(−x)
Tanh函数可以看做放大并平移的Sigmoid函数,其值域为(-1,1),并且Tanh与Sigmoid函数关系如下式:
t a n h ( x ) = 2 σ ( 2 x ) − 1 tanh(x) = 2 \sigma(2x) -1
tanh(x)=2σ(2x)−1
Tanh函数如下图所示,它的输入是零中心化的了。
x = np.linspace(-6, 6, 600)
m0 = nn.Sigmoid()
output0 = m0(torch.Tensor(x))
plt.plot(x, output0, label='Sigmod')
m0_1 = nn.Tanh()
output0_1 = m0_1(torch.Tensor(x))
plt.plot(x, output0_1, label='Tanh')
plt.title("Sigmoid and Tanh Activation Functions")
plt.xlabel("x")
plt.ylabel("Activation")
plt.grid()
plt.legend()
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
ReLU
ReLU(Rectified Linear unit)是最常见的激活函数,其公式为:
R e L U ( x ) = { x x ≥ 0 0 x < 0 = m a x ( 0 , x ) \begin {aligned} ReLU(x) &=
{x x≥00 x<0
{
�
�
≥
0
0
�
<
0
\\ &= max(0, x) \end {aligned}
ReLU(x)
={
x x≥0
0 x<0
=max(0,x)
ReLU函数示意及后面会介绍的几种变种如下图所示:
x = np.linspace(-6, 6, 600)
m0 = nn.ReLU()
output0 = m0(torch.Tensor(x))
plt.plot(x, output0, label='RELU')
m1 = nn.LeakyReLU()
output1 = m1(torch.Tensor(x))
plt.plot(x, output1, label='LeakyRELU', color='red', linestyle='--')
m2 = nn.ELU()
output2 = m2(torch.Tensor(x))
plt.plot(x, output2, label='ELU', linestyle='dotted')
m3 = nn.Softplus()
output3 = m3(torch.Tensor(x))
plt.plot(x, output3, label='Softplus', linestyle='-.')
plt.title("ReLu and It's Varies Activation Functions")
plt.xlabel("x")
plt.ylabel("Activation")
plt.grid()
plt.legend()
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ReLU函数的优点是:1. 采用ReLU的神经元只需要进行加、乘和比较的操作,计算上更加高效。2. ReLU函数被认为具有生物学合理性,比如单侧抑制、宽兴奋边界。在生物神经网络中,同时处于兴奋状态的神经元非常稀疏,比如人脑中在同一时刻大概只有 1% ∼ 4% 的神经元处于活跃状态。Sigmoid 型激活函数会导致一个非稀疏的神经网络,而 ReLU 却具有很好的稀疏性,大约 50% 的神经元会处于激活状态.3. 相对于sigmoid函数的两端饱和,ReLU函数为左饱和函数,且在x>0时的导数为1,所以相比之下一定程度上缓解了梯度消失问题,加速梯度下降的收敛速度。
ReLU函数的缺点是:1. 函数输出是非零中心化的,会使其后一层的神经元的输入发生偏置偏移(Bias Shift),进而使得梯度下降的收敛速度变慢。2. ReLU神经元在训练时比较容易”dead",如果参数在一次不恰当的更新后,第一个隐藏层中的某个ReLU神经元在所有的训练数据上都不能被激活,那么这个神经元自身参数的梯度永远都会是0,在以后的训练过程中永远不能被激活,这种现象被称为死亡ReLU问题(Dying ReLU Problem)。(其他隐藏层也是有可能发生的)
为了避免ReLU的缺点,有以下几种广泛使用的ReLU变种
Leaky ReLU
Leaky ReLU的公式如下,也就是使输入x<0时,保持一个很小的梯度γ \gammaγ,使得神经元非激活时也有一个非零的梯度可以更新参数,避免永远不能被激活:
L e a k y R e L U ( x ) = { x x > 0 γ x x ≤ 0 = m a x ( 0 , x ) + γ m i n ( 0 , x ) \begin {aligned} LeakyReLU(x) &=
{x x>0γx x≤0
{
�
�
>
0
�
�
�
≤
0
\\ &= max(0, x) + \gamma min(0,x) \end {aligned}
LeakyReLU(x)
={
x x>0
γx x≤0
=max(0,x)+γmin(0,x)
γ \gammaγ是一个很小的常数,如0.01。 当γ < 1 \gamma <1γ<1时,Leaky ReLU 也可以写为
L e a k y R e L U ( x ) = m a x ( x , γ x ) LeakyReLU(x) = max(x, \gamma x)
LeakyReLU(x)=max(x,γx)
PReLU
PRuLU(Parametric ReLU)引入了一个可学习的参数,不同神经元可以有不同的参数。对第i个神经元的PReLU定义为:
P R e L U i ( x ) = { x x > 0 γ i x x ≤ 0 = m a x ( 0 , x ) + γ i m i n ( 0 , x ) \begin {aligned} PReLU_i(x) &=
{x x>0γix x≤0
{
�
�
>
0
�
�
�
�
≤
0
\\ &= max(0, x) + \gamma_i min(0,x) \end {aligned}
PReLU
i
(x)
={
x x>0
γ
i
x x≤0
=max(0,x)+γ
i
min(0,x)
其中γ i \gamma_iγ
i
为x ≤ 0 x \le 0x≤0时函数的斜率,所以PReLU也是非饱和函数。
如果γ i = 0 \gamma_i=0γ
i
=0,PReLU就退化为ReLU。
如果γ i \gamma_iγ
i
是一个很小的常数,则PReLU就可以看作LeakyReLU。
PReLU可以允许不同神经元具有不同的参数,也可以一组神经元共享一个参数。
ELU
ELU(Exponential Linear Unit)的定义如下:
E R e L U ( x ) = { x x > 0 γ ( e x p ( x ) − 1 ) x ≤ 0 = m a x ( 0 , x ) + m i n ( 0 , γ ( e x p ( x ) − 1 ) ) \begin {aligned} EReLU(x) &=
{x x>0γ(exp(x)−1) x≤0
{
�
�
>
0
�
(
�
�
�
(
�
)
−
1
)
�
≤
0
\\ &= max(0, x) + min(0,\gamma (exp(x) - 1)) \end {aligned}
EReLU(x)
={
x x>0
γ(exp(x)−1) x≤0
=max(0,x)+min(0,γ(exp(x)−1))
定义中的γ ≥ 0 \gamma \ge 0γ≥0是一个超参数,决定x ≤ 0 x \le 0x≤0时的饱和曲线,并调整输出均值在0附近,所以ELU是一个近似的零中心化的非线性函数。
SoftPlus
SoftPlus可以看作ReLU函数的平滑版本,其定义为:
S o f t p l u s ( x ) = l o g ( 1 + e x p ( x ) ) Softplus(x) = log(1 + exp(x))
Softplus(x)=log(1+exp(x))
SoftPlus的导数是Sigmoid函数
SoftPlus函数也有与ReLU函数一样的单侧抑制、宽兴奋边界的特性,但没有稀疏激活性。
Maxout
Maxout的输入是上一层神经元的全部原始输出,是一个向量x = [ x 1 ; x 2 ; ⋯ , ; x D ] \mathbf{x} = [x_1;x_2;\cdots,;x_D]x=[x
1
;x
2
;⋯,;x
D
]
每个Maxout单元有K个权重向量w k ∈ R D \mathbf{w}_k \in \mathbb{R}^Dw
k
∈R
D
(w k = [ w k , 1 , ⋯ , w k , D ] T \mathbf{w}_k = [w_{k, 1}, \cdots, w_{k,D}]^Tw
k
=[w
k,1
,⋯,w
k,D
]
T
为第k个权重向量) 和偏置b k ( 1 ≤ k ≤ K ) b_k(1 \le k \le K)b
k
(1≤k≤K), 对于输入x \mathbf{x}x,可以得到K个净输入z k z_kz
k
,1 ≤ k ≤ K 1 \le k \le K1≤k≤K:
z k = w k T x + b k z_k = \mathbf{w}_k^T x + b_k
z
k
=w
k
T
x+b
k
Maxout单元的非线性函数定义为
m a x o u t ( x ) = max k ∈ [ 1 , K ] ( z k ) maxout(\mathbf{x}) = \max_{k\in[1,K]} (z_k)
maxout(x)=
k∈[1,K]
max
(z
k
)
Maxout激活函数可以看做任意凸函数的分段线性近似,并且在有限的点上是不可微的。
Mish
Mish的表达如下式
M i s h ( x ) = x ∗ t a n h ( S o f t p l u s ( x ) ) = x ∗ t a n h ( l n ( 1 + e x ) ) \begin{aligned} Mish(x) &=x∗tanh(Softplus(x)) \\ &= x*tanh(ln(1+e^x)) \end {aligned}
Mish(x)
=x∗tanh(Softplus(x))
=x∗tanh(ln(1+e
x
))
Mish的函数图像如下图
m1 = nn.Mish()
output1 = m1(torch.Tensor(x))
plt.plot(x, output1, label='Mish')
plt.title("Mish Activation Function")
plt.xlabel("x")
plt.ylabel("Activation")
plt.grid()
plt.legend()
plt.show()
1
2
3
4
5
6
7
8
9
Swish
Swish的定义如下:
s w i s h ( x ) = x σ ( β x ) = x 1 1 + e x p ( − β x ) \begin {aligned} swish(x) &= x \sigma(\beta x) \\ &= x \frac{1}{1+exp(-\beta x)} \end {aligned}
swish(x)
=xσ(βx)
=x
1+exp(−βx)
1
σ \sigmaσ是sigmoid函数,β \betaβ是可学习的参数或者一个固定超参数。σ ( . ) ∈ ( 0 , 1 ) \sigma(.) \in (0,1)σ(.)∈(0,1) 可以看作一种软性的门控机制,当σ ( β x ) \sigma(\beta x)σ(βx) 接近于1时,门的状态为“开”状态,激活函数的输出近似于x本身;当σ ( β x ) \sigma(\beta x)σ(βx) 接近于0时,门的状态为“关”,激活函数的输出近似于0.
Swish函数的示意图如下图
x = np.linspace(-6, 6, 600)
m1 = nn.SiLU()
output1 = m1(torch.Tensor(x))
plt.plot(x, output1, label='Swish')
plt.title("Swish Activation Function")
plt.xlabel("x")
plt.ylabel("Activation")
plt.grid()
plt.legend()
plt.show()
1
2
3
4
5
6
7
8
9
10
当β = 0 \beta=0β=0时, Swish函数变成线性函数x/2
当β = 1 \beta=1β=1时, Swish函数在x>0时近似线性,在x<0时近似饱和,同时有一定的单调性
当β → + ∞ \beta \rightarrow + \inftyβ→+∞时, Swish函数近似为ReLU函数
所以Swish函数可以看做线性函数和ReLU函数之间的非线性插值函数,其程度由β \betaβ控制
GELU
GELU (Gaussian Error Linear Unit) 也是通过门控机制来调整其输出值的激活函数,其表达式为:
G E L U ( x ) = x P ( X ≤ x ) GELU(x) = xP(X \le x)
GELU(x)=xP(X≤x)
其中的P ( X ≤ x ) P(X \le x)P(X≤x)是高斯分布N ( μ , σ 2 ) \mathcal{N}(\mu, \sigma^2)N(μ,σ
2
)的累积分布函数,μ \muμ和σ \sigmaσ也是超参数,一般取标准分布,即μ = 0 , σ = 1 \mu=0, \sigma=1μ=0,σ=1。
由于高斯分布的累积分布函数为S型函数,所以它可以用Tanh和Sigmoid函数来近似:
G E L U ( x ) ≈ 0.5 x ( 1 + t a n h ( 2 π ( x + 0.044715 x 3 ) ) ) G E L U ( x ) ≈ x σ ( 1.702 x ) GELU(x) \approx 0.5x \left( 1 + tanh (\sqrt{\frac{2}{\pi}} (x+0.044715x^3) ) \right) \\ GELU(x) \approx x \sigma(1.702x)
GELU(x)≈0.5x(1+tanh(
π
2
(x+0.044715x
3
)))
GELU(x)≈xσ(1.702x)
当用sigmoid函数来近似时,GELU相当于一种特殊的Swish函数。
GELU的示意图如下:
x = np.linspace(-6, 6, 600)
m1 = nn.GELU()
output1 = m1(torch.Tensor(x))
plt.plot(x, output1, label='GELU')
plt.title("GELU Activation Function")
plt.xlabel("x")
plt.ylabel("Activation")
plt.grid()
plt.legend()
plt.show()
1
2
3
4
5
6
7
8
9
10
大模型gpt3使用GELU激活函数
GLU
Gated Linear Units (GLU) 是在论文《Language Modeling with Gated Convolutional Networks》 中被提出来的,计算表达式为:
G L U ( a , b ) = a ⊗ σ ( b ) GLU(a, b) = a \ \otimes \ \sigma(b)
GLU(a,b)=a ⊗ σ(b)
上式中的σ \sigmaσ是sigmoid函数,⊗ \otimes⊗是矩阵间的按元素乘。
从直觉上来说,对于语言模型门控(gate)机制允许选择对于预测下一个单词更重要的单词或特征。
在论文《GLU Variants Improve Transformer》 中下面几种GLU变种被提出。
ReGLU
ReGLU是采用ReLU函数作为激活函数的GLU变体
R e G L U ( x , W , V , b , c ) = m a x ( 0 , x W + b ) ⊗ ( x V + c ) ReGLU(x, W, V, b, c) = max(0, xW + b) \otimes (xV +c)
ReGLU(x,W,V,b,c)=max(0,xW+b)⊗(xV+c)
JINA EMBEDDINGS 2 对于large版本使用的是ReGLU,其作者说对于大模型使用GEGLU相对没有那么稳定。
SwiGLU
SwiGLU可以看做采用Swish作为激活函数的GLU变体
S w i G L U ( x , W , V , b , c ) = S w i s h 1 ( x W + b ) ⊗ ( x V + c ) SwiGLU(x, W, V, b, c) = Swish_1(xW + b) \otimes (xV +c)
SwiGLU(x,W,V,b,c)=Swish
1
(xW+b)⊗(xV+c)
Meta开源的LLaMA 和 LLaMA2 以及 Baichuan大模型使用的激活函数是SwiGLU。
GEGLU
GEGLU则可以看做采用GELU作为激活函数的GLU变体
G E G L U ( x , W , V , b , c ) = G E L U ( x W + b ) ⊗ ( x V + c ) GEGLU(x, W, V, b, c) = GELU(xW + b) \otimes (xV +c)
GEGLU(x,W,V,b,c)=GELU(xW+b)⊗(xV+c)
GLM-130B 大模型使用的是GEGLU。
资源
https://www.jiqizhixin.com/articles/2021-02-24-7
邱锡鹏《神经网络与深度学习》
A Survey of Large Language Models
https://zhuanlan.zhihu.com/p/650237644
原文链接:https://blog.csdn.net/beingstrong/article/details/133827619
0 Comments