Gradient Descent介绍

他不是一个机器学习算法,而是一种基于搜索的最优化方法,是用来最小化一个损失函数,与之相反,梯度上升法是用来最大化一个效用函数的。他俩都是用来最优化目标函数的。在多元线性回归中我们可以用正规方程解,但是很多机器学习的模型是求不到数学解的,所以需要梯度下降法。

下面的平面图表示theta向量中只有一个系数(只有一个特征),即简单线性回归的梯度下降法可视化,每取一个该特征的系数的数值,会得到的损失函数J的不同值。
image.png
我们要找到J的最小值,只有当theta所在的点导数为0时,此时该点上这个曲线方程切线的斜率为0,所以这个点在极值点上,就有可能是一个最小值。因为不是所有的函数都有唯一的极值点(导数为0),他可能是当前范围内的局部最优解,所以需要随机化初始点,这个初始点是一个超参数。image.png,不过线性回归法里的损失函数都具有唯一最优解,因为函数都是规则的,比如上图表示的一元线性回归可视化。

在上图中,导数代表theta单位变化时,J相应的变化,列如theta向左或向右移动都会带来J的变化,或增大或减小。上图的切线斜率为负值,也就是导数为负,theta增加时J减少,theta减小时J增加,说明导数可以代表方向,对应J增大的方向,上图导数为负,所以J增大的方向是X轴的负方向.

对应在上图中,无论随机下降点出现在中轴的左边还是右边
theta值的方程都是theta +(- eta(dJ/dtheta))
左边的时候斜率为负数,J增大的方向为x轴负方向,所以用-eta表示J减小的方向;右边的时候斜率是正数,J增大的方向为x轴的正反向,所以还是用-eta表示J减小方向。

梯度下降法 - 图4(eta)是什么

梯度下降法 - 图5称为学习率(learning rate)
梯度下降法 - 图6的取值影响获得最优解的速度,也就是收敛的速度
收敛就是到达梯度最低点的过程
梯度下降法 - 图7取值不合适,甚至得不到最优解
image.pngimage.png
梯度下降法 - 图10是梯度下降法的一个超参数

简单线性回归梯度下降法实现

  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. plot_x = np.linspace(-1, 6, 141) # 加上-1,6一共141个点
  4. plot_y = (plot_x - 2.5)**2-1
  5. plt.plot(plot_x, plot_y) # 绘制二次曲线
  6. plt.show()
  7. def dJ(theta): # 计算当前theta值下损失函数对应的导数
  8. return 2*(theta-2.5)
  9. def J(theta):
  10. try:
  11. return (theta-2.5)**2-1
  12. """ 防止学习率过大导致theta无限增大,导致J大到计算机无法计算"""
  13. except:
  14. return float('inf')
  15. eta = 0.4
  16. epsilon = 1e-8 # epsilon小的正数
  17. theta = 0.0
  18. theta_history = [theta]
  19. while True:
  20. gradient = dJ(theta)
  21. last_theta = theta
  22. theta = theta - eta * gradient
  23. theta_history.append(theta)
  24. if(abs(J(theta) - J(last_theta))) < epsilon:
  25. break
  26. print(theta)
  27. print(J(theta))
  28. print(theta_history)
  29. plt.plot(plot_x, J(plot_x))
  30. plt.plot(np.array(theta_history), J(np.array(theta_history)), color='r',marker='+')
  31. plt.show()

image.png
为什么下降的长度越来越小?应为虽然eta不变,但是梯度变得越来越小。所以theta向前进的步长也越来越小。导致theta取值上对应的J也下降的慢了。

学习率的设置

当学习率设置成0.8时,
当学习率设置成1.1时,
因为新theta的位置超过了比原来theta的对称轴的点位,导致梯度变得更大了,所以下一次theta的位置梯度更加大,越升越高。

skleran实现随机梯度下降法

  1. from operator import ipow
  2. from sklearn.datasets import load_boston
  3. from sklearn.model_selection import train_test_split
  4. from sklearn.preprocessing import StandardScaler
  5. from sklearn.linear_model import SGDRegressor
  6. boston = load_boston()
  7. X = boston.data
  8. y= boston.target
  9. X = X[y < 50.0]
  10. y = y[y < 50.0]
  11. X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
  12. standardScaler = StandardScaler()
  13. standardScaler.fix(X_train)
  14. X_train_standard = standardScaler.transform(X_train)
  15. X_test_standard = standardScaler.transform(X_test)
  16. sgd_reg = SGDRegressor(n_iter=5)
  17. sgd_reg.fit(X_train_standard,y_train)
  18. sgd_reg.score(X_test_standard,y_test)