当前位置: 首页 > article >正文

11.19 机器学习-梯度下降

# **正规方程求解的缺点**

# 最小二乘法的缺点

# 之前利用正规方程求解的W是最优解的原因是MSE这个损失函数是凸函数。

# 但是,机器学习的损失函数并非都是凸函数,设置导数为0会得到很多个极值,不能确定唯一解,MSE还有一个问题,当数据量和特征较多时,矩阵计算量太大.

# 极值点不止一个 计算量大 求逆矩阵的时间复杂度为O(n^3)

# 梯度下降 一点一点的靠近损失函数的的极值点

# 求出损失函数 然后一点点的调整W的值使得损失函数的值变小 多个W的话随机生成一组成正太分布的数值w_0,w_1,w_2....w_n,这个随机是成正太分布的(高斯说的)

# 首先要初始化一个W 即选择一个起点 然后变大或者变小 带入导函数 导函数的值为负数 就要增大 此时的点肯定在极小值的左边 为正数要变小 此时在极小值的右边 最后导函数的值越来越靠近0

# 但是算法没有对此时的导函数的值进行正负性判断 而是依靠公式判断

# 公式   w新= w旧 -学习率a*梯度  a为正  梯度就是w旧带入导函数的值 如果为负 就说明在左边 就会+ 反之为正说明在右边就会减 离得远梯度大步子大 反之步子小

# ### 6.3学习率

# 根据我们上面讲的梯度下降公式,我们知道α是学习率,设置大的学习率α;每次调整的幅度就大,设置小的学习率α;每次调整的幅度就小,然而如果步子迈的太大也会有问题!

# 学习率大,可能一下子迈过了,到另一边去了(从曲线左半边跳到右半边),继续梯度下降又迈回来,使得来来回回震荡。步子太小呢,就像蜗牛一步步往前挪,也会使得整体迭代次数增加。

# ### 6.3学习率

# 学习率的设置是门一门学问,

# 一般我们会把它设置成一个小数,0.1、0.01、0.001、0.0001,都是常见的设定数值(然后根据情况调整)。一般情况下学习率在整体迭代过程中是不变,但是也可以设置成**随着迭代次数增多学习率逐渐变小**,

# 因为越靠近山谷我们就可以步子迈小点,可以更精准的走入最低点,同时防止走过。还有一些深度学习的优化算法会自己控制调整学习率这个值

# 自己实现一遍梯度下降

import numpy as np

import matplotlib.pyplot as plt

import random

from sklearn.datasets import fetch_california_housing

from sklearn.model_selection import train_test_split

from sklearn.preprocessing import StandardScaler

from sklearn.linear_model import SGDRegressor

import random

import numpy as np

def gradient_descent():

    w=np.linspace(-10,20,100) # 画图用的x的坐标

    loss=lambda w_1:(w_1-3.5)**2-4.5*w_1+10 # 损失函数 ***

    # plt.plot(w,loss)

    # plt.show()

    g=lambda w_1:2*(w_1-3.5)-4.5#导函数***

    w1=random.randint(-10,20) # 随机一个初始w***

    alpha=0.1

    w2_list=[]

    for x in range(100):

        w2=w1-alpha*g(w1)  #梯度下降公式

        w2_list.append(w2)

        w1=w2

        alpha=alpha-alpha/10 # 控制学习率越来越小

    plt.plot(w,loss(w))

    plt.scatter(w2_list,loss(np.array(w2_list)),marker="o")

    plt.show()

    pass

# 如果有两个w w1 ,w2 就要用偏导数

def gradient_descent2():

    # 损失函数 关于w1,w2的二次方程

    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

    # w1 w2 的偏导

    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的导函数

    # 初始化随机w1 w2

    w_1=10#np.random.randint(0,100,size=1)[0]#随机初始值

    w_2=40#np.random.randint(0,100,size=1)[0]#随机初始值

    # 学习率初始化 0.1

    alpha=0.1

    w1_list=[]

    w2_list=[]

    for x in range(10):

        w1=w_1-alpha*dw_1(w_1,w_2)

        w2=w_2-alpha*dw_2(w_1,w_2)

        w1_list.append(w1)

        w2_list.append(w2)

        w_1,w_2=w1,w2

    pass

    print(w1_list)

    print(w2_list)

# API

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

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

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

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

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

