梯度下降算法
1.1 什么是梯度下降
在线性回归中,我们使用最小二乘法,能够直接计算损失函数最小值时的参数值,但是,最小二乘法有使用的限制条件,在大多数机器学习的使用场景之下,我们会选择梯度下降的方法来计算损失函数的极小值,首先梯度下降算法的目标仍然是求最小值,但和最小二乘法这种一步到位、通过解方程组直接求得最小值的方式不同,梯度下降是通过一种“迭代求解”的方式来进行最小值的求解,其整体求解过程可以粗略描述为,先随机选取一组参数初始值,然后沿着某个方向,一步一步移动到极小值点
梯度下降法的基本思想可以类比为一个下山的过程:
一个人 被困在山上,需要从山上下来 (i.e. 找到山的最低点,也就是山谷)。但此时山上的浓雾很大,导致可视度很低。因此,下山的路径就无法确定,他必须利用自己周围的信息去找到下山的路径。这个时候,他就可以利用梯度下降算法来帮助自己下山。以他当前的所处的位置为基准,寻找这个位置最陡峭的地方,然后朝着山的高度下降的地方走
首先,我们有一个 可微分的函数 。这个函数就代表着一座山。我们的目标就是找到 这个函数的最小值 ,也就是山底。根据之前的场景假设,最快的下山的方式就是找到当前位置最陡峭的方向,然后沿着此方向向下走,对应到函数中,就是 找到给定点的梯度 ,然后朝着梯度相反的方向,就能让函数值下降的最快。
1.2 梯度的概念
- 在单变量的函数中,梯度就是函数的微分,代表着函数在某个给定点的切线的斜率;
- 在多变量函数中,梯度是一个向量,向量有方向,梯度的方向就指出了函数在给定点的上升最快的方向;
- 在微积分里面,对多元函数的参数求∂偏导数,把求得的各个参数的偏导数以向量的形式写出来,就是梯度。
向量求导的梯度向量形式 :
在给定具体的参数一组取值之后,我们就能计算梯度表达式的取值,该值也被称为损失函数在某组参数取值下的梯度
当前的函数是一元函数,我们只需要计算导数即可算出梯度值
当前的函数是一元函数,我们只需要计算导数即可算出梯度值
我们可以设置学习率为lr=0.01,则从x0进行移动的距离是0.01∗11.25=0.1125,而又是朝向梯度的负方向进行移动,因此x0最终移动到了X1=0.5+0.1125=0.6125
1.3代码实现
def gradient_descent(df, x, alpha=0.01, iterations=100, epsilon=1e-8): history = [x] for i in range(iterations): if abs(df(x)) < epsilon: print("梯度足够小") break x = x - alpha * df(x) history.append(x) return history
- df: 目标函数的导数(gradient)。在优化过程中,梯度下降法沿着函数下降最快的方向更新变量x
- x: 初始化的起点或当前点,表示我们开始搜索最小值的位置
- alpha: 学习率(learning rate),它决定了每次迭代时x的更新步长。较大的alpha可能导致更快的收敛,但也可能使算法错过最小值;较小的alpha可能导致更慢的收敛速度,但结果可能更精确
- iterations: 最大迭代次数
- epsilon: 极小值,用于判断梯度是否足够小
- history: 用于存储每次迭代后的x值,用来绘制优化过程或者检查收敛性
import numpy as np x = np.linspace(0,6,1000) y = np.power(x,3) - 3*np.power(x,2)-9*x +2 yf = lambda x: np.power(x,3) - 3*np.power(x,2)-9*x +2 y_d = lambda x: 3*np.power(x,2) - 6*x -9 path = gradient_descent(y_d, 1,0.01, 100) path[-1]
- 结果为2.9999876804184145,path中的最后一个值已经很接近于这个函数在【0,6】中最小值坐标点的X值。
path = gradient_descent(y_d, 0.5,0.01, 200) path[-1]
可以发现迭代200次后,就触发了停止迭代的条件,说明迭代次数以及足够多而且梯度值以及不足以继续下降了。
我们还可以将迭代过程进行可视化展示:
path_x = np.array(path) path_y = yf(path_x) plt.plot(x, y) plt.scatter(x[y.argmin()],y[y.argmin()]) plt.text(0.5,yf(0.5),"start") plt.quiver(path_x[:-1], path_y[:-1], path_x[1:]-path_x[:-1],path_y[1:]-path_y[:-1], scale_units='xy',angles="xy",scale=1) plt.show()
- argmin()与argmax()方法是一种,argmin()是找到当前序列的最小值的索引,方法的参数axis是指沿着某个轴运算。
- plt.scatter(x[y.argmin()],y[y.argmin()])就是找到函数的全局最小值。
有了梯度计算公式之后,我们可以使用gradient_descent方法进行迭代计算,计算出x_0的值
loss_prime = lambda x:(np.power(x,2)-2)*x path = gradient_descent(loss_prime, 1, 0.01,500) path[-1]
输出1.414213559949299,最小值为1.4142135623730951
先读取并展示数据点:
import matplotlib.pyplot as plt plt.scatter(data[:,0],data[:,1]) plt.show()
def linear_regression_gd_iteration(X, y, w, alpha=0.01, iterations=100, epsilon=1e-9): history = [w] for i in range(iterations): gd = linearRegression_gd(X, y, w) if np.max(np.abs(gd)< epsilon): print("梯度过小") break w = w - alpha * gd history.append(w) return history lr = 0.001 iterations = 10000 w0 = np.array([-7.5,-7.5]).reshape(-1,1) path = linear_regression_gd_iteration(X, y , w0,lr,iterations) path[-1] def draw_line(X,y,w,lineWidth=2): plt.scatter(X[:,0],y) yhat = X @ w plt.plot(X[:,0],yhat,'r-',linewidth=lineWidth) plt.show() draw_line(X, y, path[-1])
梯度下降算法(二)+https://developer.aliyun.com/article/1544681?spm=a2c6h.13148508.setting.27.2a1e4f0euIPhgb