前面我们介绍到求最小值时,我们可以用高斯的最小二乘法来计算,但是这对计算机的算力太高,这里我们就来学习,计算机是怎么找的。

我们找w的某一个值,使loss的值最小,假如有一个w1=1算出来的loss为20,计算机怎么判断这个loss值是否最小,是不是再找一个w对应的loss来作比较,所以我们先给w加上1,然后一算loss为19,现在是不是就又变小了,假如算出来是30,我还要继续加吗?肯定要减了涩,我们在计算机里怎么判断,是不是加一个if就行了,但是这样是不是有点麻烦了,而且假如w为999999的时候loss最小,我一个一个加是不是有一点慢,有小伙伴说,我们加一个大一点,那么假如w为2就最小了,加一个大点是不是离得更远了,那么有没有什么方法,仅能控制方向又能控制每次加的大小呢?

一、梯度下降

1.1梯度下降概念

什么是梯度下降

这里的文字描述很官方,看不懂也没关系,我们先看后面的。

假设你在一个陌生星球的山地上,你想找到一个谷底,那么肯定是想沿着向下的坡行走,如果想尽快的走到谷底,那么肯定是要沿着最陡峭的坡下山。每走一步,都找到这里位置最陡峭的下坡走下一步,这就是梯度下降。

在这个比喻中,梯度就像是山上的坡度,告诉我们在当前位置上地势变化最快的方向。为了尽快走向谷底,我们需要沿着最陡峭的坡向下行走,而梯度下降算法正是这样的方法。

每走一步,我们都找到当前位置最陡峭的下坡方向,然后朝着该方向迈进一小步。这样,我们就在梯度的指引下逐步向着谷底走去,直到到达谷底(局部或全局最优点)。

在机器学习中,梯度表示损失函数对于模型参数的偏导数。具体来说,对于每个可训练参数,梯度告诉我们在当前参数值下,沿着每个参数方向变化时,损失函数的变化率。通过计算损失函数对参数的梯度,梯度下降算法能够根据梯度的信息来调整参数,朝着减少损失的方向更新模型,从而逐步优化模型,使得模型性能更好。

在 \bar e={\frac{1}{n}}\sum_{i=1}^{n}x_{i}^{2}w^{2}-{\frac{2}{n}}\sum_{i=1}^{n} x_{i}y_{i}w+{\frac{1}{n}}\sum_{i=1}^{n} y_{i}^{2} 这个一元二次方程中,损失函数对于参数 w 的梯度就是关于 w 点的切线斜率。梯度下降算法会根据该斜率的信息来调整参数 w,使得损失函数逐步减小,从而找到使得损失最小化的参数值,优化模型的性能。

梯度下降法(Gradient Descent)是一个算法,但不是像多元线性回归那样是一个具体做回归任务的算法,而是一个非常通用的优化算法来帮助一些机器学习算法求解出最优解,所谓的通用就是很多机器学习算法都是用梯度下降,甚至深度学习也是用它来求解最优解。 所有优化算法的目的都是期望以最快的速度把模型参数W求解出来,梯度下降法就是一种经典常用的优化算法。

1.2梯度下降步骤

我们能够发现,是不是离最小值越远,它的切线斜率是不是就越大,离得越近是不是就越接近于0,咦,这不就有自动控制步长不就来了么,

然后w新 =  w旧 - g(w旧),这样是不是能控制了,但是为什么要减,我们的斜率不是一个有正负的嘛?

梯度下降流程就是“猜"正确答案的过程:

1、Random随机数生成初始W,随机生成一组成正太分布的数值w_0,w_1,w_2....w_n,这个随机是成正太分布的(高斯说的)

2、求梯度g,梯度代表曲线某点上的切线的斜率,沿着切线往下就相当于沿着坡度最陡峭的方向下降.

3、if g < 0,w变大,if g >0,w变小(目标左边是斜率为负右边为正 )

4、判断是否收敛,如果收敛跳出迭代,如果没有达到收敛,回第2步再次执行2~4步收敛的判断标准是:随着迭代进行查看损失函数Loss的值,变化非常微小甚至不再改变,即认为达到收敛

5.上面第4步也可以固定迭代次数

1.2梯度下降公式

随机给一个w初始值,然后就不停的修改它,直到达到抛物线最下面附近,比如

w=0.2

w=w-0.01*w为0.2时的梯度(导数) 假设算出来是 0.24

w=w-0.01*w为0.24时的梯度(导数) 假设算出来是 0.33

w=w-0.01*w为0.33时的梯度(导数) 假设算出来是 0.51

w=w-0.01*w为0.51时的梯度(导数) 假设算出来是 0.56

w=w-0.01*w为0.56时的梯度(导数) 假设算出来是 0.58

w=w-0.01*w为0.58时的梯度(导数) 假设算出来是 0.62

就这样一直更新下去,会在真实值附近,我们可以控制更新的次数

1.3 关于随机的w在左边和右边问题:

因为导数有正负

如果在左边 导数是负数 减去负数就是加 往右移动

如果在右边 导数是正数 减去正数就是减 往左移动

1.4 学习率

根据我们上面讲的梯度下降公式,我们知道α是学习率,设置大的学习率α;每次调整的幅度就大,设置小的学习率α;每次调整的幅度就小,然而如果步子迈的太大也会有问题! 学习率大,可能一下子迈过了,到另一边去了(从曲线左半边跳到右半边),继续梯度下降又迈回来,使得来来回回震荡。步子太小呢,就像蜗牛一步步往前挪,也会使得整体迭代次数增加。

学习率的设置是门一门学问,一般我们会把它设置成一个小数,0.1、0.01、0.001、0.0001,都是常见的设定数值(然后根据情况调整)。一般情况下学习率在整体迭代过程中是不变,但是也可以设置成随着迭代次数增多学习率逐渐变小,因为越靠近山谷我们就可以步子迈小点,可以更精准的走入最低点,同时防止走过。还有一些深度学习的优化算法会自己控制调整学习率这个值

1.5 自己实现梯度下降

我们自己用代码亲自实现一遍梯度下降,之后使用API时就明白它底层的核心实现过程了.

1.假设损失函数是只有一个w_1特征的抛物线:

我们要求解这个抛物线最小值时的横坐标w_1的值

#1.列损失函数 画出函数图像
loss=lambda w_1:(w_1-3.5)**2-4.5*w_1+10
w_1=np.linspace(0,11.5,100)
plt.plot(w_1,loss(w_1))

#2.求这个损失函数的最小值:梯度下降
def cb():
    g=lambda w_1:2*(w_1-3.5)-4.5#导函数
    t0,t1=1,100    
    alpha=t0/t1#学习率,设置大和过大会导致震荡或者无法收敛
    w_1=np.random.randint(0,10,size=1)[0]#随机初始值
    #控制更新次数
    for i in range(1000):
        alpha=t0/(i+t1)#控制学习率 逐步变小
        w_1=w_1-alpha*g(w_1)#梯度下降公式
        print("更新后的w_1:",w_1)
cb()

2.假设损失函数是有两个w_1,w_2特征的椎体(我画不来 假装下面是个椎体)

上一个案例:一个w_1更新梯度时是抛物线对于w_1 求导然后更新w_1

这个案例是:两个w_1,w_2,那么我们再分别更新w_1,w_2时 就是对于另一个求偏导

比如随机初始:w_1=10,w_2=40

第一次更新时:

w_1新 = 10-学习率*把w_2=40带入求w_1的导数

