本文主要讲解梯度下降的数学推导,并假定读者已经了解梯度下降的思想,不适合没有任何基础的同学
推荐博客 梯度下降
了解上述推荐博客后,我们来推导一下最简单的梯度下降方法
很明显,梯度下降主要用于解决无约束的最优化问题,我们以最小化损失函数为例
θ
∗
=
arg
min
θ
L
(
θ
)
\theta^* = \mathop{\arg \min_{\theta}L(\theta)}
θ∗=argθminL(θ)
首先我们画出损失函数
L
(
θ
)
L(\theta)
L(θ)的等高线(这里是用两个自变量为例的
θ
1
,
θ
2
\theta_1,\theta_2
θ1,θ2)
我们最终的目标就是求出
θ
∗
\theta^*
θ∗使得
L
(
θ
)
L(\theta)
L(θ)最小。
首先,我们随机的取一个点,假定为 ( θ 1 ′ , θ 2 ′ ) (\theta_1^{'},\theta_2^{'}) (θ1′,θ2′),接下来我们需要确定下一步我们要向哪边走。
此点的损失函数为(泰勒计数,仅仅展开到一阶)
L
(
θ
)
=
L
(
θ
1
′
,
θ
2
′
)
+
∂
L
(
θ
1
′
,
θ
2
′
)
∂
θ
1
(
θ
1
−
θ
1
′
)
+
∂
L
(
θ
1
′
,
θ
2
′
)
∂
θ
2
(
θ
2
−
θ
2
′
)
L(\theta) = L(\theta_1^{'},\theta_2^{'})+\frac{\partial L(\theta_1^{'},\theta_2^{'}) }{\partial \theta_1}(\theta_1 - \theta_1^{'}) + \frac{\partial L(\theta_1^{'},\theta_2^{'})}{\partial \theta_2}(\theta_2 - \theta_2^{'})
L(θ)=L(θ1′,θ2′)+∂θ1∂L(θ1′,θ2′)(θ1−θ1′)+∂θ2∂L(θ1′,θ2′)(θ2−θ2′)
首先明确目标是为了使得
L
(
θ
)
L(\theta)
L(θ)最小,又因为
L
(
θ
1
′
,
θ
2
′
)
L(\theta_1^{'},\theta_2^{'})
L(θ1′,θ2′),
∂
L
(
θ
1
′
,
θ
2
′
)
∂
θ
1
\frac{\partial L(\theta_1^{'},\theta_2^{'})}{\partial \theta_1}
∂θ1∂L(θ1′,θ2′),
∂
L
(
θ
1
′
,
θ
2
′
)
∂
θ
2
\frac{\partial L(\theta_1^{'},\theta_2^{'})}{\partial \theta_2}
∂θ2∂L(θ1′,θ2′)都是常数,所以只能让
∂
L
(
θ
1
′
,
θ
2
′
)
∂
θ
1
(
θ
1
−
θ
1
′
)
+
∂
L
(
θ
1
′
,
θ
2
′
)
∂
θ
2
(
θ
2
−
θ
2
′
)
\frac{\partial L(\theta_1^{'},\theta_2^{'}) }{\partial \theta_1}(\theta_1 - \theta_1^{'}) + \frac{\partial L(\theta_1^{'},\theta_2^{'})}{\partial \theta_2}(\theta_2 - \theta_2^{'})
∂θ1∂L(θ1′,θ2′)(θ1−θ1′)+∂θ2∂L(θ1′,θ2′)(θ2−θ2′)取得最小值,首先我们在图中画出两个偏导数的向量(即
∂
L
(
θ
1
′
,
θ
2
′
)
∂
θ
1
\frac{\partial L(\theta_1^{'},\theta_2^{'})}{\partial \theta_1}
∂θ1∂L(θ1′,θ2′),
∂
L
(
θ
1
′
,
θ
2
′
)
∂
θ
2
\frac{\partial L(\theta_1^{'},\theta_2^{'})}{\partial \theta_2}
∂θ2∂L(θ1′,θ2′)),由于本文以二维表示,故尚可在平面中画出,如果自变量维数增多,便很难进行可视化。
图中
△
θ
1
=
θ
1
−
θ
1
′
\triangle \theta_1 =\theta_1 - \theta_1^{'}
△θ1=θ1−θ1′,
△
θ
2
=
θ
2
−
θ
2
′
\triangle \theta_2 =\theta_2 - \theta_2^{'}
△θ2=θ2−θ2′,
u
=
∂
L
(
θ
1
′
,
θ
2
′
)
∂
θ
1
u = \frac{\partial L(\theta_1^{'},\theta_2^{'})}{\partial \theta_1}
u=∂θ1∂L(θ1′,θ2′),
v
=
∂
L
(
θ
1
′
,
θ
2
′
)
∂
θ
2
v = \frac{\partial L(\theta_1^{'},\theta_2^{'})}{\partial \theta_2}
v=∂θ2∂L(θ1′,θ2′)
由上图可以很明显的看出,只有 ( △ θ 1 , △ θ 2 ) (\triangle \theta_1 ,\triangle \theta_2) (△θ1,△θ2)与 ( u , v ) (u,v) (u,v)反向而且取得最长时,使得 L ( θ ) L(\theta) L(θ)最小。即为 − η ( u , v ) T - \eta (u,v)^T −η(u,v)T
由于
L
(
θ
)
L(\theta)
L(θ)的近似公式是由泰勒级数展开获得的,所以一定要要满足
(
θ
1
−
θ
1
′
)
⟶
0
(\theta_1 - \theta_1^{'})\longrightarrow 0
(θ1−θ1′)⟶0,
(
θ
2
−
θ
2
′
)
⟶
0
(\theta_2 - \theta_2^{'})\longrightarrow 0
(θ2−θ2′)⟶0。
由此可以得出约束条件
(
θ
1
−
θ
1
′
)
2
+
(
θ
2
−
θ
2
′
)
2
≤
d
2
(\theta_1 - \theta_1^{'}) ^2+(\theta_2 - \theta_2^{'}) ^2 \le d^2
(θ1−θ1′)2+(θ2−θ2′)2≤d2
其中
d
⟶
0
d \longrightarrow 0
d⟶0
到此我们可以得出如果要让 L ( θ ) L(\theta) L(θ)最小,此时 θ 1 \theta_1 θ1, θ 2 \theta_2 θ2 需要满足的条件为
( θ 1 , θ 2 ) T = ( θ 1 ′ , θ 2 ′ ) T − η ( u , v ) T (\theta_1, \theta_2)^T = (\theta_1^{'}, \theta_2^{'})^T- \eta (u,v)^T (θ1,θ2)T=(θ1′,θ2′)T−η(u,v)T
即为本文第二个图,从一个圈,尽最大可能向最小点迈进,从而开始下一圈的迈进。
这就是我们套用的梯度下降的公式,经过公式推导可以看出由于受到泰勒级数条件的限制,其中的 η \eta η 应该是趋近于0的,这样才能保证寻找局部最优值。但是在实际的训练过程中, η \eta η的值可以认为进行设定,这样也就能解释为何在 η \eta η过大的时候,会使得损失函数 L ( θ ) L(\theta) L(θ) 增大。
下面用python 写一下梯度下降
本文以
f
(
x
)
=
b
+
w
x
f(x) = b+wx
f(x)=b+wx 为例
其损失函数为
L
(
w
,
b
)
=
(
y
i
−
f
(
x
i
)
)
2
L(w,b) = (y_i - f(x_i))^2
L(w,b)=(yi−f(xi))2
偏导数为
∂
L
∂
w
=
2
∗
(
y
i
−
f
(
x
i
)
)
∗
x
i
\frac{\partial L}{\partial w} = 2*(y_i - f(x_i))*x_i
∂w∂L=2∗(yi−f(xi))∗xi
∂
L
∂
b
=
2
∗
(
y
i
−
f
(
x
i
)
)
∗
1
\frac{\partial L}{\partial b} = 2*(y_i - f(x_i))*1
∂b∂L=2∗(yi−f(xi))∗1
由梯度公式得
b
=
b
−
l
e
a
r
n
_
r
a
t
i
o
×
∂
L
∂
b
b = b - learn\_ratio \times \frac{\partial L}{\partial b}
b=b−learn_ratio×∂b∂L
w
=
w
−
l
e
a
r
n
_
r
a
t
i
o
×
∂
L
∂
w
w = w - learn\_ratio \times \frac{\partial L}{\partial w}
w=w−learn_ratio×∂w∂L
每次更新去平均值作为更新值
# Gradient Decesent
# @author Hongchuan CAO
import numpy as np
import matplotlib.pyplot as plt
class SGD:
def __init__(self):
# self.x_data = [338., 333., 328., 207., 226., 25., 179., 60., 208., 606.]
# self.y_data = [640., 633., 619., 393., 428., 27., 193., 66., 226., 1591]
self.x_data = [100, 80, 120, 75, 60, 43, 140, 132, 63, 55, 74, 44, 88]
self.y_data = [120, 92, 143, 87, 60, 50, 167, 147, 80, 60, 90, 57, 99]
def regression(self):
self.b = 10
self.w = 1
iteration = 100000 # 迭代次数
ratio = 0.00001 #学习率
for i in range(iteration):
w_ratio = 0
b_ratio = 0
for j in range(len(self.x_data)):
w_ratio = w_ratio + 2*(self.b+self.w*self.x_data[j]-self.y_data[j])*self.x_data[j]
b_ratio = b_ratio + 2*(self.b+self.w*self.x_data[j]-self.y_data[j])*1
#将样例数据取平均
self.w = self.w - ratio* w_ratio /len(self.x_data)
self.b = self.b - ratio* b_ratio /len(self.x_data)
#print(str(i)+" "+str(self.w) + " " + str(self.b))
def plot1(self):
#离散数据点
plt.scatter(self.x_data,self.y_data)
xx = [x for x in np.arange(0,max(self.x_data),1)]
yy = []
for i in range(len(xx)):
yy.append(self.w*xx[i]+self.b)
# 回归
plt.plot(xx,yy,'b-')
plt.show()
if __name__ == '__main__':
obj = SGD()
obj.regression()
obj.plot1()
结果: