在上一篇文章中,介绍了如何使用优化函数更新权重参数,不断逼近损失函数的最小值,从而达到学习的目的。优化函数的基本思想是梯度下降法,而权重参数更新,需要计算所有权重相对于损失函数的梯度。而从之前神经网络介绍那篇文章我们可以知道,影响权重的梯度因素包括损失函数的导数、激活函数的导数、节点的输入值、权重值。
接下来,本文将介绍梯度消失和梯度爆炸的概念,以及神经网络训练过程中防止梯度消失和梯度爆炸问题的一些tricks。
梯度消失和梯度爆炸
神经网络训练时,特别是深层神经网络所面临的一个大问题就是梯度消失或梯度爆炸,也就权重对损失函数的导数变得非常大,或者非常小。梯度消失或爆炸问题一般随着网络层数的增加会变得越来越明显。
模拟梯度消失
如下图所示,假设每层都只有一个神经元,且每一层都可以用如下的公式表示,其中
σ
\sigma
σ为激活函数,在这里以sigmoid为例。
a
i
=
σ
(
z
i
)
=
σ
(
w
i
∗
x
i
)
,
其中
x
i
=
a
i
−
1
a_i = \sigma{(z_i)} = \sigma{(w_i * x_i)}, 其中x_i = a_{i-1}
ai=σ(zi)=σ(wi∗xi),其中xi=ai−1
那么可以推导出如下公式:
α
L
α
w
1
=
α
L
α
a
4
∗
α
a
4
α
z
4
∗
α
z
4
α
a
3
∗
α
a
3
α
z
3
∗
α
z
3
α
a
2
∗
α
a
2
α
z
2
∗
α
z
2
α
a
1
∗
α
a
1
α
z
1
∗
α
z
1
α
w
1
\frac{\alpha{L}}{\alpha{w_1}} = \frac{\alpha{L}}{\alpha{a_4}}*\frac{\alpha{a_4}}{\alpha{z_4}}*\frac{\alpha{z_4}}{\alpha{a_3}}*\frac{\alpha{a_3}}{\alpha{z_3}}*\frac{\alpha{z_3}}{\alpha{a_2}}*\frac{\alpha{a_2}}{\alpha{z_2}}*\frac{\alpha{z_2}}{\alpha{a_1}}*\frac{\alpha{a_1}}{\alpha{z_1}}*\frac{\alpha{z_1}}{\alpha{w_1}}
αw1αL=αa4αL∗αz4αa4∗αa3αz4∗αz3αa3∗αa2αz3∗αz2αa2∗αa1αz2∗αz1αa1∗αw1αz1
=
α
L
α
a
4
∗
σ
′
z
4
∗
w
4
∗
σ
′
z
3
∗
w
3
∗
σ
′
z
2
∗
w
2
∗
σ
′
z
1
∗
x
1
=\frac{\alpha{L}}{\alpha{a_4}}*{\sigma'{z_4}}*w_4*{\sigma'{z_3}}*w_3*{\sigma'{z_2}}*w2*{\sigma'{z_1}}*x_1
=αa4αL∗σ′z4∗w4∗σ′z3∗w3∗σ′z2∗w2∗σ′z1∗x1
而sigmoid函数的导数如下图所示:
可见,
σ
′
(
x
)
\sigma'(x)
σ′(x)的最大值为
1
4
\frac{1}{4}
41,而一般网络训练时,会使用一个均值为0标准差为1的高斯分布来初始化网络权重,即初始化的权重值通常都是小于1的,从而
σ
′
(
x
)
∗
w
≤
1
4
\sigma'(x)*w ≤ \frac{1}{4}
σ′(x)∗w≤41。因此,对于上式中的链式求导,当层数越多,求导结果越小,最终导致梯度消失的情况出现。
梯度爆炸
当
σ
′
(
x
)
∗
w
>
1
\sigma'(x)*w > 1
σ′(x)∗w>1时,也即
w
w
w比较大的情况。则靠近输入层的隐藏层梯度变化巨大,从而引起梯度爆炸的问题。
归一化输入
训练神经网络,其中一个加速训练的方法就是归一化输入。归一化输入包含如下两个步骤:
- 零均值:计算所有样本的均值 μ = 1 m ∑ i = 1 m x i \mu=\frac{1}{m}\sum_{i=1}^m{x^{i}} μ=m1∑i=1mxi,然后每个样本减去均值 x i = x i − μ x^i = x^i - \mu xi=xi−μ
- 归一化方差:计算方差 σ 2 = 1 m ∑ i = 1 m ( x i ) 2 \sigma^2 = \frac{1}{m}\sum_{i=1}^m(x^i)^2 σ2=m1∑i=1m(xi)2,然后每个样本都除以均值 x i = x i σ 2 + ϵ x^i = \frac{x^i}{\sqrt{\sigma^2 + \epsilon}} xi=σ2+ϵxi
权重初始化
为什么要初始化权重
从之前权重梯度计算中,可以知道权重值也参与了梯度计算,即权重初始化的目的是为了防止深度神经网络在前向传播过程中,由于权重过大或者过小导致输出无效,反向传播过程中出现梯度消失或爆炸。
前向传播
以一个简单没有激活函数的100层神经网络为例,使用torch.randn生成标准正态分布数据初始化输入x和权重矩阵a,进行前向传播:
x
=
x
1
∗
w
1
+
x
2
∗
w
2
+
.
.
.
+
x
100
∗
w
100
x = x_1*w_1 + x_2*w_2 + ... + x_{100}*w_{100}
x=x1∗w1+x2∗w2+...+x100∗w100
>>> x = torch.randn(512)
>>> for i in range(100):
... a = torch.randn(512, 512)
... x = a @ x
...
>>> x.mean()
tensor(nan)
>>> x.std()
tensor(nan)
可以看到,经过100次矩阵乘法,在某次运算中,层输出变得非常大,导致计算机都无法识别其标准差和均值。也就是出现了梯度爆炸的情况。
当使用均值为0,方差为0.01的正态分布初始化权重时,进行前向传播:
>>> x = torch.randn(512)
>>> for i in range(100):
... a = torch.randn(512, 512) * 0.01
... x = a @ x
...
>>> x.mean()
tensor(0.)
>>> x.std()
tensor(0.)
可以看到,此时层输出值无限趋近于0。也即,权重初始值太大或太小,模型都不能好好学习。
权重初始化的方法
常见的权重初始化方法有三种:Xavier初始化、Kaimming He初始化、初始化为0.
Xavier初始化
Xavier初始化是一种经典的权重初始化方法,根据输入和输出的维度自适应地设置权重参数地初始值,将每层的权重设置在有界的随机均匀分布上,表达式如下所示:
W
∼
U
[
−
6
n
i
+
n
i
+
1
,
6
n
i
+
n
i
+
1
]
W\sim{U[-\frac{\sqrt{6}}{\sqrt{n_i + n_{i+1}}}, \frac{\sqrt{6}}{\sqrt{n_i + n_{i+1}}}]}
W∼U[−ni+ni+16,ni+ni+16]
其中
n
i
n_i
ni表示该神经元的输入连接数,
n
i
+
1
n_{i+1}
ni+1表示输出连接数。Xavier权重初始化能保证激活函数和反向传播梯度的方差,一直向上或向下传播到神经网络的每一层。
Kaimming He初始化
与Xavier初始化类似,He初始化也是根据输入和输出地维度自适应地设置权重参数的初始值。不同的是,He初始化方法是为了更好地适应ReLU激活函数而设计的。Xavier激活函数适用于:关于0对称,线性的激活函数,而ReLU激活函数并不满足这些条件。
初始化为0
以下图的简单两层神经网络为例,模拟权重初始化为0的前向传播和反向传播过程。
前向传播:
z
1
[
1
]
=
w
11
[
1
]
∗
x
1
+
w
21
[
1
]
∗
x
2
=
0
;
a
1
[
1
]
=
σ
(
z
1
[
1
]
)
=
0.5
z_1^{[1]} = w_{11}^{[1]} * x_1 + w_{21}^{[1]} * x_2 = 0;a_1^{[1]}=\sigma(z_1^{[1]})=0.5
z1[1]=w11[1]∗x1+w21[1]∗x2=0;a1[1]=σ(z1[1])=0.5
z
2
[
1
]
=
0
;
a
2
[
1
]
=
0.5
z_2^{[1]}=0;a_2^{[1]}=0.5
z2[1]=0;a2[1]=0.5
z
3
[
1
]
=
0
;
a
3
[
1
]
=
0.5
z_3^{[1]}=0;a_3^{[1]}=0.5
z3[1]=0;a3[1]=0.5
z
1
[
2
]
=
0
;
a
1
[
2
]
=
0.5
z_1^{[2]}=0;a_1^{[2]}=0.5
z1[2]=0;a1[2]=0.5
当权重全初始化为0时,神经元的输出值全部相同。接下来模拟反向传播:
α
L
α
w
11
[
2
]
=
α
L
α
a
1
[
2
]
∗
α
a
1
[
2
]
α
z
1
[
2
]
∗
a
1
[
1
]
=
α
L
α
a
1
[
2
]
∗
σ
(
z
1
[
2
]
)
(
1
−
σ
(
z
1
[
2
]
)
)
∗
0.5
=
α
L
α
a
1
[
2
]
∗
(
0.5
)
3
\frac{\alpha{L}}{\alpha{w_{11}^{[2]}}}=\frac{\alpha{L}}{\alpha{a_{1}^{[2]}}}*\frac{\alpha{a_1^{[2]}}}{\alpha{z_{1}^{[2]}}}*a_1^{[1]}=\frac{\alpha{L}}{\alpha{a_{1}^{[2]}}}*\sigma(z_1^{[2])}(1-\sigma(z_1^{[2])})*0.5 = \frac{\alpha{L}}{\alpha{a_{1}^{[2]}}}*(0.5)^3
αw11[2]αL=αa1[2]αL∗αz1[2]αa1[2]∗a1[1]=αa1[2]αL∗σ(z1[2])(1−σ(z1[2]))∗0.5=αa1[2]αL∗(0.5)3
α
L
α
w
21
[
2
]
=
α
L
α
a
1
[
2
]
∗
(
0.5
)
3
\frac{\alpha{L}}{\alpha{w_{21}^{[2]}}}=\frac{\alpha{L}}{\alpha{a_{1}^{[2]}}}*(0.5)^3
αw21[2]αL=αa1[2]αL∗(0.5)3
α
L
α
w
31
[
2
]
=
α
L
α
a
1
[
2
]
∗
(
0.5
)
3
\frac{\alpha{L}}{\alpha{w_{31}^{[2]}}}=\frac{\alpha{L}}{\alpha{a_{1}^{[2]}}}*(0.5)^3
αw31[2]αL=αa1[2]αL∗(0.5)3
而对于
w
11
[
1
]
,
w
21
[
1
]
,
w
31
[
1
]
w_{11}^{[1]},w_{21}^{[1]},w_{31}^{[1]}
w11[1],w21[1],w31[1]的偏导,由于相乘的数值中包含权重值,因此全为0.
综上,当权重全部初始化为0时,每层神经元在第一次前向传播时具有相同的输出值,而在反向传播更新权重时,只有最后一层权重得到更新,从而导致网络无法学习。
学习率衰减
在Mini-Batch梯度下降法中,由于损失函数的梯度计算取决于一小部分样本,样本的随机性可能导致梯度波动方差较大,可以通过不断减少学习率,慢慢收敛到极小值。
学习率衰减方法
常见的学习率衰减方法共有四种:指数衰减、固定步长衰减、多步衰减、余弦退火衰减。变化规则如下图所示:
指数衰减
学习率按照指数的形式衰减是比较常用的策略。pytorch中的使用方法如下:
ExpLR = torch.optim.lr_scheduler.ExponentialLR(optimizer_ExpLR, gamma=0.98)
其中参数gamma表示衰减的底数,选择不同的gamma值可以获得幅度不同的衰减曲线,如下:
可以看到gamma值越小学习率衰减的越快。
固定步长衰减
即学习率每个一定的步数(或者epoch)就减少为原来的gamma分之一。
StepLR = torch.optim.lr_scheduler.StepLR(optimizer_StepLR, step_size=step_size, gamma=0.65)
其中gamma参数表示衰减的程度,step_size参数表示每隔多少个step进行一次学习率调整。
多步长衰减
固定步长的衰减虽然能够按照固定的区间长度进行学习率更新,但是优势我们希望不同的区间采用不同的更新频率。
torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[200, 300, 320, 340, 200], gamma=0.8)
其中milestones参数便是学习率更新的起止区间,上述表示在区间[0, 200]之间学习率不更新,其后区间都进行一次更新。
余弦退火
严格来说,余弦退火策略不应该是学习率衰减策略,因为它使得学习率成周期性变化。
CosineLR = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer_CosineLR, T_max=150, eta_min=0)
其中T_max表示余弦函数周期;eta_min表示学习率的最小值。
BatchNorm
BatchNorm是一种常用的神经网络正则化技术,旨在加速训练并提高模型性能。
为什么要使用BatchNorm
BatchNorm的作用是,在深度神经网络训练过程中使每一层神经网络的输入变得更加稳定,从而提高网络的训练速度。
Internal Covariate Shift问题
在深度神经网络中,每一层的输入数据分布通常会随着训练的进行而发生变化,即每一层的输入分布总是变化,使得网络很难稳定学的规律。在训练过程中,由于各层参数在不停变化,导致隐藏层的输入分布老是变来变去,就所谓的"Internal Covariate Shift"问题。
BatchNorm的基本思想:让每个隐藏节点的激活输入
z
z
z分布固定下来,从而避免"Internal Covariate Shift"问题。由于深度神经网络在做非线性变换前的激活输入值在训练过程中,其分布逐渐发生偏移或者变动,使得整体分布逐渐往非线性函数(sigmoid为例)的取值区间的上下两端靠近,导致反向传播时低层神经网络的梯度消失,神经网络收敛越来越慢。
BN就是通过规范化手段,将每个神经元的输入值的分布强行拉回到均值为0方差为1的标准正态分布,使得激活输入值
z
z
z落在非线性激活函数变化率较大的区域,输入小的变换能够引起损失函数较大的变化,避免梯度消失问题产生,同时非线性激活函数的敏感区域能引起梯度较大变化,即能加快训练速度。
同时,当所有分布都被拉回到标准正态分布后,多层神经网络每一层都成了一个固定的表达式,即网络的表达能力下降了,深度的意义不存在。为了解决该问题,BN对变换后的标准正态分布又进行了scale和shift操作,这两个参数scale和shift是通过训练学习得到的。
什么是BatchNorm
对于mini-batch训练来说,一次训练过程包含m个训练实例,BN的具体操作流程如下:
首先,将神经元的输入激活值拉到均值为0,方差为1的标准分布,为了防止网络表达能力下降,为每个神经元增加两个调节参数(scale和shift),使得网络的拟合能力增强。
训练阶段
在训练阶段,BN会对每个输入值(样本)进行标准化,并使用指数加权移动平均法将均值和方差保存下来,近似得到整个样本集的均值和方差。在整个样本集上,会产生(样本总数/BatchSize)组 γ \gamma γ和 β \beta β。
def bn_simple_for_train(x, gamma, beta, bn_params):
'''
X : 输入数据
gamma:缩放因子
beta:平移因子
bn_params: batch norm所需要的一些参数
running_mean: 滑动平均的方式计算新的均值,训练时计算,为测试数据做准备
running_var: 滑动平均的方式计算新的方差,训练时计算,为测试数据做准备
'''
running_mean = bn_params["running_mean"] # shape = [B]
running_var = bn_params["running_var"]
x_mean = x.mean(axis=0)
x_var = x.var(axis=0)
# 归一化
x_normalized = (x - x_mean) / np.sqrt(x_var + eps)
# bn
res = gamma * x_normalized + beta
# 滑动平移方式
running_mean = momentum * running_mean + (1- momentum) * x_mean
running_var = momentum * running_var + (1 - momentum) * x_var
# 记录新的参数值
bn_params["running_mean"] = running_mean
bn_params["running_var"] = running_var
return res, bn_params
推理阶段
由于测试的时候,输入样本只有一个,没法计算均值和方差,即使用训练阶段求得的全局统计量来预测。
def bn_simple_for_test(x, gamma, beta, bn_params):
'''
X : 输入数据
gamma:缩放因子
beta:平移因子
bn_params: batch norm所需要的一些参数
running_mean: 滑动平均的方式计算新的均值,训练时计算,为测试数据做准备
running_var: 滑动平均的方式计算新的方差,训练时计算,为测试数据做准备
'''
running_mean = bn_params["running_mean"]
running_var = bn_params["running_var"]
# 归一化
x_normalized = (x - running_mean) / np.sqrt(running_var + eps)
# bn
res = gamma * x_normalized + beta
return res, bn_params
激活函数
在机器学习和深度学习中,激活函数通常用来为神经网络引入非线性因素,使得网络能在输入和输出数据中构建复杂和非线性关系。激活函数应该需要具有如下特性:
- 非线性:激活函数必须具有非线性,使得输入和输出数据之间具有非线性关系;
- 连续性:激活函数应该是连续且可微的,因为在进行梯度更新时,需要计算激活函数的导数;
- 计算效率高:计算量大的激活函数会显著减慢训练过程;
为什么需要激活函数
如果不使用激活函数,即激活函数为
f
(
x
)
=
x
f(x)=x
f(x)=x,此时,每一次节点的输入都是上层输出的线性函数,那么,无论神经网络有多少层,输出都是输入的线性组合,无法处理非线性关系,网络表达能力有限。通过引入激活函数,增加网络的非线性特性,使得网络的表达能力更加强大,可以拟合任意函数。此外,激活函数还可以使神经网络具有一定的抗噪性,能够处理噪声数据。
不同激活函数的区别和特点
常见的激活函数包括sigmoid函数、tanh函数、ReLU函数等。
- sigmoid函数
sigmoid是常用的非线性激活函数,数学形式如下:
f
(
x
)
=
1
1
+
e
−
z
f(x)=\frac{1}{1 + e^{-z}}
f(x)=1+e−z1
几何图像如下:
其导数的表达式如下:
f
′
(
x
)
=
σ
(
x
)
(
1
−
σ
(
x
)
)
f'(x) = \sigma(x)(1-\sigma(x))
f′(x)=σ(x)(1−σ(x))
几何图像如下:
优点:
- sigmoid函数的输出范围在[0,1]之间,可以将输出限制在一个特定的范围内;
- sigmoid函数的导数可以用它自己表示,方便计算;
- sigmoid函数具有平滑的连续性,可以保证神经网络的连续性;
缺点:
- sigmoid函数的梯度在较大或较小的输入值处接近于0,会导致梯度消失的问题,使得神经网络无法继续学习;
- sigmoid函数的输出不是以0为中心zero-centered,那么在反向传播时,梯度的方向会偏向某一侧,而不是均匀地分布在两侧,这可能倒是训练过程出现不稳定的现象。
- sigmoid函数的计算比ReLU和tanh函数慢,因为需要进行指数运算;
- tanh函数
tanh是一种常用的激活函数,其输出范围为[-1,1]。与sigmoid函数类似,tanh函数也是一种S型函数,但是 它的输出范围更广。其数学表达式如下:
t
a
n
h
(
x
)
=
e
x
−
e
−
x
e
x
+
e
−
x
tanh(x) = \frac{e^x- e^{-x}}{e^x+e^{-x}}
tanh(x)=ex+e−xex−e−x
几何图像如下所示:
tanh函数的导数为:
d
d
x
t
a
n
h
(
x
)
=
1
−
(
t
a
n
h
(
x
)
)
2
\frac{d}{dx}tanh(x) = 1- {(tanh(x))}^2
dxdtanh(x)=1−(tanh(x))2
几何图像如下所示:
优点:
- 输出范围为[-1, 1],可以将数据规范化到一个较少的范围,有助于模型的稳定性和收敛速度;
- 具有zero-centered特性,有组于模型的训练和优化;
缺点:
- 容易出现梯度消失问题;
- 计算量较大,tanh函数的计算量比sigmoid函数大两倍,影响模型的训练速度;
- 对于输入较大或较少的数据,tanh函数会出现饱和现象,也存在梯度饱和问题,影响模型的训练效率;
- ReLU函数
ReLU激活函数是一种常用的非线性激活函数,其表达式如下:
r
e
l
u
(
x
)
=
m
a
x
(
0
,
x
)
relu(x) = max(0, x)
relu(x)=max(0,x)
其几何图像如下所示:
优点:
- 计算速度快;
- 解决了梯度消失问题;
- 收敛速度快,因为ReLU激活函数的导数为0或1,不存在平滑的过渡区域,因此在训练时更容易收敛;
缺点:
- 部分神经元可能“死亡”,即输出一直为0,导致这些神经元无法参与模型的训练;
- 需要进行数据预处理,将输入的数据进行归一化或标准化,以避免出现负数输入;
- leaky ReLU(2013)
Leaky ReLU激活函数的函数定义为:
l
e
a
k
y
r
e
l
u
(
x
)
=
m
a
x
(
x
,
α
x
)
leaky_relu(x) = max(x, \alpha{x})
leakyrelu(x)=max(x,αx)
其中α是一个非常小的正数常量,通常设置为0.01。其几何图像如下图所示:
优点:
- 解决了神经元可能“死亡”问题;
- 计算效率高;
- Softplus(2010)
Softplus激活函数的定义如下:
s
o
f
t
p
l
u
s
(
x
)
=
l
n
(
1
+
e
x
)
softplus(x)=ln(1+e^x)
softplus(x)=ln(1+ex)
其几何图像如下图所示:
softplus激活函数可以近似堪称ReLU函数的平滑,连续且处处可导。相对于ReLU函数具有如下特点。
优点:
- 连续性:softplus函数是一个具有连续一阶导数的函数,有利于梯度更新;
- 非零的:不同于ReLU函数产生的输出值要么为0,要么为正,softplus函数产生正输出值;
- 非零梯度:softplus函数对负输入值有一个非零梯度,可以防止dying ReLU问题;
缺点:
- softplus输出值不是以0为中心;
- 其导数常常小于1,可能存在梯度消失问题;
- Swish(2017)
Swish激活函数的定义如下:
S
w
i
s
h
(
x
)
=
x
∗
σ
(
β
∗
x
)
Swish(x)=x*\sigma(\beta*x)
Swish(x)=x∗σ(β∗x)
其中
β
\beta
β是一个可学习参数,
σ
\sigma
σ是sigmoid函数。
- SiLU(2017)
SiLU(Sigmoid Linear Unit)激活函数融合了sigmoid和线性激活函数元素,其定义如下:
S
i
L
U
(
x
)
=
x
1
+
e
−
x
SiLU(x)=\frac{x}{1+e^{-x}}
SiLU(x)=1+e−xx
其几何图像如下所示:
优点:
- smooth gradients:SiLU函数具有平滑导数,可以避免出现梯度消失问题;
- 非单调性:SiLU函数是非单调的,既有正值也有负值,使得SiLU函数可以捕获输入数据中的复杂模式;
- 计算效率高;
- HardSwish(2019)
HardSwish激活函数是一种分段线性激活函数,是Swish函数的简化版本,其定义如下:
h
a
r
d
s
w
i
s
h
(
x
)
=
{
0
,
i
f
(
x
≤
−
3
)
x
,
i
f
(
x
≥
3
)
x
(
x
+
3
)
6
,
o
t
h
e
r
v
i
s
e
hard_swish(x) = \begin{cases} 0, \quad if(x\le-3) \\x, \quad if(x\ge3) \\ \frac{x(x+3)}{6}, \quad othervise \end{cases}
hardswish(x)=⎩
⎨
⎧0,if(x≤−3)x,if(x≥3)6x(x+3),othervise
其几何图像如下所示:
hardswish激活函数是对swish激活函数的改进,swish激活函数能在一定程度上提高神经网络的准确性,但是不适合在嵌入式移动设备上使用,因为”S“型函数在嵌入式移动设备上的计算成本高,求导较为复杂。
优点:
- 计算速度快;
- 相对于ReLU,能够有效地缓解梯度消失问题;
缺点:
- 非线性程度较低:与Swish和Mish激活函数相比,HardSwish的非线性程度相对较低,可能无法充分挖掘数据中的非线性特征;
- Mish(2019)
Mish激活函数拥有** 无上界、有下界、平滑导数和非单调**四个优点,其数学表达形式如下:
f
(
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
p
(
x
)
)
)
f(x)=x*tanh(softplus(x)) = x * tanh(ln(1+exp(x)))
f(x)=x∗tanh(softplus(x))=x∗tanh(ln(1+exp(x)))
几何图形如下:
特点:
- 非单调性(非线性):通过导数可以得到Mish函数在不同区间上可能单调递增或递减,可以捕获输入数据中的复杂模式;
- 连续性:Mish激活函数具有较好的连续性,且处处可微,能够更好地更新模型;
- 无上界有下界:无上界可以避免饱和问题,有下界有助于实现强正则化效果;
如何选择合适的激活函数
选择合适的激活函数可以考虑如下几点:
- 尽量选择使用zero-centered特点的激活函数来加快模型的收敛速度;
- 考虑梯度消失问题,选择不容易出现梯度消失问题的激活函数,如ReLU、Leaky ReLU等;
- 考虑计算效率;
参考链接
- https://zhuanlan.zhihu.com/p/72374385
- https://zhuanlan.zhihu.com/p/62850258
- https://blog.csdn.net/Roaddd/article/details/114794071
- https://blog.csdn.net/weixin_44751294/article/details/125085657
- https://blog.csdn.net/tyhj_sf/article/details/79932893
- https://blog.csdn.net/weixin_46716951/article/details/124292876
- https://www.cnblogs.com/guoyaohua/p/8724433.html