梯度下降算法

梯度下降算法

1.1 什么是梯度下降

​ 在线性回归中,我们使用最小二乘法,能够直接计算损失函数最小值时的参数值,但是,最小二乘法有使用的限制条件,在大多数机器学习的使用场景之下,我们会选择梯度下降的方法来计算损失函数的极小值,首先梯度下降算法的目标仍然是求最小值,但和最小二乘法这种一步到位、通过解方程组直接求得最小值的方式不同,梯度下降是通过一种“迭代求解”的方式来进行最小值的求解,其整体求解过程可以粗略描述为,先随机选取一组参数初始值,然后沿着某个方向,一步一步移动到极小值点

梯度下降法的基本思想可以类比为一个下山的过程:

​ 一个人 被困在山上,需要从山上下来 (i.e. 找到山的最低点,也就是山谷)。但此时山上的浓雾很大,导致可视度很低。因此,下山的路径就无法确定,他必须利用自己周围的信息去找到下山的路径。这个时候,他就可以利用梯度下降算法来帮助自己下山。以他当前的所处的位置为基准,寻找这个位置最陡峭的地方,然后朝着山的高度下降的地方走

​ 首先,我们有一个 可微分的函数 。这个函数就代表着一座山。我们的目标就是找到 这个函数的最小值 ,也就是山底。根据之前的场景假设,最快的下山的方式就是找到当前位置最陡峭的方向,然后沿着此方向向下走,对应到函数中,就是 找到给定点的梯度 ,然后朝着梯度相反的方向,就能让函数值下降的最快。

1.2 梯度的概念

  • 在单变量的函数中,梯度就是函数的微分,代表着函数在某个给定点的切线的斜率;

  • 在多变量函数中,梯度是一个向量,向量有方向,梯度的方向就指出了函数在给定点的上升最快的方向;

  • 在微积分里面,对多元函数的参数求∂偏导数,把求得的各个参数的偏导数以向量的形式写出来,就是梯度。

向量求导的梯度向量形式 :
∇ x f ( x ) = ∂ f ∂ x = [ ∂ f ∂ x 1 , ∂ f ∂ x 2 , . . . , ∂ f ∂ x n ] T \nabla _xf(x) = \frac{\partial f}{\partial x} = [\frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2}, ..., \frac{\partial f}{\partial x_n}]^T xf(x)=xf=[x1f,x2f,...,xnf]T
在给定具体的参数一组取值之后,我们就能计算梯度表达式的取值,该值也被称为损失函数在某组参数取值下的梯度
f ( x ) = x 3 − 3 x 2 − 9 x + 2 当前的函数是一元函数,我们只需要计算导数即可算出梯度值 f(x) = x^3 - 3x^2 -9x +2当前的函数是一元函数,我们只需要计算导数即可算出梯度值 f(x)=x33x29x+2当前的函数是一元函数,我们只需要计算导数即可算出梯度值

f ′ ( x ) = 3 x 2 − 6 x − 9 f^{\prime}(x)= 3x^2 - 6x -9 f(x)=3x26x9

当前的函数是一元函数,我们只需要计算导数即可算出梯度值
f ′ ( x ) = 3 x 2 − 6 x − 9 f^{\prime}(x)= 3x^2 - 6x -9 f(x)=3x26x9

我们可以设置学习率为 l r = 0.01 ,则从 x 0 进行移动的距离是 0.01 ∗ 11.25 = 0.1125 ,而又是朝向梯度的负方向进行移动,因此 x 0 最终移动到了 x 1 = 0.5 + 0.1125 = 0.6125 我们可以设置学习率为lr = 0.01,则从x_0进行移动的距离是0.01 * 11.25 = 0.1125, 而又是朝向梯度的负方向进行移动,因此x_0最终移动到了x_1 = 0.5 + 0.1125 = 0.6125 我们可以设置学习率为lr=0.01,则从x0进行移动的距离是0.0111.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
  1. df: 目标函数的导数(gradient)。在优化过程中,梯度下降法沿着函数下降最快的方向更新变量x
  2. x: 初始化的起点或当前点,表示我们开始搜索最小值的位置
  3. alpha: 学习率(learning rate),它决定了每次迭代时x的更新步长。较大的alpha可能导致更快的收敛,但也可能使算法错过最小值;较小的alpha可能导致更慢的收敛速度,但结果可能更精确
  4. iterations: 最大迭代次数
  5. epsilon: 极小值,用于判断梯度是否足够小
  6. 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
# 参数表示x的初始值选择1,并且学习率是0.01, 迭代100次
path = gradient_descent(y_d, 1,0.01, 100)
path[-1]
  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()])就是找到函数的全局最小值点。

