zoukankan      html  css  js  c++  java
  • 梯度下降法的原理与实现

    梯度下降法的原理与实现

    概念介绍

    梯度下降法目的是为了“下降”,下降的方法是按照“梯度”。比如你在一座山上,当前你只能迈出一步,如何走才能使你的高度下降的最多呢,根据梯度的理论,我们沿着当前梯度的反方向走,会让我们的下降幅度最大。
    上述例子中,山就是一个函数,在山上的你就是函数中待优化的变量,人的坐标表示变量初始值,我们要 求的是函数最小值即到达山底,人该如何走即如何迭代变量。所以我们只要沿着函数梯度的反方向,就能最快的到达我们要去的地方。
    梯度下降是一种更新参数的方法,具体如何更新跟原函数的在某点的梯度有关。不会改变要求的最优解。
    我们可以利用梯度下降法求最大值和最小值,求最大值沿着梯度方向走即可,求最小值则沿着梯度的反方向走。

    公式

    抽象的公式就一个
    θ n e x t = θ n o w − α ▽ f ( θ n o w ) heta ^{next} = heta ^{now} - alphaigtriangledown f( heta ^{now}) θnext=θnowαf(θnow)
    θ n e x t heta ^{next} θnext:x在下个时刻的坐标
    θ n o w heta ^{now} θnow:x在当前时刻的坐标
    α alpha α:步长,每一步走多远,即学习率
    ▽ f ( θ n o w ) igtriangledown f( heta ^{now}) f(θnow):目标函数f(x)在 θ n o w heta ^{now} θnow点的导数
    举个例子:
    目标函数 y = x 2 y = x^{2} y=x2,学习率 α alpha α=0.1,当前位置x =1,要求y最小值,则下一时刻x的值应该更新为多少呢。根据梯度下降理论,下一时刻:
    x = 1 - 0.1*2*1 = 0.8,此时的xx=1的时候更接近0这个最小值。这就是一元变量下的梯度下降算法,多元变量是也是一样的,只是求梯度时有些许不同而已。

    算法实现

    结合线性回归模型来实现梯度下降算法。梯度下降是线性回归求最优解的一种常用方法。
    设我们的线性回归模型为:
    h θ ( x ( i ) ) = θ 0 + θ 1 x 1 ( i ) + θ 2 x 2 ( i ) + . . . + θ n x n ( i ) h_{ heta}( x^{(i)}) = heta_{0} + heta_{1}x_{1}^{(i)} + heta_{2}x_{2}^{(i)} +...+ heta_{n}x_{n}^{(i)} hθ(x(i))=θ0+θ1x1(i)+θ2x2(i)+...+θnxn(i)

    即我们变量是n维的,对每个维度上都加了个权重,求所有维度上的带权和然后加上一个偏置项就是我们的回归函数。而我们的目的就是求出 Θ 0 . . . Θ n Theta_{0}...Theta_{n} Θ0...Θn这n+1个参数。
    定义代价函数
    J ( θ ) = 1 2 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 J( heta) = frac{1}{2m}sum_{i=1}^{m}(h_{ heta}( x^{(i)})-y^{(i)})^{2} J(θ)=2m1i=1m(hθ(x(i))y(i))2
    这个代价函数就是预测值与实际值之间的距离的平方,m是样本的个数,求个平均更准确点嘛。分母的2是为跟后面平方项求导后的2约掉。
    在程序中,多变量的运算都是通过矩阵来完成的,所以我们要将上述式子写成矩阵相乘的式子:
    我们用 Θ Theta Θ来表示 [ Θ 0 , . . . , Θ n ] [Theta_{0},...,Theta_{n}] [Θ0,...,Θn],用 X 来 表 示 [ 0 , x 1 , . . . , x n ] X来表示[0,x_{1},...,x_{n}] X[0,x1,...,xn]
    这样,原来的回归模型就可以写成:
    h Θ ( X ) = X Θ h_{Theta}( X) = XTheta hΘ(X)=XΘ
    原来的代价函数可以写成:
    J ( Θ ) = 1 2 m ( X Θ − Y ) T ( X Θ − Y ) J(Theta) = frac{1}{2m}(XTheta-Y)^{T}(XTheta-Y) J(Θ)=2m1(XΘY)T(XΘY)
    上述两式子中的变量全为矩阵表示。
    将代价函数对我们要求的参数 Θ Theta Θ求一阶导数得:
    ▽ J ( Θ ) = 1 m ( X Θ − Y ) X igtriangledown J(Theta) = frac{1}{m}(XTheta-Y) X J(Θ)=m1(XΘY)X
    这个一阶导数就是我们每次更新参数时需要的梯度。这样我们就从一元变量扩展到了多元变量上。可以对含有多元参数的目标函数利用梯度下降法求出最优解。
    代码实现:

    import numpy as np
    
    
    row = 20
    x0 = np.zeros((row,1))
    x1 = np.arange(0,row+0).reshape(row,1)
    x2 = np.arange(10,row+10).reshape(row,1)
    x3 = np.arange(21,row+21).reshape(row,1)
    x = np.hstack((x1,x2,x3))
    y = 2*x1 +3*x2 + 4*x3 + np.random.random(row).reshape(row,1)
    
    #定义代价函数
    def error_function(theta, x, y):
        diff = np.dot(x, theta) - y
        return (1./2*row) * np.dot(np.transpose(diff), diff)
    
    #求梯度的函数
    def gradient_function(theta, x, y):
        diff = np.dot(x, theta) - y
        return (1./row) * np.dot(np.transpose(x), diff)
    
    
    #利用梯度下降法不断迭代参数
    def gradient_descent(x, y, alpha):
        theta = np.array([1, 1, 1]).reshape(3, 1)
        gradient = gradient_function(theta, x, y)
        while not np.all(np.absolute(gradient) <= 1e-5):
            theta = theta - alpha * gradient
            gradient = gradient_function(theta, x, y)
            # print(gradient)
        return theta
    
    alpa = 0.001
    theta = gradient_descent(x,y,alpa)
    print(theta)

     

    输出结果:

    [[1.        ]
     [1.97155845]
     [2.96137676]
     [4.05017691]]

     

    可以看到这个跟我们设定函数时x0,x1,x2,x3是非常接近的。

    注意

    上述代码中 ,学习率为0.001,把学习率改成1会发生什么呢,自己试试看,会发现程序会一直运行不停止,打印出梯度会发现,梯度一直增加最终变成了无限大。
    这是因为,如果学习率过大,会导致不收敛,因为跨的步数太大,会越过那个最低点,并一直震荡。至于为什么梯度会变得越来越大以至于无限大,可以举个例子,函数 y = 2 x 2 y=2x^{2} y=2x2,其一阶导数为 y = 4 x y =4x y=4x
    在这里插入图片描述

    在A(10,200)点,梯度为40,所以下一时刻到B点的横坐标为10-140= -30,
    在B(-30,1800)点,梯度为-120,所以下一时刻到达的点的横坐标为-30+1
    120=90,这样会导致离最优值越来越远。
    所以:

    • 学习率太大会导致不收敛
    • 学习率太小会导致到达最低点的迭代次数太大,费时
     
  • 相关阅读:
    【CF536D】Tavas in Kansas(博弈+动态规划)
    【CF643F】Bears and Juice(信息与可区分情况数)
    【AT3981】[ARC093D] Dark Horse(容斥+状压DP)
    【CF708E】Student's Camp(动态规划)
    【洛谷6775】[NOI2020] 制作菜品(思维好题)
    【洛谷2282】[HNOI2003] 历史年份(线段树优化DP)
    【洛谷5068】[Ynoi2015] 我回来了(线段树)
    【洛谷4117】[Ynoi2018] 五彩斑斓的世界(第二分块)
    【洛谷3745】[六省联考2017] 期末考试(水题)
    【AtCoder】AtCoder Grand Contest 050 解题报告(A~D)
  • 原文地址:https://www.cnblogs.com/xiondun/p/13725318.html
Copyright © 2011-2022 走看看