# - **Batch Gradient Descent (BGD)**: 在这种情况下,每一次迭代都会使用全部的训练样本**计算梯度**来更新权重。 就是上面自己做的方式 这个数量大了太慢 把全部的数据集拿来做梯度下降 均方差公式的n值 写均方差公式的时候 全部的样本都考虑

# 这意味着每一步梯度更新都是基于整个数据集的平均梯度。这种方法的优点是每次更新的方向是最准确的,但缺点是计算量大且速度慢,尤其是在大数据集上。

"""

**特点**

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

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

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

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

**使用场景**

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

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

**实现注意事项**

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

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

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

**API**

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

"""

# - **Mini-Batch Gradient Descent (MBGD)**: 这种方法介于批量梯度下降和随机梯度下降之间。它不是用全部样本也不是只用一个样本,  每次下降考虑一部分数据 均方差公式的n值

# 而是每次迭代从数据集中随机抽取一小部分样本(例如,从500个样本中选取32个),然后基于这一小批样本的平均梯度来更新权重。这种方法在准确性和计算效率之间取得了一个平衡。 每次一般选择2的次方个




 

# - **Stochastic Gradient Descent (SGD)**: 在随机梯度下降中,每次迭代仅使用随机单个样本(或有时称为“例子”)来计算梯度并更新权重。

# 这种方法能够更快地收敛,但由于每次更新都基于单个样本,所以会导致权重更新路径不稳定。 最快 每次n变为了1

"""

**基本步骤**

1. **初始化参数**:

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

2. **选择样本**:

   - 随机选取一个训练样本$ (x^{(i)}, y^{(i)})$。

3. **计算梯度**:

   - 使用所选样本 $(x^{(i)}, y^{(i)})$来近似计算损失函数 $J(\theta) $的梯度 $\nabla J(\theta)$。

4. **更新参数**:

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

     $\theta := \theta - \alpha \cdot \nabla J(\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_ 偏置

def sgd1():

   data=fetch_california_housing(data_home="assets/datasets")

   # print(data.feature_names)

   # print(data.target_names)

   x=data.data

   y=data.target

   # print(x)

   # print(y)

   

   scaler1=StandardScaler()

   scaler2=StandardScaler()

   # 创建sgd工具

   sgd=SGDRegressor(loss="squared_error",max_iter=10000,shuffle=True,eta0=0.001)  # loss 损失函数,默认为 ’squared_error’

   x_train,x_test,y_train,y_test=train_test_split(x,y,random_state=666,train_size=0.7)

   x_train_stand=scaler1.fit_transform(x_train)

   x_test_stand=scaler1.transform(x_test)

   sgd.fit(x_train_stand,y_train)

   score1=sgd.score(x_test_stand,y_test)

   

   print(score1) # 得分范围为 负无穷到1 sgd.score使用的是R² score(决定系数)可以为负 使用mse不能为负

   pass


 

if __name__=="__main__":

    # gradient_descent()

    # gradient_descent2()

    sgd1()


http://www.kler.cn/a/406195.html

相关文章:

  • numpy中的nan填充
  • C#元组详解:创建、访问与解构
  • mongodb多表查询,五个表查询
  • Linux 进程概念与进程状态
  • 集成金蝶云星空数据至MySQL的完整案例解析
  • 99.【C语言】数据结构之二叉树的基本知识
  • unity3d——基础篇2刷(Mathf)
  • PyCharm的类型警告: Expected type ‘SupportsWrite[bytes]‘, got ‘BinaryIO‘ instead
  • 通过IIC访问模块寄存器[ESP--1]
  • springboot图书馆预约与占座小程序
  • RT-DETR融合[TIP2023]DehazeFormer中的SKFusion模块及相关改进思路
  • C++算法练习-day42——98.验证二叉搜索树
  • 31、js中日期操作
  • vulfocus在线靶场:CVE_2019_16662 速通手册
  • 耿恭坚守城池的方法
  • c++11的动态类型
  • 【AIGC】ChatGPT提示词Prompt解析:拒绝的艺术:如何优雅地说“不“
  • 如何为PDF文件创建口令密码
  • 如何在MATLAB中实现图像自动分割
  • C语言基础学习:抽象数据类型(ADT)
  • 远程服务器Docker使用本地代理加速访问外部资源
  • gitlab:使用脚本批量下载项目,实现全项目检索
  • 关于Linux中线程优先级的问题探讨
  • 【Linux】-学习笔记04
  • [ruby on rails] 安装docker
  • 量化交易系统开发-实时行情自动化交易-4.3.1.跨市场套利策略实现