w_2新 = 40-学习率*把w_1=10带入求w_2的导数

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
#1.列损失函数 画出函数图像
loss=lambda w_1,w_2:(w_1-3.5)**2+(w_2-2)**2+2*w_2-4.5*w_1+3*w_1*w_2+20
#2.求这个损失函数的最小值:梯度下降
def cb2():
    t0,t1=1,100    
    alpha=t0/t1#学习率,设置大和过大会导致震荡或者无法收敛
    w_1=10#np.random.randint(0,100,size=1)[0]#随机初始值
    w_2=40#np.random.randint(0,100,size=1)[0]#随机初始值
    dw_1=lambda w_1,w_2:2*(w_1-3.5)+3*w_2-4.5#w_1的导函数
    dw_2=lambda w_1,w_2:3*w_1+2*w_2-2#w_2的导函数
    #控制更新次数
    for i in range(100):
        alpha=t0/(i+t1)#控制学习率 逐步变小
        w_1_=w_1#保存起来  防止梯度下降过程中w_1和w_2的值发生改变
        w_2_=w_2#
        w_1=w_1-alpha*dw_1(w_1_,w_2_)#梯度下降公式
        w_2=w_2-alpha*dw_2(w_1_,w_2_)
        print("更新后的w_1,w_2:",w_1,w_2)
cb2()

至此我们已经实现了BGD批量梯度下降

3.假设损失函数是有多个w_1,w_2....特征的超平面

这时候我们也可以自己写 但是学到这里 知道原理以后 该上API了

1.6 sklearn梯度下降

官方的梯度下降API常用有三种:

批量梯度下降BGD(Batch Gradient Descent)

小批量梯度下降MBGD(Mini-BatchGradient Descent)

随机梯度下降SGD(Stochastic Gradient Descent)。

三种梯度下降有什么不同呢?

  • Batch Gradient Descent (BGD): 在这种情况下,每一次迭代都会使用全部的训练样本计算梯度来更新权重。这意味着每一步梯度更新都是基于整个数据集的平均梯度。这种方法的优点是每次更新的方向是最准确的,但缺点是计算量大且速度慢,尤其是在大数据集上。

  • Mini-Batch Gradient Descent (MBGD): 这种方法介于批量梯度下降和随机梯度下降之间。它不是用全部样本也不是只用一个样本,而是每次迭代从数据集中随机抽取一小部分样本(例如,从500个样本中选取32个),然后基于这一小批样本的平均梯度来更新权重。这种方法在准确性和计算效率之间取得了一个平衡。

  • Stochastic Gradient Descent (SGD): 在随机梯度下降中,每次迭代仅使用随机单个样本(或有时称为“例子”)来计算梯度并更新权重。这种方法能够更快地收敛,但由于每次更新都基于单个样本,所以会导致权重更新路径不稳定。

批量梯度下降BGD

批量梯度下降是一种用于机器学习和深度学习中的优化算法,它用于最小化损失函数(目标函数)。批量梯度下降使用整个训练数据集来计算梯度并更新模型参数。

原理

批量梯度下降的基本思想是在每个迭代步骤中使用所有训练样本来计算损失函数的梯度,并据此更新模型参数。这使得更新方向更加准确,因为它是基于整个数据集的梯度,而不是像随机梯度下降那样仅基于单个样本。

更新规则

我们前面讲的就是批梯度下降

特点

  • 准确性:由于使用了所有训练样本,所以得到的梯度是最准确的,这有助于找到全局最小值。

  • 计算成本:每次更新都需要遍历整个数据集,因此计算量较大,特别是在数据集很大的情况下。

  • 收敛速度:虽然每一步的更新都是准确的,但由于计算成本较高,实际收敛到最小值的速度可能不如其他方法快。

  • 内存需求:需要在内存中存储整个数据集,对于大型数据集来说可能成为一个问题。

使用场景

  • 小数据集:当数据集较小时,批量梯度下降是一个不错的选择,因为它能保证较好的收敛性和准确性。

  • 不需要实时更新:如果模型不需要实时更新,例如在离线训练场景下,批量梯度下降是一个合理的选择。

