今天要整理的内容有关梯度。从这篇文章,你可以了解到什么是梯度,梯度又是怎样下降的,怎样通过下降来更新参数,以及在下降过程中,为什么会出现消失和爆炸的问题及其解决方案。
导数与方向导数
关于导数最简单的理解就是:函数在某一点切线的斜率,被称为函数在该点上的导数。如果想用数学公式来理解的话:假设函数y=f(x),自变量在
x
0
x_0
x0这点上变化了
△
x
\triangle x
△x(这里的变化是增量),那么我们相应地能得到一个函数的变化量
△
y
\triangle y
△y,我们定义:如果函数的变化量
△
y
\triangle y
△y与自变量的变化量
△
x
\triangle x
△x的比值,在
△
x
\triangle x
△x趋向于0时的极限(假设极限值为a)存在,记为:
lim
△
x
→
0
△
y
△
x
=
lim
△
x
→
0
f
(
x
0
+
△
x
)
−
f
(
x
0
)
△
x
=
a
\lim_{\triangle x\to 0}\frac{\triangle y}{\triangle x}=\lim_{\triangle x\to 0}\frac{f(x_0+\triangle x)-f(x_0)}{\triangle x}=a
△x→0lim△x△y=△x→0lim△xf(x0+△x)−f(x0)=a
那么a就为函数在
x
0
x_0
x0处的导数。
方向导数: 顾名思义就是有方向的导数,那么什么才有方向?我们都知道点是没有方向可言的(我们定义 点是具备任意方向的),而线是有方向的,正所谓两点确定一条直线,直线有正方向和反方向,而带箭头的直线只有一个方向。知道这个前提就好办了,为了方便举例,我们在平面上定义线的存在,
(
x
0
,
y
0
)
(x_0,y_0)
(x0,y0)和
(
x
1
,
y
1
)
(x_1,y_1)
(x1,y1)两个点确定了一条线(可以说是确定了一个方向)。
我们定义函数z=f(x,y)表示,点P代表
(
x
0
,
y
0
)
(x_0,y_0)
(x0,y0),q代表
(
x
1
,
y
1
)
(x_1,y_1)
(x1,y1),那么按照导数的定义,该函数在这两点之间的变化量
△
z
\triangle z
△z与两点之间的距离
l
=
∣
P
q
∣
=
(
△
x
)
2
+
(
△
y
)
2
l=|Pq|=\sqrt {(\triangle x)^2+(\triangle y)^2}
l=∣Pq∣=(△x)2+(△y)2的极限存在,那么就有:
ϑ
f
ϑ
l
=
lim
l
→
0
△
z
△
l
=
lim
△
l
→
0
f
(
x
+
△
x
,
y
+
△
y
)
−
f
(
x
,
y
)
△
l
\frac{\vartheta f}{\vartheta l}=\lim_{l \to 0}\frac{\triangle z}{\triangle l}=\lim_{\triangle l\to 0}\frac{f(x+\triangle x,y+\triangle y)-f(x,y)}{\triangle l}
ϑlϑf=l→0lim△l△z=△l→0lim△lf(x+△x,y+△y)−f(x,y)
这个就称为点P沿着方向L的方向导数。简单地说,方向导数就是函数沿着某个方向的变化率,即斜率。
梯度
梯度: 是一个矢量(具有大小和方向),表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(梯度方向)变化最快,变化率(梯度的模即大小)最大。按照理解:我们说过一个点是具有任意方向的,那在空间中,函数上的某一个点也是具有任意方向的,而如果沿着任意方向都有导数存在,那么一定会有一个最大的导数,而沿着这个方向的方向导数就是梯度。也就是说:方向导数中最大值的方向就是梯度的方向,方向导数的最大值就是梯度的值,即梯度是斜率最大的切线方向。
由于梯度的方向是与方向导数的最大值方向(向上增长的方向)是一致的,所以沿着梯度的反方向下降总是最快的。
梯度下降
在深度学习中,其实所有的神经网络说白了就是一个复合的非线性多元函数。那么既然是函数了,就有我们上面所说的导数、方向导数等等这些了。为了方便描述,我们令一个神经网络为多元函数F(x):
F
(
x
)
=
f
n
(
.
.
.
f
2
(
f
1
(
x
)
∗
w
1
+
b
)
∗
w
2
+
b
)
.
.
.
)
F(x)=f_n(...f_2(f_1(x)*w_1+b)*w_2+b)...)
F(x)=fn(...f2(f1(x)∗w1+b)∗w2+b)...)
训练神经网络的过程,其实就是优化函数中的参数
w
i
和
b
w_i和b
wi和b,(i=1,…n),最终使得这个多元函数很好地拟合输入与输出之间的关系,假设对不同的输入,输出的最优解是g(x),那我们优化的目标是通过找到损失函数
L
o
s
s
=
L
(
g
(
x
)
,
F
(
x
)
)
Loss=L(g(x),F(x))
Loss=L(g(x),F(x))的最小值。而寻找一个函数的最值问题是属于数学上的优化问题,有很多方法可以解决,但对于求解无约束问题时常用的是梯度下降法。
梯度下降法(gradient descent) 是一种迭代法,它的计算过程是沿着梯度下降的方向求解极小值(反过来,如果要求解损失函数的最大值,那就要用梯度上升法来迭代)。在机器学习中,基于基本的梯度下降法发展了两种梯度下降方法,分别为随机梯度下降法(SGD)和批量梯度下降法(BGD)。梯度下降的基本迭代公式是:
w
k
+
1
=
w
k
−
α
△
L
(
w
)
△
w
w_{k+1}=w_k-\alpha \frac{\triangle L(w)}{\triangle w}
wk+1=wk−α△w△L(w)
其中,
x
k
x_k
xk为当前时刻值,
x
k
+
1
x_{k+1}
xk+1为下一时刻值,
α
\alpha
α是一个正数,代表步长(在深度学习中,我们称它为学习率),
△
F
(
x
)
△
x
\frac{\triangle F(x)}{\triangle x}
△x△F(x)为梯度;减号代表梯度的反方向。
补充:学习率的作用就是限制参数更新的幅度,这里借用一幅图来展示学习率的作用:
注:图来源于一篇博文,上图中,左图是我们所期望的,一个点按照梯度方向下降,慢慢逼近最低点,右图中展示的梯度下降步子过大,容易一次性就直接跨过了最低点,导致函数很难收敛,无法找到最优解。
举个栗子
回到我们刚才的迭代公式中,列举一个非常简单的栗子,我们只考虑优化参数w的情况。假设刚才的损失函数为
L
o
s
s
=
L
(
w
)
=
1
2
∑
i
=
1
n
(
F
w
(
x
i
)
−
g
(
x
)
i
)
2
Loss=L(w)=\frac12\sum_{i=1}^n(F_w(x^i)-g(x)^i)^2
Loss=L(w)=21i=1∑n(Fw(xi)−g(x)i)2
那么,对参数w的求导过程为:
ϑ
ϑ
w
j
L
(
w
)
=
ϑ
ϑ
w
j
1
2
(
F
w
(
x
)
−
g
(
x
)
)
2
=
2
⋅
1
2
(
F
w
(
x
)
−
g
(
x
)
)
⋅
ϑ
ϑ
w
j
(
F
w
(
x
)
−
g
(
x
)
)
=
(
F
w
(
x
)
−
g
(
x
)
)
⋅
ϑ
ϑ
w
j
(
∑
i
=
1
n
(
w
i
x
i
+
b
)
−
g
(
x
)
)
=
(
F
w
(
x
)
−
g
(
x
)
)
x
j
\begin{aligned} \frac{\vartheta }{\vartheta w_j}L(w)&=\frac{\vartheta }{\vartheta w_j}\frac12(F_w(x)-g(x))^2\\ &=2 \cdot \frac12(F_w(x)-g(x))\cdot \frac{\vartheta }{\vartheta w_j}(F_w(x)-g(x))\\ &=(F_w(x)-g(x))\cdot \frac{\vartheta }{\vartheta w_j}(\sum_{i=1}^n(w_ix_i+b)-g(x))\\ &=(F_w(x)-g(x))x_j \end{aligned}
ϑwjϑL(w)=ϑwjϑ21(Fw(x)−g(x))2=2⋅21(Fw(x)−g(x))⋅ϑwjϑ(Fw(x)−g(x))=(Fw(x)−g(x))⋅ϑwjϑ(i=1∑n(wixi+b)−g(x))=(Fw(x)−g(x))xj
最后根据迭代公式,更新下一个参数
w
k
+
1
w_{k+1}
wk+1。这样我们就可以找到最优的参数w和b使得损失函数L取得最小值了。
梯度爆炸与消失
梯度爆发(exploding gradient) 或 梯度消失(vanishing gradient),从字面上可以很好地理解这两个词的概念:梯度等于0即梯度消失了,梯度无限制地增大即梯度爆炸。其实,它们是一回事,总的来说就是梯度出现了问题,只是表现形式和产生的原因不一样而已。
如何判断梯度是否出现了问题?
在训练过程中,仔细留意计算图的一些变化,我们能发现梯度是出现问题了:
- 模型不稳定,在更新过程中,损失值变化非常明显
- 训练过程中,模型梯度快速变化
- 训练过程中,模型权重变成了NaN值或者损失值变成NaN
- 训练过程中,每个节点和层的误差梯度值持续超过1.0
引起的原因
我们都知道,浅层的神经网络拟合效果总是比深层的网络的差,所以大家都偏向于增加隐层的数量。但是,随着网络层数地不断加深,问题就会出来了。假设这里三个隐层的网络每一层都使用softmax作为激活函数。网络的表示为
f
i
(
x
)
f_i(x)
fi(x),其中i为第i层,前一层(即i-1层)的输出为
f
i
(
x
)
f_i(x)
fi(x)。softmax函数表示
s
o
f
t
m
a
x
=
f
(
t
)
,
t
=
w
x
softmax=f(t),t=wx
softmax=f(t),t=wx。
如果我们要更新每层隐层的参数,根据迭代公式: w k + 1 = w k − α ϑ L ( w ) ϑ w k + 1 w_{k+1}=w_k-\alpha \frac{\vartheta L(w)}{\vartheta w_{k+1}} wk+1=wk−αϑwk+1ϑL(w),而需要求出损失函数对 w k + 1 w_{k+1} wk+1偏导数。
首先求第3隐层的参数
w
3
w_3
w3的偏导数,根据链式法则,就有:
ϑ
L
o
s
s
ϑ
w
3
=
ϑ
L
(
w
)
ϑ
f
3
ϑ
f
3
ϑ
t
3
ϑ
t
3
ϑ
w
3
=
ϑ
L
(
w
)
ϑ
f
3
ϑ
f
3
ϑ
t
3
x
3
=
A
s
(
3
)
x
3
\begin{aligned}\frac{\vartheta Loss}{\vartheta w_3} &=\frac{\vartheta L(w)}{\vartheta f_3}\;\frac{\vartheta f_3}{\vartheta t_3}\;\frac{\vartheta t_3}{\vartheta w_3}\\ &=\frac{\vartheta L(w)}{\vartheta f_3}\;\frac{\vartheta f_3}{\vartheta t_3}\;x_3\\ &=A\;s(3)x_3 \end{aligned}
ϑw3ϑLoss=ϑf3ϑL(w)ϑt3ϑf3ϑw3ϑt3=ϑf3ϑL(w)ϑt3ϑf3x3=As(3)x3
求第2隐层的参数
w
2
w_2
w2的偏导数:
ϑ
L
o
s
s
ϑ
w
2
=
ϑ
L
(
w
)
ϑ
f
3
ϑ
f
3
ϑ
t
3
ϑ
t
3
ϑ
f
2
ϑ
t
2
ϑ
w
2
=
ϑ
L
(
w
)
ϑ
f
3
ϑ
f
3
ϑ
t
3
w
3
ϑ
f
2
ϑ
t
2
x
2
=
A
s
(
3
)
w
3
s
(
2
)
x
2
\begin{aligned}\frac{\vartheta Loss}{\vartheta w_2} &=\frac{\vartheta L(w)}{\vartheta f_3}\;\frac{\vartheta f_3}{\vartheta t_3}\;\frac{\vartheta t_3}{\vartheta f_2}\;\frac{\vartheta t_2}{\vartheta w_2}\\ &=\frac{\vartheta L(w)}{\vartheta f_3}\;\frac{\vartheta f_3}{\vartheta t_3}\;w_3\;\frac{\vartheta f_2}{\vartheta t_2}\;x_2\\ &=A\;s(3)w_3\;s(2)x_2 \end{aligned}
ϑw2ϑLoss=ϑf3ϑL(w)ϑt3ϑf3ϑf2ϑt3ϑw2ϑt2=ϑf3ϑL(w)ϑt3ϑf3w3ϑt2ϑf2x2=As(3)w3s(2)x2
同理,隐层1的参数梯度:
ϑ
L
o
s
s
ϑ
w
1
=
ϑ
L
(
w
)
ϑ
f
3
ϑ
f
3
ϑ
t
3
ϑ
t
3
ϑ
f
2
ϑ
t
2
ϑ
f
1
ϑ
f
1
ϑ
t
1
ϑ
t
1
ϑ
w
1
=
ϑ
L
(
w
)
ϑ
f
3
ϑ
f
3
ϑ
t
3
w
3
ϑ
f
2
ϑ
t
2
w
2
ϑ
f
1
ϑ
t
t
x
1
=
A
s
(
3
)
w
3
s
(
2
)
w
2
s
(
1
)
x
1
\begin{aligned}\frac{\vartheta Loss}{\vartheta w_1} &=\frac{\vartheta L(w)}{\vartheta f_3}\;\frac{\vartheta f_3}{\vartheta t_3}\;\frac{\vartheta t_3}{\vartheta f_2}\;\frac{\vartheta t_2}{\vartheta f_1}\;\frac{\vartheta f_1}{\vartheta t_1}\;\frac{\vartheta t_1}{\vartheta w_1}\\ &=\frac{\vartheta L(w)}{\vartheta f_3}\;\frac{\vartheta f_3}{\vartheta t_3}\;w_3\;\frac{\vartheta f_2}{\vartheta t_2}\;w_2\frac{\vartheta f_1}{\vartheta t_t}\;x_1\;\\ &=A\;s(3)w_3\;s(2)w_2\;s(1)x_1 \end{aligned}
ϑw1ϑLoss=ϑf3ϑL(w)ϑt3ϑf3ϑf2ϑt3ϑf1ϑt2ϑt1ϑf1ϑw1ϑt1=ϑf3ϑL(w)ϑt3ϑf3w3ϑt2ϑf2w2ϑttϑf1x1=As(3)w3s(2)w2s(1)x1
其中,
A
A
A代表损失函数对输入神经元的偏导
ϑ
L
(
w
)
ϑ
f
3
\frac{\vartheta L(w)}{\vartheta f_3}
ϑf3ϑL(w),这是定值,用A表示。
ϑ
f
3
ϑ
t
3
\frac{\vartheta f_3}{\vartheta t_3}
ϑt3ϑf3是激活函数softmax的偏导数,用
s
(
3
)
s(3)
s(3)表示,
ϑ
t
3
ϑ
f
2
\frac{\vartheta t_3}{\vartheta f_2}
ϑf2ϑt3s\是
w
x
wx
wx对
x
x
x求偏导,得到
w
w
w。
而softmax函数是用来做多分类的,它的函数形式是sigmoid的累加,为简单方便求解,使用sigmoid函数的形式:
s
i
g
m
o
i
d
=
f
(
t
)
=
1
(
1
+
e
−
w
x
)
sigmoid=f(t)=\frac{1}{(1+e^{-wx})}
sigmoid=f(t)=(1+e−wx)1,其函数图像为:
该函数具有如下的特性:当x趋近于负无穷时,y趋近于0;当x趋近于正无穷时,y趋近于1;当x= 0时,y=0.5。Sigmoid函数求导容易,处处可导,它的导数为:
f
′
(
t
)
=
s
(
t
)
=
f
(
t
)
(
1
−
f
(
t
)
)
f^′(t)=s(t)=f(t)(1−f(t))
f′(t)=s(t)=f(t)(1−f(t))
导数图像为:
从图像上可知:sigmoid的导函数曲线呈现驼峰状,导数的取值范围在0到0.25之间。由此可推:sigmoid的导函数最大值为0.25,即
1
4
\frac14
41,从上面每一隐层的梯度公式中可以看到,每个参数的梯度都是与sigmoid的导函数链式相乘,即
s
(
i
)
∗
w
i
s(i)*w_i
s(i)∗wi,所以:
- w i > 4 w_i\gt4 wi>4,梯度会随着层数的增加越来越大,会有梯度爆炸的可能;
- w i < 4 w_i\lt4 wi<4,梯度会随着层数的增加越来越小,会有梯度消失的可能;
解决方案
- 权重初始化: 使用Xavier初始化方式或者He初始化方式。Xavier初始化方法的使用条件是正向传播时,激活值的方差保持不变;反向传播时,关于状态值的梯度的方差保持不变,初始化参数: W ∼ U [ − 6 n i + n i + 1 , 6 n i + n i + 1 ] W\sim U[-\frac{\sqrt6}{\sqrt{n_i+n{i+1}}},\frac{\sqrt6}{\sqrt{n_i+n{i+1}}}] W∼U[−ni+ni+16,ni+ni+16],而He初始化方法的使用条件正向传播时,状态值的方差保持不变;反向传播时,关于激活值的梯度的方差保持不变。使用ReLu激活函数的参数被初始化为: W ∼ N [ 0 , 2 n i ] W\sim N[0,\sqrt{\frac{2}{n_i}}] W∼N[0,ni2],使用Leaky ReLu激活函数的参数被初始化为: W ∼ N [ 0 , 2 ( 1 + α 2 ) n i ] W\sim N[0,\sqrt{\frac{2}{(1+\alpha^2)n_i}}] W∼N[0,(1+α2)ni2]。
- pre-training+fine-tune: pre-training是预训练,基本思想是先找局部最优,然后再整合找全局最优。具体做法是逐层训练,训练完这一层隐层节点后,将这一层隐层的输出作为下一层的输入,再训练下一层。在预训练后,对整个网络微调(fine-tune)。
- 梯度剪切和权重正则: 梯度剪切是针对梯度爆炸提出的,它的思想是设置一个梯度的阈值,在更新梯度的时候,当梯度超过设定的阈值,就将梯度强制限制在阈值范围内,以防梯度爆炸。权重正则化也是解决梯度爆炸的另一个手段,通过对网络权重做正则防止过拟合,惩罚产生较大权重值的损失函数,通常使用L1惩罚项(权重绝对值)或L2惩罚项(权重平方)。
- 选择合适的激活函数: 可以使用relu、leakrelu、elu等激活函数代替原来的激活函数。relu函数的出现就是为了解决梯度消失和梯度爆炸的问题,同时它的计算还方便快速,能加速网络训练。leakrelu、elu都是relu函数的衍生版,都是为了解决relu函数的0区间带来的影响而出现的。
- 加入批量归一化层: 批量归一化层(BatchNormalization,BN)就是一个归一化网络层,它的思想是分别计算出样本的均值和方差,然后将样本进行平移和缩放,将样本规范化到均值为0,方差为1的标准特征分布范围里去。BN层能加快训练训练速度,提高网络的泛化能力。
- 使用残差结构: 使用残差结构,就是给原始模型增加一个shortcut,这种shortcut可以动态地调整模型的复杂度,最终实现让网络层数加深,又不用担心出现梯度问题。残差结构以跳层连接的形式,改变了损失函数求梯度的链式反应,很好地解决了深层网络退化问题。
总结
全文主要整理了有关梯度的问题:什么是梯度,梯度又是怎样下降的,怎样通过下降来更新参数,以及在下降过程中,为什么会出现消失和爆炸的问题及其解决方案。对于解决方案部分,里面提到了很多专业名词并没有详细地介绍,目前先写上,有个概念,后面会慢慢补上的。
参考:
https://blog.csdn.net/hfutdog/article/details/81151006?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
https://blog.csdn.net/weixin_39445556/article/details/83661219
https://www.jianshu.com/p/52fcd56f2406
https://blog.csdn.net/xxy0118/article/details/84333635
https://blog.csdn.net/donkey_1993/article/details/81871132