1.梯度下降图形解释
上一篇已经介绍了代价函数J(θ0,θ1),我们的目的是要求出使代价函数最小的θ0、θ1,那么我们先从三维图像来描述一下梯度下降怎样寻找代价函数的最小值。
这里就是一个J(θ0,θ1)的图像,要找J的最小值,这里假设图像是一座一座山峰,我们就从任意一个点出发,先假设 θ0=0,θ1=0,取得J的值在红色的山上,这时假如我们要快速下山,我们就环顾四周寻找下降最快的方向,向下走一小步,得到了新的θ0,θ1,这时我们又重新环顾四周找下一个下降最快的方向,以此类推,我们就到了山底,此时的θ0,θ1就是我们想要的,我们得到了一个局部最优解。
当然如果我们最初选的点不是θ0=0,θ1=0的点,假如刚开始的点靠右一点,重复上述步骤,梯度下降就将带领我们到另一个山底,就有了另一个与之前完全不一样的局部最优解。如下图所示:
这就是梯度下降的特点,后面我们会讨论这个问题。
2.梯度下降的数学解释
这里强调一点θ0,θ1是同时更新的,temp0和temp1所求的偏导都是上一次的θ0和θ1。ɑ 为学习速率,他控制我们以多大的速率来更新参数。
下面讨论仅有θ1的情况,即代价函数为J(θ1),此时的temp1如下:
这时的temp1中求导部分就是求得斜率,假设θ1在右边,斜率为正,那么下一次的θ1就是减去ɑ斜率,得到的θ1变小,逐渐向左;反之当θ1在左边,斜率为负,那么下一次的θ1就是减去ɑ\斜率(<0),得到的θ1变大,逐渐向右。
下面讨论ɑ的取值大小对梯度下降的影响
当ɑ较小时,则J(θ1)向最小值移动的速度会比较慢,但最终会到达最小值点,只是下降速率很慢。
当ɑ较大时,每走一步太大,可能永远都不能到达最小值点,甚至越离越远,最后无法收敛甚至发散。
如果此时已经是最低点了,那么此时的斜率就为0,他就不会继续下降,所得的就是我们要找的θ1。
当θ1所对应的变化率较大时,θ1下降的幅值就越大,反之当θ1对应的变化率较小时,θ1下降的幅值就越小,所以梯度下降是自动改变J(θ1)的变化速度的,即我们不需要实时改变ɑ。
3.梯度下降的最终表示总结
下面将J(θ0,θ1)带入到梯度下降的公式里面:
即:
4.用python实现线性回归的梯度下降(“Batch” Gradient Descent)
线性回归的问题可以用到梯度下降,只要每一次的θ0,θ1按照上面的公式进行,就可以实现直线拟合,下面作者使用了python中的matplotlib来进行可视化,更清楚的了解梯度下降的线性回归。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53import matplotlib.pyplot as plt
x_train = [100,80,120,75,60,43,140,132,63,55,74,44,88] #数据集
y_train = [120,92,143,87,60,50,167,147,80,60,90,57,99]
alpha = 0.00001 #a步长
m = len(x_train) #数据集长度
def h(x,theta_list):
"""假设函数,传入参数为x,和theta_list列表,[theta0,theta1],返回h(x)的值"""
return theta_list[1]*x + theta_list[0]
def Get_theta(theta_list):
"""求下一次的θ0和θ1,返回他们的列表,传入的是上一次的θ0和θ1"""
theta0_sum = 0
theta1_sum = 0
for i in range(m):
theta0_sum+=(h(x_train[i],theta_l·ist)-y_train[i])
theta1_sum+=(h(x_train[i],theta_list)-y_train[i])*x_train[i]
theta1=theta_list[1]-alpha/m*theta1_sum
theta0=theta_list[0]-alpha/m*theta0_sum
return [theta0,theta1]
def J(theta_list):
"""代价函数"""
result = 0
for i in range(m):
result += ((y_train[i] - (theta_list[0] + theta_list[1] * x_train[i])) ** 2) /2/m
return result
def main():
result_last=0
result=0
plt.plot(x_train,y_train,'go') #画数据集
n = 0 #更新次数
theta_list = [0,0]
while True:
theta_list = Get_theta(theta_list)
result = J(theta_list)
print(abs(result - result_last)) #输出前后两次的幅值差值
if n % 5 == 0:
plt.plot(x_train,[h(x,theta_list) for x in x_train],'blue') #每隔5次画一条拟合的蓝线
n = n + 1
if abs(result - result_last) < 0.00001: #判断前后两次的幅值是否小于0.00001,表示达到最优解
break
else:
result_last = result
print(n)
plt.plot(x_train,[h(x, theta_list) for x in x_train],'red') #画出最终的拟合出来的结果
plt.show()
if __name__ == '__main__':
main()经过拟合之后画出的图像如下:,蓝色是每隔5次梯度下降的结果,最后的红色线是最终拟合出来的,发现拟合结果较好。
输出的结果如下:
1 | 4504.186913638355 |
- 可以发现前面的下降速率比较快,越向后下降速率越慢,最终θ0,θ1改变了114次得到了最优解,完美拟合直线,与之前的理论相对应。