前言
其起源是我们想要神经网络结构对输入进行学习去拟合我们的目标输出,如何去衡量我们拟合的好不好,就是去衡量网络输出与标签值的距离,这个衡量距离的方法我们就称之为损失函数.有了损失函数我们的目标就是要去使得这个损失函数最小化,如何使得损失函数最小,我们想到导数,导数的定义如下方公式所示,当足够逼近x0时的斜率存在,则该点可导.
f
′
(
x
0
)
=
lim
△
x
→
0
f
(
x
0
+
△
x
)
−
f
(
x
0
)
△
x
f'(x_0)= \lim\limits_{\vartriangle x \to 0} \frac { f(x_0+\vartriangle x)-f(x_0) }{\vartriangle x}
f′(x0)=△x→0lim△xf(x0+△x)−f(x0)
导数经过上图可以进一步理解,斜率 a 被称为 f 在 p 点的导数(derivative)。如果 a 是负的,说明 x 在 p 点附近的微小变
化将导致 f(x) 减小(如图 2-10 所示);如果 a 是正的,那么 x 的微小变化将导致 f(x) 增大。
此外,a 的绝对值(导数大小)表示增大或减小的速度快慢.
理解了导数就可以去求损失函数的最小值了,如果知道损失函数的导数,就知道了改变 x 后 f(x) 会如何变化,(如上图,斜率为正,要减小f则要将x减小;斜率为负,要减小f则要将x增大),总结得出希望减小 f(x) 的值,只需将 x 沿着导数的反方向移动一小步。
反向传播算法
由前言得知要使得损失函数减小,可以通过导数去改变x值来减小.因此我们需要损失函数要可导,可以通过迭代的方式不断减小.其传播的流程如下
- 初始化参数,输入经过网络计算得到输出
- 根据损失函数f(x)计算得到当前损失值,与损失函数在参数(w,b)下的导数也称为梯度
- 根据求取的梯度更新参数,然后重复该流程直到损失函数足够小.
上面的流程咋看比较简单,但是我们的网络可能是比较复杂的,有多层的,此时要如何求梯度呢。
例如,下面这个网络 f 包含 3 个张量运算 a、b 和 c,还有 3 个权重矩阵 W1、W2 和 W3。
f
(
W
1
,
W
2
,
W
3
)
=
a
(
W
1
,
b
(
W
2
,
c
(
W
3
)
)
)
f(W1, W2, W3) = a(W1, b(W2, c(W3)))
f(W1,W2,W3)=a(W1,b(W2,c(W3)))
此时采用导数的链式法则可以求得导数
(
f
(
g
(
x
)
)
)
′
=
f
′
(
g
(
x
)
)
∗
g
′
(
x
)
(f(g(x)))' = f'(g(x)) * g'(x)
(f(g(x)))′=f′(g(x))∗g′(x)
根据上面的流程可以看到每一步都有一些可能影响算法效果的存在,接下来进行详细分析
- 参数初始化的重要性,不同的初始化其开始的起点不一样,若初始化时就在最优点附近,则只需迭代很少的次数就可以达到目标了.
- 当停止迭代时,此时可能达到的是局部极小值,其梯度已接近0,再进行迭代也无法跳出该位置.
- 在更新参数时,我们会引入一个学习率,以加大参数的变化幅度,这个学习率设置过小前期迭代时间花费过长,;学习率设置过大又可能使得幅度过大,跨过了最优点,在最优点附近来回震荡.
- 我们知道当网络变深时,根据链式法则其导数进行了叠乘,当导数比较接近0时,叠乘后梯度接近消失;同理当导数大于1时,叠乘后梯度呈指数上涨.前者使得我们无法获得最优的模型,后者使得我们的参数更新变动过大,无法收敛,
后续针对上面四点提出了很多优化方法,可以后续进一步熟悉.