实现注意事项

  • 选择合适的学习率:选择合适的学习率对于快速且稳定的收敛至关重要。如果学习率太小,收敛速度会很慢;如果太大,则可能会导致不收敛。

  • 数据预处理:对数据进行标准化或归一化,可以提高批量梯度下降的效率。

  • 监控损失函数:定期检查损失函数的变化趋势,确保算法正常工作并朝着正确的方向前进。

API

批量梯度下降通常不是首选方法,因为它在大数据集上的计算成本较高。如果你确实需要批量梯度下降,那么可以考虑自己实现。

随机梯度下降SGD

随机梯度下降(Stochastic Gradient Descent, SGD)是一种常用的优化算法,在机器学习和深度学习领域中广泛应用。与批量梯度下降(BGD)和小批量梯度下降(MBGD)相比,SGD 每一步更新参数时仅使用单个训练样本,这使得它更加灵活且计算效率更高,特别是在处理大规模数据集时。

基本步骤

  1. 初始化参数:

    • 选择一个初始点作为参数向量 \theta的初始值。

  2. 选择样本:

    • 随机选取一个训练样本,来计算。

  3. 计算梯度:

  4. 更新参数:

    • 根据梯度的方向来更新参数 \theta。更新公式为:

    • 其中 \alpha 是学习率,决定了每次迭代时参数更新的步长。

  5. 重复步骤 2 到 4:

    • 对所有的训练样本重复此过程,直到完成一个完整的 epoch(即所有样本都被访问过一次)。

  6. 重复多个 epoch:

    • 重复上述过程,直到满足某个停止条件,比如达到最大迭代次数或者梯度足够小。

  7. 输出结果:

    • 输出最小化损失函数后的最优参数 \theta^*。

注意事项

  • 学习率 \alpha: 需要适当设置,太大会导致算法不收敛,太小则收敛速度慢。

  • 随机性: 每次迭代都从训练集中随机选择一个样本,这有助于避免陷入局部最小值

  • 停止条件: 可以是达到预定的最大迭代次数,或者梯度的范数小于某个阈值。

随机梯度下降的一个关键优势在于它能够快速地进行迭代并适应较大的数据集。然而,由于每次只使用一个样本进行更新,梯度估计可能较为嘈杂,这可能导致更新过程中出现较大的波动。在实际应用中,可以通过减少学习率(例如采用学习率衰减策略)来解决这个问题。

API

sklearn.linear_model.SGDRegressor()
功能:梯度下降法线性回归
参数:
	loss: 损失函数,默认为 ’squared_error’
	fit_intercept: 是否计算偏置, default=True
	eta0: float, default=0.01学习率初始值
 	learning_rate:  str, default=’invscaling’   
 		The learning rate schedule:
            ‘constant’: eta = eta0 学习率为eta0设置的值,保持不变
            ‘optimal’: eta = 1.0 / (alpha * (t + t0)) 
            ‘invscaling’: eta = eta0 / pow(t, power_t)
            ‘adaptive’: eta = eta0, 学习率由eta0开始,逐步变小
    max_iter: int,  default=1000 经过训练数据的最大次数(又名epoch)
    shuffle=True 每批次是否洗牌
 	penalty: {‘l2’, ‘l1’, ‘elasticnet’, None}, default=’l2’
 		要使用的惩罚(又称正则化项)。默认为' l2 ',这是线性SVM模型的标准正则化器。' l1 '和' 
 		elasticnet '可能会给模型(特征选择)带来' l2 '无法实现的稀疏性。当设置为None时,不添加惩罚。
属性:	 
coef_ 回归后的权重系数
intercept_ 偏置

批量梯度下降MBGD

小批量梯度下降是一种介于批量梯度下降(BGD)与随机梯度下降(SGD)之间的优化算法,它结合了两者的优点,在机器学习和深度学习中被广泛使用。

