什么是梯度下降?
梯度是一个向量,学习的前进方向(变化最快的方向),简单理解就是一个导数,只不过这个导数对于二维的、一元的情况来讲它就是导数,对于多元的这样一个函数来讲的话,我们对其中一个自变量x进行求导之后,我们把它称之为偏导导数和偏导梯度的一部分,除了这个数值之外呢它还有一个方向在里面。
回顾机器学习
收集数据 x x x ,构建机器学习模型 f f f,得到 f ( x , w ) = Y p r e d i c t f(x,w) = Y_{predict} f(x,w)=Ypredict
判断模型好坏的方法:
l
o
s
s
=
(
Y
p
r
e
d
i
c
t
−
Y
t
r
u
e
)
2
(
回归损失
)
l
o
s
s
=
Y
t
r
u
e
⋅
l
o
g
(
Y
p
r
e
d
i
c
t
)
(
分类损失
)
\begin{align*} loss & = (Y_{predict}-Y_{true})^2 &(回归损失) \\ loss & = Y_{true} \cdot log(Y_{predict}) &(分类损失) \end{align*}
lossloss=(Ypredict−Ytrue)2=Ytrue⋅log(Ypredict)(回归损失)(分类损失)
目标:通过调整(学习)参数
w
w
w,尽可能的降低
l
o
s
s
loss
loss,那么我们该如何调整
w
w
w呢?
随机选择一个起始点
w
0
w_0
w0,通过调整
w
0
w_0
w0,让loss函数(损失函数)取到最小值
w w w的更新方法:
- 计算 w w w的梯度(导数)
∇ w = f ( w + 0.000001 ) − f ( w − 0.000001 ) 2 ∗ 0.000001 \nabla w = \frac{f(w+0.000001)-f(w-0.000001)}{2*0.000001} ∇w=2∗0.000001f(w+0.000001)−f(w−0.000001)
- 更新
w
w
w
w = w − α ∇ w w = w - \alpha \nabla w w=w−α∇w
其中:
∇
w
<
0
\nabla w <0
∇w<0 ,意味着w将增大
∇
w
>
0
\nabla w >0
∇w>0 ,意味着w将减小
总结:梯度就是多元函数参数的变化趋势(参数学习的方向),只有一个自变量时称为导数
偏导的计算
已知 J ( a , b , c ) = 3 ( a + b c ) , 令 u = a + v , v = b c J(a,b,c) = 3(a+bc),令u=a+v,v = bc J(a,b,c)=3(a+bc),令u=a+v,v=bc,求a,b,c各自的偏导数。
公式
令 : J ( a , b , c ) = 3 u d J d a = d J d u × d u d a = 3 × 1 d J d b = d J d u × d u d v × d v d b = 3 × 1 × c d J d c = d J d u × d u d v × d v d c = 3 × 1 × b \begin{align*} 令:& J(a,b,c) = 3u\\ \frac{dJ}{da} &=\frac{dJ}{du} \times \frac{du}{da} = 3\times1 \\ \frac{dJ}{db} &=\frac{dJ}{du} \times \frac{du}{dv} \times \frac{dv}{db} = 3\times1\times c \\ \frac{dJ}{dc} &=\frac{dJ}{du} \times \frac{du}{dv} \times \frac{dv}{dc} = 3\times1\times b \\\end{align*} 令:dadJdbdJdcdJJ(a,b,c)=3u=dudJ×dadu=3×1=dudJ×dvdu×dbdv=3×1×c=dudJ×dvdu×dcdv=3×1×b
反向传播算法
计算图和反向传播
计算图:通过图的方式来描述函数的图形
在上面的练习中, J ( a , b , c ) = 3 ( a + b c ) , 令 u = a + v , v = b c J(a,b,c) = 3(a+bc),令u=a+v,v = bc J(a,b,c)=3(a+bc),令u=a+v,v=bc,把它绘制成计算图可以表示为:
绘制成为计算图之后,可以清楚的看到向前计算的过程
之后,对每个节点求偏导可有:
那么反向传播的过程就是一个上图的从右往左
的过程,自变量
a
,
b
,
c
a,b,c
a,b,c各自的偏导就是连线上的梯度的乘积:
d
J
d
a
=
3
×
1
d
J
d
b
=
3
×
1
×
c
d
J
d
c
=
3
×
1
×
b
\begin{align*} \frac{dJ}{da} &= 3 \times 1 \\ \frac{dJ}{db} &= 3 \times 1 \times c \\ \frac{dJ}{dc} &= 3 \times 1 \times b \end{align*}
dadJdbdJdcdJ=3×1=3×1×c=3×1×b
神经网络中的反向传播
神经网络的示意图
w 1 , w 2 , . . . . w n w1,w2,....wn w1,w2,....wn表示网络第n层权重
w n [ i , j ] w_n[i,j] wn[i,j]表示第n层第i个神经元,连接到第n+1层第j个神经元的权重。
神经网络的计算图
其中:
- ∇ o u t \nabla out ∇out是根据损失函数对预测值进行求导得到的结果
- f函数可以理解为激活函数
为了我们能够快速的计算出从out,假设我们已经有了这样一个损失函数f之后,为了这个损失函数,这个out就是我们损失函数的某一次传入一个数据之后的一个结果,这个结果我妈想通过它这个函数求出来这个 w 1 [ 1 , 1 ] w_1[1,1] w1[1,1] 它的这个梯度,那这个时候呢我妈可以跟之前一样,我们可以把这条线上面的所有的梯度都给它计算出来,计算出来之后连线相乘就够了。
问题: 那么此时 w 1 [ 1 , 2 ] w_1[1,2] w1[1,2]的偏导该如何求解呢?
通过观察,发现从 o u t out out 到 w 1 [ 1 , 2 ] w_1[1,2] w1[1,2]的来连接线有两条
结果如下:
d
o
u
t
d
W
1
[
1
,
2
]
=
x
1
∗
f
′
(
a
2
)
∗
(
W
2
[
2
,
1
]
∗
f
′
(
b
1
)
∗
W
3
[
1
,
1
]
∗
∇
o
u
t
+
W
2
[
2
,
2
]
∗
f
′
(
b
2
)
∗
W
3
[
2
,
1
]
∗
∇
o
u
t
)
\frac{dout}{dW_1[1,2]} = x1*f^{'}(a2)*(W_2[2,1]*f^{'}(b1)*W_3[1,1]*\nabla out +W_2[2,2]*f^{'}(b2)*W_3[2,1]*\nabla out)
dW1[1,2]dout=x1∗f′(a2)∗(W2[2,1]∗f′(b1)∗W3[1,1]∗∇out+W2[2,2]∗f′(b2)∗W3[2,1]∗∇out)
公式分为两部分:
- 括号外:左边红线部分
- 括号内
- 加号左边:右边红线部分
- 加号右边:蓝线部分
但是这样做,当模型很大的时候,计算量非常大
所以反向传播的思想就是对其中的某一个参数单独求梯度(一层一层计算),之后更新,如下图所示:
计算过程如下
W 3 [ 1 , 1 ] 的偏导: ∇ W 3 [ 1 , 1 ] = f ( b 1 ) ∗ ∇ o u t (计算 W 3 [ 1 , 1 ] 梯度) ∇ W 3 [ 2 , 1 ] = f ( b 2 ) ∗ ∇ o u t (计算 W 3 [ 2 , 1 ] 梯度) ∇ b 1 = f ′ ( b 1 ) ∗ W 3 [ 1 , 1 ] ∗ ∇ o u t (计算 W 3 [ 2 , 1 ] 梯度) ∇ b 2 = f ′ ( b 2 ) ∗ W 3 [ 2 , 1 ] ∗ ∇ o u t (计算 W 3 [ 2 , 1 ] 梯度) \begin{align*} W_3[1,1]的偏导:&\nabla W_3[1,1] = f(b_1)*\nabla out & (计算W_3[1,1]梯度)\\ &\nabla W_3[2,1] = f(b_2)*\nabla out & (计算W_3[2,1]梯度)\\ \\ &\nabla b_1= f^{'}(b_1)*W_3[1,1]*\nabla out & (计算W_3[2,1]梯度)\\ &\nabla b_2= f^{'}(b_2)*W_3[2,1]*\nabla out & (计算W_3[2,1]梯度)\\ \end{align*} W3[1,1]的偏导:∇W3[1,1]=f(b1)∗∇out∇W3[2,1]=f(b2)∗∇out∇b1=f′(b1)∗W3[1,1]∗∇out∇b2=f′(b2)∗W3[2,1]∗∇out(计算W3[1,1]梯度)(计算W3[2,1]梯度)(计算W3[2,1]梯度)(计算W3[2,1]梯度)
更新参数之后,继续反向传播
计算过程如下:
∇
W
2
[
1
,
2
]
=
f
(
a
1
)
∗
∇
b
2
∇
a
2
=
f
′
(
a
2
)
∗
(
w
2
[
2
,
1
]
∇
b
1
+
W
2
[
2
,
2
]
∇
b
2
)
\begin{align*} &\nabla W_2[1,2] = f(a_1)* \nabla b_2 \\ &\nabla a_2 = f^{'}(a_2)*(w_2[2,1]\nabla b_1 +W_2[2,2] \nabla b_2) \end{align*}
∇W2[1,2]=f(a1)∗∇b2∇a2=f′(a2)∗(w2[2,1]∇b1+W2[2,2]∇b2)
继续反向传播
它是一层一层往后计算的,它不会从根就开始一样一次性全部都算出来, 一次性算会有很多很多计算你要保存在一个位置,保存很多变量去保存, 你这个时候你要占用很多内存空间, 去保存那些不停的一串的加一串的乘, 或者说有很多很多串加上乘都要保存下来, 这样的话你需要占用额外的很多的空间,但是你这样一层一层算的时候,你就不需要这样很多的空间, 你只是当前这次的这些变量更新完就完事, 把这一层的结果才能拿到下一层去,最后进行计算。
计算过程如下:
▽
W
1
[
1
,
2
]
=
x
1
∗
▽
a
2
▽
x
1
=
(
W
1
[
1
,
1
]
∗
▽
a
1
+
w
1
[
1
,
2
]
∗
▽
a
2
)
∗
x
1
’
\begin{align*} &▽W_1[1,2]= x_1*▽a_2\\ &▽x_1= (W_1[1,1]*▽a_1+w_1[1,2]*▽a_2)*x_1’ \end{align*}
▽W1[1,2]=x1∗▽a2▽x1=(W1[1,1]∗▽a1+w1[1,2]∗▽a2)∗x1’
通用的描述如下
∇
w
i
,
j
l
=
f
(
a
i
l
)
∗
∇
a
j
i
+
1
∇
a
i
l
=
f
′
(
a
i
l
)
∗
(
∑
j
=
1
m
w
i
,
j
∗
∇
a
j
l
+
1
)
\nabla w^{l}_{i,j} = f(a^l_i)* \nabla a^{i+1}_{j}\\ \nabla a^{l}_i = f'(a^l_i)*(\sum_{j=1}^{m}w_{i,j}*\nabla a_j^{l+1})
∇wi,jl=f(ail)∗∇aji+1∇ail=f′(ail)∗(j=1∑mwi,j∗∇ajl+1)