美文网首页
2020-08-19--梯度下降法01

2020-08-19--梯度下降法01

作者: program_white | 来源:发表于2020-08-20 22:06 被阅读0次
    • 梯度下降法简介
    • 多元线性回归中的梯度下降法
    • 随机梯度下降法
    • 梯度下降法 的调试

    1.梯度下降法简介

    • 不是一个机器学习算法
    • 是一种基于搜索的最优化方法
    • 作用:最小化损失函数 (最小值的点)
    • 梯度上升法:最大化一个效用函数(最大值的点 )

    1.1一元线性回归梯度下降原理分析

    首先我们一元线性回归为例:

    一元线性回归的目标:

    我们的目标是求a和b的值,以作到损失函数最小。

    在上式中X(i)和y(i)为训练集数据,我们假设这个直线最终结果是一个没有截距过原点的直线,也就是将b看作一个常数(或者将b直接去掉),对公式进行变换:

    对于第i个数据的损失函数表达式为:

    那么这样看的话这是一个关于a的一元二次方程。
    总共有m个数据,他们每一个损失函数的值相加,最后相加的结果还是一个一元二次方程。

    所以我们的目标就是找到该方程的最小值。

    参数theta对应的损失函数J的值对应的示例图,我们需要找到使得损失函数值J取得最小值对应的theta(这里是二维平面,也就是我们的参数只有一个)

    1.我们要找的就是图中的theta(m)值。
    • 在直线方程中,导数代表斜率。
    • 在曲线方程中,导数代表切线斜率。斜率越大,变化越快。
    • theta越靠近theta(m),J的变化越慢
    2.怎么理解图中的导数可以代表方向,对应J增大的方向以及公式?

    我们对图中任意一点求导(切线),这个切线都是有方向的

    • 在最小值左侧,切线的斜率是负的,对应途中的(1),它的指向为J增大的方向
    • 在最小值的右侧,切线斜率是正的,对应图中的(2),它的指向也为J增大的方向
    • 而我们的目标是向最小值的为晃着靠近,所以对每一个点求导之后,取相反数,那么这样切线就指向J减小的方向。
    3.对于学习率n,接下来介绍:

    η太小,会减慢收敛学习速度:

    η太大,甚至导致不收敛:

    那么这样的话表达式:

    我们在知道下边的原理就可以理解了。

    寻找最小点theta(m)的原理过程:

    在图中的线上随机寻找一个点,我们要不断的更新theta的值,而这个更新值与原值之间的区间就是上边的公式(我们暂且将公式值即为p),那么下一次更新的值就为(theta+p)。由于这个更新值一定指向J缩小的方向,所以theta不断靠近theta(m),直到某一次theta对应的J比上一次的theta值对应的J小于某一个很小的值(越靠近theta(m),J的变化速度越小),说明我们找到了该点theta。

    4.其他注意事项

    并不是所有函数都有唯一的极值点

    5.解决方案:
    • 多次运行,随机化初始点
    • 梯度下降法的初始点也是一个超参数
    6.有b时的情况

    在之前的分析中我们把b看作一个常数/0。

    如果加上b的话,那么损失函数就随着a,b两个参数而做改变,这就是一个三维的空间,如果做图的话,x为theta,y为b,z为J:

    那么画出来就类似于倒过来的大钟。

    1.2模拟梯度下降法

    接下来我们使用代码来实现上边的分析过程。

    1.创建数据集,画图:
    import numpy as np
    import matplotlib.pyplot as plt
    
    # 生成等差数列[-1,6],个数为141个
    plot_x = np.linspace(-1,6,141)
    print(plot_x)
    # print(len(plot_x))
    
    # 生成一元二次方程
    plot_y = (plot_x-2.5)**2 - 1
    print(plot_y)
    
    # 画图
    plt.plot(plot_x,plot_y)
    plt.show()
    

    运行:

    2.实现梯度下降:
    # 学习率n
    eta = 0.1
    # 最小差距
    epsilon = 1e-8
    
    # 定义生成J值得函数
    def J(theta):
        return (theta-2.5)**2 - 1
    
    # 定义d(J)/d(theta)得值
    def DJ(thate):
        return 2*(thate-2.5)
    
    # 设置初始theta
    theta = 0.0
    while True:
        # 记录当前位置,后边用于判断是否跳出
        last = theta
    
        # 计算下一个点的位置,直接赋给循环变量theta
        theta = theta-eta * DJ(theta)
    
        if abs(J(theta) - J(last)) < epsilon:
            break
    
    print(theta)
    print(J(theta))
    # 2.499891109642585
    # -0.99999998814289
    

    分析:

    1. 首先定义超参数n和最小差距,然后定义两个函数J和DJ,计算某一点的J值,以及计算某一点J对theta的导。
    2. 设置超参数--初始点的theta,进入无限迭代中,先记录本次点的theta值定义last,然后计算下一个点的theta,判断本次theta和上一次theta点的J值差距是否小于最小差距,若是则跳出,否则继续循环。

    3.生成梯度下降寻找最小值的过程展示:

    import matplotlib.pyplot as plt
    import numpy as np
    
    # 设置初始theta
    theta = 0.0
    # 记录寻找过程中的点
    theta_list = []
    while True:
        # 记录当前位置,后边用于判断是否跳出
        last = theta
        theta_list.append(theta)
        # 计算下一个点的位置,直接赋给循环变量theta
        theta = theta-eta * DJ(theta)
    
        if abs(J(theta) - J(last)) < epsilon:
            break
    print(len(theta_list))      # 45
    
    # 画图
    # J函数的x,y
    plot_x = np.linspace(-1,6,141)
    plot_y = J(plot_x)
    
    plt.plot(plot_x,plot_y)
    plt.plot(theta_list,J(np.array(theta_list)),color='r',marker='+')
    plt.show()
    

    运行:

    由图:
    从左到右的过程中,+号越来月稀疏。
    总共循环了45次,找到了这个theta最小值。
    这个循环次数是由学习率n,初始点,和最小差距决定的。
    例如:
    1.将学习率调小

    将学习率n为0.000001
    那么,循环次数达到了1956011次
    

    运行:

    我们可以多次改变初始点的位置以保证准确性。

    2.调大学习率

    将学习率n为0.8
    那么,循环次数为21次
    

    运行:

    学习率不能调的过大,结果会过大,会报错。

    修改J函数:

    def J(theta):
        try:
            return (theta-2.5)**2 - 1
        except:
            return float('inf')       # 返回一个很大的float数
    

    J()在返回值进入下方循环中时,能保证不报错,但是会陷入死循环中,因为在学习率很大时,在x轴上的跳跃很快,当循环次数达到一定程度,就会超出范围。

    所以在下边我们封装为函数后,可以加一个循环次数的参数,就可以查看其超出范围是怎么回事了。

    3.封装为函数
    def gradient_descent(init_theta,eta,n_iters=1e4,epsilon=1e-8):
        '''
    
        :param init_theta: 初始点的theta值
        :param eta:  学习率
        :param n_iters: 循环次数,默认为1e4
        :param epsilon:  最小差距值,默认为1e-8
        :return:
        '''
        # 将初始化的init_theta赋给theta
        theta = init_theta
        i_iter = 0       # 初始化循环次数
        theta_history = []      #  初始化路径列表
    
        while i_iter < n_iters:        # 当循环次数小于参数n_iter时,执行循环
            last = theta             # 记录本次的theta
            theta_history.append(theta)          # 传进列表
            theta = theta - eta * DJ(theta)        # 计算下次的theta
            # 判断上次的J值和本次的J值差距是否小于最小值
            if abs(J(theta) - J(last)) < epsilon:
                break
            # 循环次数+1 
            i_iter += 1
        return theta,theta_history      # 最佳theta值和寻找theta值路径列表
    

    调用:

    # 调用函数
    eta = 1.1
    result,result_list = gradient_descent(init_theta=0.0,eta=eta,n_iters=10)
    print(result)
    print(result_list)
    
    # 画图
    plt.plot(plot_x,plot_y)
    plt.plot(result_list,J(np.array(result_list)),color='r')
    plt.show()
    

    将eta设置为1.1后,循环次数设为9次,运行:

    开始值很小,慢慢的J值变化越来越快,就会溢出。

    2. 线性回归中的梯度下降法

    上述的过程实现了简单的线性回归关于y = ax的实现,而y = ax+b以及多元线性回归中的y = a(0)+a(1)x(1)+a(2)x(2)+...a(n)x(n)并没有实现。

    来看看多元线性回归:

    y轴还是J函数,x轴变为一个数据集---(theta(0),theta(1),...theta(n))。为了表达清除,化成平面图,其实这个模型图是一个n维的模型图,我们画不出来,但是我们可以画一个三维的来看一下:

    一个三维空间中的梯度下降法(x,y为系数,z为损失函数):

    在这里中theta是一个向量,可将y = ax+b中的b看作a(0),那么对于这个一元线性回归来说,这个theta就是一个有两行一列的向量。多元线性方程是多行一列的向量。,其实本质上都是一样的。

    原理:
    原理与一元线性回归一样,随即设置一个点,不断的迭代更新该点,进而找出最优点。

    • 这里就牵扯到一个变量--更新量。也就是一元中的【-n(d(J)/d(theta))】
      在多元中,由于theta是一个向量,那么要不断更新该点的位置,那么这个更新量也必须是一个向量,该向量用【-n(J对每一个theta的偏导)】
    • 这样(广播操作)向量-向量后的结果还是向量,达到了移动该点的效果。对应图中的(1)(2)点的效果。
    • 根据新的theta求出该点的J,比较差距跳出即可。

    1.损失函数求导的公式推导

    对于多元的损失函数来说,他不想一元的J那样求导的话一眼能看出来,
    例如:
    J =(theta-2.5)2 -1
    DJ = 2
    (theta-2.5)
    多元的J比较复杂:

    不可能看出来答案,所以我们要对它进行推导。

    推导:

    推导思路与线性回归章节中的思想一样,将y_head表达为两个矩阵的点乘进行计算:

    y_head = X(b) (*) theta

    X(b)和theta的表示:

    所以对J可以表示为:

    对于J求导:

    求导的依据【标量对列向量】的求导方法进行求导。

    但是上面推导出的式子的大小是和样本数有关的,m越大,结果越大,这是不合理的,我们希望和m无关,所以对损失函数J除以m:

    那么J导就变为:

    这样的话J函数对theta向量求导后的数据就表示出来了。

    2.在线性回归的梯度下降代码实现

    1.J的函数定义

    损失函数的公式:


    根据公式得知参数有 测试数据:X_b,对应真实值y,以及theta值。

    # 损失函数J
    def J(theta,X_b,y):
        try:
            return np.sum((y - X_b.dot(theta))**2)/len(X_b)
        except:
            return float('inf')
    
    2.DJ的实现

    对DJ的公式进行分析:

    DJ的公式结果是一个向量,其中数据的个数是由theta向量个数决定的,因为他每一项都是J/theta的导。所以y = ax+b其实就相当于只有theta(0)和theta(1)两个元素。

    我们将它分为两个部分,第一部分是对theta(0)的导,其余部分是第二部分。这样我们便于计算。

    参数列表:测试集数据X_b,对应真实值y,以及theta向量。

    DJ函数:

    def DJ(theta,X_b,y):
        res = np.empty(len(theta))
        # 第一个元素
        res[0] = np.sum(X_b.dot(theta) - y)
        # 第二个往后
        for i in range(1,len(theta)):
            res[i] = (X_b.dot(theta) - y).dot(X_b[:,i])
    
        return res *2 / len(X_b)
    

    分析:

    1. 首先创建一个与theta向量等长的数组res,用于填充数据。这个原因上边说过。计算第一部分数据的值--计算括号内数据直接求和即可,赋给res[0]。
    2. 其他数据项使用for循环循环计算,为了便于计算,我们把它换位向量的点乘。
      首先分析这其中一项:
    • 该数据项是m个数据值之和,他的每一项数据值都是标量*标量,例如第二行分析:


    所以就可以将公式看作(以第二行数据为例):

    那么用就可以在代码用for循环给每一项赋值。

    1. 最后返回res * 2 / len(X_b)。
    3.梯度下降函数

    与之前的y = ax的函数大概一致,只是在函数中调用J和DJ函数时要使用的参数X_b和y要加在该函数的参数中。

    gradient_descent_many:

    def gradient_descent_many(X_b,y,init_theta,eta,n_iters=1e4,epsilon=1e-8):
        '''
        :param X_b: 数据集,经过改造(第0列都为1)
        :param y:  数据集对应正确值
        :param init_theta: 初始点的theta值,一个向量
        :param eta:  学习率
        :param n_iters: 循环次数,默认为1e4
        :param epsilon:  最小差距值,默认为1e-8
        :return: theta向量
        '''
        # 将初始化的init_theta赋给theta
        theta = init_theta
        i_iter = 0       # 初始化循环次数
        # theta_history = []      #  初始化路径列表
    
        while i_iter < n_iters:        # 当循环次数小于参数n_iter时,执行循环
            last = theta             # 记录本次的theta
            # theta_history.append(theta)          # 传进列表
            theta = theta - eta * DJ(theta,X_b,y)        # 计算下次的theta
            # 判断上次的J值和本次的J值差距是否小于最小值
            if abs(J(theta,X_b,y) - J(last,X_b,y)) < epsilon:
                break
            # 循环次数+1
            i_iter += 1
    
        return theta
    
    4.生成数据,测试梯度下降
    '''生成数据'''
    np.random.seed(666)
    x = 2 * np.random.random(size=100)
    # 修改为100行1列的二维数组,也就是100个数据,每个数据1个特征
    X = x.reshape(-1,1)
    # 生成100个靠近y = 3x + 4 直线的点
    y = x * 3. + 4. + np.random.normal(size=100)
    # 将X修改其中数据值为X_b
    ones = np.ones((len(X),1))
    X_b = np.hstack([ones,X])
    print(X_b[:5])
    # [[1.         1.40087424]
    #  [1.         1.68837329]
    #  [1.         1.35302867]
    #  [1.         1.45571611]
    #  [1.         1.90291591]]
    
    # 设置init_theta,一个列向量,其长度与数据集X_b的维度(列数)相同
    # 不能是X,因为theta向量包含theta(0)
    init_theta = np.zeros(X_b.shape[1])
    print(init_theta)
    # [0. 0.]
    
    eta = 0.01
    

    如果梯度下降法寻找出来的theta(0)接近4,theta(1)接近3,那么就说明找到了。

    theta = gradient_descent_many(X_b,y,init_theta,eta)
    print(theta)
    # [4.02145786 3.00706277]
    

    成功!!!

    5.整体代码
    import numpy as np
    import matplotlib.pyplot as plt
    
    # 损失函数J
    def J(theta,X_b,y):
        try:
            return np.sum((y - X_b.dot(theta))**2)/len(X_b)
        except:
            return float('inf')
    
    def DJ(theta,X_b,y):
        res = np.empty(len(theta))
        # 第一个元素
        res[0] = np.sum(X_b.dot(theta) - y)
        # 第二个往后
        for i in range(1,len(theta)):
            res[i] = (X_b.dot(theta) - y).dot(X_b[:,i])
    
        return res *2 / len(X_b)
    
    def gradient_descent_many(X_b,y,init_theta,eta,n_iters=1e4,epsilon=1e-8):
        '''
    
        :param X_b: 数据集,经过改造(第0列都为1)
        :param y:  数据集对应正确值
        :param init_theta: 初始点的theta值,一个向量
        :param eta:  学习率
        :param n_iters: 循环次数,默认为1e4
        :param epsilon:  最小差距值,默认为1e-8
        :return:
        :return:
        '''
        # 将初始化的init_theta赋给theta
        theta = init_theta
        i_iter = 0       # 初始化循环次数
        # theta_history = []      #  初始化路径列表
    
        while i_iter < n_iters:        # 当循环次数小于参数n_iter时,执行循环
            last = theta             # 记录本次的theta
            # theta_history.append(theta)          # 传进列表
            theta = theta - eta * DJ(theta,X_b,y)        # 计算下次的theta
            # 判断上次的J值和本次的J值差距是否小于最小值
            if abs(J(theta,X_b,y) - J(last,X_b,y)) < epsilon:
                break
            # 循环次数+1
            i_iter += 1
    
        return theta
    
    '''生成数据'''
    np.random.seed(666)
    
    x = 2 * np.random.random(size=100)
    # 修改为100行1列的二维数组,也就是100个数据,每个数据1个特征
    X = x.reshape(-1,1)
    # 生成100个靠近y = 3x + 4 直线的点
    y = x * 3. + 4. + np.random.normal(size=100)
    # 将X修改其中数据值为X_b
    ones = np.ones((len(X),1))
    X_b = np.hstack([ones,X])
    print(X_b[:5])
    # [[1.         1.40087424]
    #  [1.         1.68837329]
    #  [1.         1.35302867]
    #  [1.         1.45571611]
    #  [1.         1.90291591]]
    
    # 设置init_theta,一个列向量,其长度与数据集X_b的维度(列数)相同
    # 不能是X,因为theta向量包含theta(0)
    init_theta = np.zeros(X_b.shape[1])
    print(init_theta)
    # [0. 0.]
    eta = 0.01
    
    theta = gradient_descent_many(X_b,y,init_theta,eta)
    print(theta)
    # [4.02145786 3.00706277]
    

    3. 封装梯度下降函数-->线性回归类

    在之前我们写的线性回归的类中。我们的fit方法是通过公式推导的方式计算theta的,而梯度下降法是通过不断迭代寻找最好的theta的。

    fit_gd():梯度下降法函数,在该函数中封装了三个函数:

    • J():计算损失函数
    • DJ():计算损失函数的导
    • gradient_descent():寻找最佳theta
    • fit_gd()的参数为原始训练数据,而这三个内部函数的参数数据为经过处理的数据,所以在内部函数外要进行数据整理(X_b)以及参数(init_theta,eta)的设置。
    class LinearRegression:
    
        def __init__(self):
            """初始化Linear Regression模型"""
    
            ## 系数向量(θ1,θ2,.....θn)
            self.coef_ = None
            ## 截距 (θ0)
            self.interception_ = None
            ## θ向量
            self._theta = None
    
        '''线性回归公式训练模型,计算theta'''
        def fit_normal(self, X_train, y_train):
            # 拼接为X(b)格式的数据,-----在每行的第一列之前加上1.
            ones_vector = np.ones((len(X_train), 1))
            X_b = np.hstack([ones_vector, X_train])
    
            # 根据X_b带入公式计算w
            # arr.dot(arr):点乘
            # np.linalg.inv(arr):矩阵的逆
            self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train)
    
            self.coef_ = self._theta[1:]
            self.interception_ = self._theta[0]
    
            return self
    
        '''使用梯度下降寻找theta'''
        def fit_gd(self, X_train, y_train, eta=0.01, n_iters=1e4):
            """根据训练数据集X_train, y_train, 使用梯度下降法训练Linear Regression模型"""
            assert X_train.shape[0] == y_train.shape[0], \
                "the size of X_train must be equal to the size of y_train"
    
            def J(theta, X_b, y):
                try:
                    return np.sum((y - X_b.dot(theta)) ** 2) / len(y)
                except:
                    return float('inf')
    
            def dJ(theta, X_b, y):
                res = np.empty(len(theta))
                res[0] = np.sum(X_b.dot(theta) - y)
                for i in range(1, len(theta)):
                    res[i] = (X_b.dot(theta) - y).dot(X_b[:, i])
                return res * 2 / len(X_b)
    
            def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8):
    
                theta = initial_theta
                cur_iter = 0
    
                while cur_iter < n_iters:
                    gradient = dJ(theta, X_b, y)
                    last_theta = theta
                    theta = theta - eta * gradient
                    if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
                        break
    
                    cur_iter += 1
    
                return theta
    
            X_b = np.hstack([np.ones((len(X_train), 1)), X_train])
            initial_theta = np.zeros(X_b.shape[1])
            self._theta = gradient_descent(X_b, y_train, initial_theta, eta, n_iters)
    
            self.interception_ = self._theta[0]
            self.coef_ = self._theta[1:]
    
            return self
    
    
        '''测试集'''
        def perdict(self, X_perdict):
            ones_vector = np.ones((len(X_perdict), 1))
            X_b = np.hstack([ones_vector, X_perdict])
    
            y_head = X_b.dot(self._theta)
    
            return y_head
    
        '''MSE'''
        def mean_squared_error(self, y_true, y_predict):
            """计算y_true和y_predict之间的MSE"""
            assert len(y_true) == len(y_predict), \
                "the size of y_true must be equal to the size of y_predict"
    
            return np.sum((y_true - y_predict) ** 2) / len(y_true)
    
        '''R^2'''
        def r2_score(self, y_true, y_perdict):
            r2_score = 1 - self.mean_squared_error(y_true, y_perdict) / np.var(y_true)
            return r2_score
    
        def __repr__(self):
            return 'LinearRegression'
    

    调用:

    '''生成数据'''
    np.random.seed(666)
    
    x = 2 * np.random.random(size=100)
    # 修改为100行1列的二维数组,也就是100个数据,每个数据1个特征
    X = x.reshape(-1,1)
    # 生成100个靠近y = 3x + 4 直线的点
    y = x * 3. + 4. + np.random.normal(size=100)
    
    # 实例化算法模型
    lin = LinearRegression()
    lin.fit_gd(X,y)
    print(lin.coef_)        # [3.00706277]
    print(lin.interception_)        # 4.021457858204859
    print(lin._theta)      # [4.02145786 3.00706277]
    

    训练结果大概正确。

    4.向量化

    我们在计算多元线性回归的的损失函数J对每个theta值的导DJ时略显麻烦,先计算第一个,在循环计算其他得数据项,如果把这个DJ用向量的点乘表示出来,那么就轻松了。

    推导:

    由于X(b)的第0列的所有数据都是1,所以上式成立。

    1. 观察上式右边的式子,先不看 2/m:
      它是一个n+1 * 1 格式的向量,其每一项都是m个标量求和,那么去掉求和符号的话:所以其每一项必然是一个行向量(1 * m)(点乘)一个列向量(m * 1),并且他们每一个行式子的区别都是右边向量X_b的列数变化
    • 那么我们呢可以将左边看作一个列向量(m * 1),右边看作一个矩阵,该矩阵就是X_b矩阵的转置矩阵(n+1 * m)。

    展开来写:

    这样计算出来就是DJ了。

    修改DJ函数:

    def DJ(theta,X_b,y):
        return X_b.T.dot(X_b.dot(theta) - y)* 2. / len(X_b)
    

    使用boston房价进行测试:

    from sklearn import datasets
    from KNN.knn_iris import train_test_split
    from Tidudown.manyTidu.tuduClass import LinearRegression
    
    data = datasets.load_boston()
    X = data.data
    y = data.target
    X = X[y<50]
    y = y[y<50]
    
    X_train,y_train,x_test,y_test = train_test_split(X,y)
    
    lr = LinearRegression()
    
    lr.fit_gd(X_train,y_train,eta = 0.000001,n_iters=1e6)
    y_perdict = lr.perdict(x_test)
    z = lr.r2_score(y_test,y_perdict)
    print(z)
    # 0.6908063505166206
    

    使用公式推导的方式计算theta训练模型:

    # 使用公式推导的方式训练模型
    lr.fit_normal(X_train,y_train)
    y_perdict = lr.perdict(x_test)
    z = lr.r2_score(y_test,y_perdict)
    print(z)
    # 0.784704968177089
    

    在使用真实的数据,调整eta和n_iters,

    • 要么由于eta太小导致无法得出真实的结果,导致学习不好,正确率低
    • 要么由于eta太大导致训练时间加长,这是由于数据的规模在不同的特征上不同,所以我们需要对数据进行归一化。

    5.数据归一化

    为了防止数据中某一列数据的值过大导致结果发生偏差,要进行数据归一化操作。

    from sklearn import datasets
    from KNN.knn_iris import train_test_split
    from Tidudown.manyTidu.tuduClass import LinearRegression
    from sklearn.preprocessing import StandardScaler
    
    data = datasets.load_boston()
    X = data.data
    y = data.target
    X = X[y<50]
    y = y[y<50]
    
    # 分割数据
    X_train,y_train,x_test,y_test = train_test_split(X,y)
    
    # 数据归一化
    ss = StandardScaler()
    ss.fit(X_train)
    X_train_standard = ss.transform(X_train)
    x_test_standard = ss.transform(x_test)
    
    # 开始学习
    lin = LinearRegression()
    # 梯度下降
    lin.fit_gd(X_train_standard,y_train)
    y_perdict = lin.perdict(x_test_standard)
    re = lin.r2_score(y_test,y_perdict)
    print(re)
    # 0.7876525859547368
    # 公式推导
    lin.fit_normal(X_train,y_train)
    y_perdict = lin.perdict(x_test)
    z = lin.r2_score(y_test,y_perdict)
    print(z)
    # 0.7876600935022398
    

    可以看到使用两种方式学习后的正确率基本都差不多了。

    6.梯度下降法的优势

    自己定义一个训练集,theta向量,以及他们之间的线值y。

    m = 1000
    n = 5000
    
    big_X = np.random.normal(size=(m, n))
    true_theta = np.random.uniform(0.0, 100.0, size=n+1)
    big_y = big_X.dot(true_theta[1:]) + true_theta[0] + np.random.normal(0., 10., size=m)
    
    big_reg1 = LinearRegression()
    %time big_reg1.fit_normal(big_X, big_y)
    
    # CPU times: user 18.8 s, sys: 899 ms, total: 19.7 s
    # Wall time: 10.9 
    
    big_reg2 = LinearRegression()
    %time big_reg2.fit_gd(big_X, big_y)
    
    # CPU times: user 9.51 s, sys: 121 ms, total: 9.63 s
    # Wall time: 5.76 s
    

    如果样本数非常多,那么即使使用梯度下降法也会导致速度比较慢,因为在梯度下降法中,J的值需要每一个样本都要参与运算。这时候需要采用随机梯度下降法。

    相关文章

      网友评论

          本文标题:2020-08-19--梯度下降法01

          本文链接:https://www.haomeiwen.com/subject/spdjjktx.html