l o s s ( x ) = 1 2 ( x 2 − 2 ) 2 loss(x) = \frac{1}{2}(x^2-2)^2 loss(x)=21(x22)2

l o s s ′ ( x ) = ( x 2 − 2 ) x loss^{\prime}(x) = (x^2-2)x loss(x)=(x22)x

有了梯度计算公式之后,我们可以使用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]) 

如果学习率调整为0.3,那么将找不到最低点,还会产生震荡**

在这里插入图片描述

我们将学习率改为0.01时,最后的值为path[-1] = 2.9999876804184145,已经很接近x = 3。

在这里插入图片描述

我们再将学习率改为0.001,此时曲线将离最低点还有一段距离:

在这里插入图片描述

包括我们将迭代次数改为1000次后,我们的x值将为2.999999999256501,无限接近与最低点。

假设我们有一些散点数据,需要拟合它:

在这里插入图片描述

train_x = data[:,0]
train_y = data[:,1]
X = np.concatenate([train_x.reshape(-1,1), np.ones_like(train_x.reshape(-1,1))], axis=1) 
# 加偏置
y = train_y.reshape(-1,1)
np.linalg.lstsq(X, y, rcond=-1)

我们可以用最小二乘法来求解,求出损失最小的权值w和b,通过正规方程,得出w=0.93099006,b = -1.52679069。

回到最初的问题,正规方程或者是最小二乘法求解过程中,存在诸多的限制,接下来采用梯度下降来求解该问题;

我们使用MSE作为损失函数,则该损失函数的梯度表达式为
M S E L o s s ( w ^ ) ∂ w ^ = 2 X T ( X w ^ − y ) m \frac{MSELoss(\hat w)}{\partial{\boldsymbol{\hat w}}} = \frac{2X^T(X\hat w -y)}{m} w^MSELoss(w^)=m2XT(Xw^y)

def linearRegression_gd(X, y, w):
    """
    梯度计算公式
    """
    m = X.shape[0]
    gd = 2 * X.T.dot(X.dot(w)-y) / m
    return gd
linearRegression_gd(X[:1,:],y[:1,:],np.array([1,1]).reshape(-1,1))
# 结果:-107.237845,-25.528548
  • X.T.dot(误差项)通过将误差项与𝑋X的转置矩阵相乘,实际上是计算了每个参数的偏导数之和,结果是一个与w维度相同的向量。
  • X.T.dot(误差项)是用来计算梯度的一种方式,它通过考虑所有样本的贡献来同时更新模型的所有参数。

我们使用梯度下降求解出的结果为w = 0.940894,b = -1.627557 ,现在已经很接近正规方程计算出的最小值,但是还没有收敛,还需继续迭代或者更换学习率。

在这里插入图片描述

总结:

梯度下降用于最小化损失函数以找到模型参数的最佳估计,重点就是学习率、迭代次数和初始点的选择;

学习率(Learning Rate)

  1. 学习率决定了在每次迭代中参数更新的步长
  2. 学习率过大可能导致学习过程震荡不稳,可能错过最优解,甚至使得损失函数发散。
  3. 学习率过小收敛过程会变得非常缓慢,需要大量的迭代才能达到较好的解。
  4. 学习率适当能够保证较快的收敛速度同时避免错过最优解,最理想的情况是逐渐减小学习率,以加速初期训练并在后期更精细地调整参数。

迭代次数(iterations)

  1. 一个iterations指的是整个训练数据集被模型遍历并用于更新一次参数的完整过程。
  2. 迭代次数过多可能导致过拟合,尤其是在数据集较小且模型复杂度较高的情况下。
  3. 迭代次数过小模型可能没有足够的时间从数据中学习到有效的模式,导致欠拟合。

初始点

模型参数初始值会影响梯度下降的收敛速度和最终解,良好的初始化可以加速收敛过程,避免陷入局部极小值或鞍点。

精细地调整参数。

迭代次数(iterations)

  1. 一个iterations指的是整个训练数据集被模型遍历并用于更新一次参数的完整过程。
  2. 迭代次数过多可能导致过拟合,尤其是在数据集较小且模型复杂度较高的情况下。
  3. 迭代次数过小模型可能没有足够的时间从数据中学习到有效的模式,导致欠拟合。

初始点

模型参数初始值会影响梯度下降的收敛速度和最终解,良好的初始化可以加速收敛过程,避免陷入局部极小值或鞍点。

策略:随机初始化,多次选择初始点位,避免一开始从不合适的点迭代。

  • 48
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小森( ﹡ˆoˆ﹡ )

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值