原理

小批量梯度下降的基本思想是在每个迭代步骤中使用一小部分(即“小批量”)训练样本来计算损失函数的梯度,并据此更新模型参数。这样做的好处在于能够减少计算资源的需求,同时保持一定程度的梯度准确性。

更新规则

取一部分样本集来跟新梯度。

特点

  • 计算效率:相比于批量梯度下降,小批量梯度下降每次更新只需要处理一部分数据,减少了计算成本。

  • 梯度估计:相比于随机梯度下降,小批量梯度下降提供了更准确的梯度估计,这有助于更稳定地接近最小值。

  • 内存需求:相比批量梯度下降,小批量梯度下降降低了内存需求,但仍然比随机梯度下降要高。

  • 收敛速度与稳定性:小批量梯度下降能够在保持较快的收敛速度的同时,维持相对较高的稳定性。

使用场景

  • 中等规模数据集:当数据集大小适中时,小批量梯度下降是一个很好的折衷方案,既能够高效处理数据,又能够保持良好的收敛性。

  • 在线学习:在数据流式到达的场景下,小批量梯度下降可以有效地处理新到来的数据批次。

  • 分布式环境:在分布式计算环境中,小批量梯度下降可以更容易地在多台机器上并行执行。

实现注意事项

  • 选择合适的批量大小:批量大小的选择对性能有很大影响。较大的批量可以减少迭代次数,但计算成本增加;较小的批量则相反。

  • 选择合适的学习率:选择合适的学习率对于快速且稳定的收敛至关重要。如果学习率太小,收敛速度会很慢;如果太大,则可能会导致不收敛。

  • 数据预处理:对数据进行标准化或归一化,可以提高小批量梯度下降的效率。

  • 监控损失函数:定期检查损失函数的变化趋势,确保算法正常工作并朝着正确的方向前进。

API

还是使用sklearn.linear_model.SGDRegressor()

只是训练时我们分批次地训练模型,调用partial_fit函数训练会直接更新权重,而不需要调fit从头开始训练。通常情况下,我们会将数据分成多个小批量,然后对每个小批量进行训练。

案例

# 线性回归 加载加利福尼亚住房数据集,进行回归预测
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, SGDRegressor, Ridge
from sklearn.metrics import mean_squared_error

from sklearn.datasets import fetch_california_housing
# 1)加载数据
housing = fetch_california_housing(data_home="./src")
print(housing)
# 2)划分训练集与测试集
x_train, x_test, y_train, y_test = train_test_split(housing.data, housing.target, random_state=22)
# 3)标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 4)线性回归预估器
estimator = SGDRegressor(learning_rate="constant", eta0=0.01, max_iter=1000,shuffle=True, penalty="l1")
# 小批量梯度下降
batch_size = 50  # 批量大小
n_batches = len(x_train) // batch_size  # 批次数量
for epoch in range(estimator.max_iter):
    indices = np.random.permutation(len(x_train))  # 随机打乱样本顺序
    for i in range(n_batches):
        start_idx = i * batch_size
        end_idx = (i + 1) * batch_size
        batch_indices = indices[start_idx:end_idx]
        X_batch = x_train[batch_indices]
        y_batch = y_train[batch_indices]
        estimator.partial_fit(X_batch, y_batch)  # 更新模型权重

  
# 5)得出模型
print("权重系数为:\n", estimator.coef_)  #权重系数与特征数一定是同样的个数。
print("偏置为:\n", estimator.intercept_)

# 6)模型评估
y_predict = estimator.predict(x_test)
print("得分:\n",estimator.score(x_test, y_test))
print("预测的数据集:\n", y_predict)
error = mean_squared_error(y_test, y_predict)
print("均方误差为:\n", error)

1.7 梯度下降优化

1.标准化

前期数据的预处理,之前讲的

2.正则化

防止过拟合

后面再讲

更多推荐