美文网首页
机器学习理论系列2——梯度下降法

机器学习理论系列2——梯度下降法

作者: 刺猬ciwei_532a | 来源:发表于2017-09-23 21:57 被阅读0次

    什么是优化算法

    优化算法要求解的,是一个问题的最优解或者近似最优解。在机器学习中,有很多问题都是优化问题,即我们要求出输入特征和标签之间的映射关系,并且我们一定是期望,通过这个映射关系得到的标签结果,和实际标签之间的误差最小。

    机器学习中,优化算法有很多种,最基本的,也是应用非常广泛的,就是梯度上升/下降,此外还有遗传算法等。

    什么是梯度下降

    当我们得到一个目标函数之后,如何求解它的参数?直接求解?并不一定可解,线性回归算是一个特例(使用最小二乘法求解)。

    梯度上升/下降,是机器学习中求解无约束优化问题时,最常用的方法之一。
    它的套路是,喂给机器一堆数据,告诉它什么样的方式是对的(目标函数),然后让它自己朝着这个方向去做。

    那么怎么知道【方向】呢?这个方向,就是我们说的梯度。在微积分里边,对多元函数的参数求∂偏导数,把求得的偏导数用向量表示出来,就是梯度。沿着梯度的方向,函数值的变化最快。

    所以,如果我们要求损失函数的最大值,就采用梯度上升的方法,沿着梯度方向一步步迭代,得到最大值;反之,如果我们要求损失函数的最小值,就采用梯度下降,沿着梯度的反方向,一步步迭代,得到最小值。

    所以,梯度下降法,就是一个用于【寻找最小化损失函数的参数值】的【最优化算法】。

    梯度下降的视觉直观解释

    我们把下面的图形,想象成两座山,假设我们站在【Initial Condition】这个山顶点,我们想下到山的最底部,但是不知道往哪个方向走最快。于是我们每走一步,都计算一下当前所在位置的梯度,即最陡峭、下山最快的方向,然后沿着这个方向走。这样走一步算一步,最终就走到了山底。这就是梯度下降法,它的要点是:【梯度】和【迭代】,即沿着函数值变化最快的方向,每走一步,计算一次,不断迭代,从而找到最优解。

    梯度下降

    当然按照梯度下降法走下去,我们不一定走到了两座山的最低点(图中的Global Minimum),而是走到了一个局部最低点(图中次低点)。所以梯度下降法得到的不一定是全局最优解,而是局部最优解。

    不过机器学习中我们遇到的很多损失函数,都是凸函数,如线性回归对应的就是凸函数。如果只有一个特征变量,凸函数的形状类似于下面的图形,分别为下凸和上凸:

    如果有两个特征变量,则类似于下面这个碗的造型。如果是凸函数,采用梯度上升/下降法,得到的一定是全局最优解。

    最小二乘法和梯度下降法的关系

    最小二乘法的目标是,求解最小误差平方和,有两种形式:线性和非线性;线性的解可以直接用数学方法推导出来,也可以用迭代的方法求解;非线性的解,需要用迭代的方法求解。
    梯度下降法是一种迭代求解的方法,可以用来求解最小二乘问题(线性和非线性的都可以)。

    梯度下降相关概念

    1. 步长:在神经网络中也叫学习速率(Learning Rate),步长决定了在在梯度下降迭代过程中,每一步沿着梯度负方向前进的长度。

    2. 损失函数:也叫成本函数;用来度量拟合的程度,损失函数极小化,意味着拟合程度最好,对应的模型参数即为最优解。损失函数的定义如下:

    损失函数

    其中m代表样本数量,1/m是为了平均化,因为如果m=100,右边的平方和所得结果,肯定比m=1000的时候小很多,但这并不能代表m=100的时候计算所得参数值要优于m=1000的时候的参数值。所以这里取平均值,消除这个影响。

    特征数据归一化

    样本的特征取值范围可能都不一样,这可能导致迭代速度很慢。但是不能因为想要加速下降速度,就把下降步伐调整过大,否则找到函数最小值的速度反而容易变慢,出现overshoot the minimum的现象,即如下图所示:

    overshoot the minimum

    为了加快迭代速度,我们可以采用Feature Scaling的方法,对特征数据进行归一化处理,来加速下降的执行速度。即将各个特征值标准化,使他们的取值范围都在(-1,1)之间。这样迭代速度会大大加快。

    常用的方法是均值归一化(Mean Normalization),即:

    均值归一化

    或者求标准分(Standard Score),即:

    标准化

    算法流程

    1. 初始化:初始化θ参数,步长α,终止距离ε

    2. 循环操作:

      2.1 计算当前位置的损失函数对应的梯度,通过求损失函数的偏导获得:
      2.2 步长 * 损失函数的梯度 = 当前位置下降的距离;

      2.3 判断是否所有的θ参数,梯度下降的距离都小于ε,如果是,则算法终止;否则进入下一步;

      2.4 更新所有θ参数,更新表达式如下:
    3. 输出最优解

    梯度下降的三种方式

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

    批量梯度下降法,即在计算梯度时,使用所有的样本数据来计算。如果我们有m个样本,求梯度的时候,就用到m个样本的梯度数据。

    这种方法容易得到最优解。但是每次都要考虑所有的样本数据,迭代速度非常慢。尤其是在样本数据量巨大的时候。

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

    和批量梯度下降法的区别,仅仅在于,在求梯度时,没有用到所有样本的数据,而是随机选取其中一个样本来计算梯度。

    这种方法的优点是迭代速度很快。但是每次只选择一个样本,所以不一定每次都是朝着全局最优的方向,不过大方向是朝着全局最优的。

    小批量梯度下降法 MBGD(Mini-Batch Gradient Descent)

    这是最实用的一种方法,综合了批量和随机的特点,每次选择一小批样本数据(32,64,128比较常见)来计算平均梯度的更新方向。

    三种算法的Python实现和说明

    假设我们有这样的样本数据:

    x1 x2 y
    1 4 19
    2 5 26
    5 1 19
    4 2 29
    3 5 29
    8 1 28
    7 2 29
    1 2 11
    6 2 24
    9 3 39
    我们需要一个函数来拟合上面的数据,这个函数为:

    我们的目标是求出θ1和θ2,让h(θ)尽量逼近实际值y。

    我们结合Python和实际案例,来说明一下三种算法。参考自:批量梯度下降(BGD)、随机梯度下降(SGD)、小批量随机梯度下降(MSGD)实现过程详解

    批量梯度下降法

    #BGD
    input_x = [[1,4], [2,5], [5,1], [4,2],[3,5],[8,1],[7,2],[1,2],[6,2],[9,3]]  #输入
    y = [19,26,19,20,28,25,27,13,28,37]   #输出
    theta = [1,1]       #θ参数初始化
    loss = 10           #loss先定义一个数,为了进入循环迭代
    step_size = 0.01    #步长
    eps =0.0001         #精度要求
    max_iters = 10000   #最大迭代次数
    error =0            #损失值
    iter_count = 0      #当前迭代次数
    
    err1=[0,0,0,0,0,0,0,0,0,0]      #求Θ1梯度的中间变量1
    err2=[0,0,0,0,0,0,0,0,0,0]      #求Θ2梯度的中间变量2
    
    while(loss > eps and iter_count < max_iters):
        loss = 0
        err1num = 0
        err2num = 0
        for i in range(10):    #我们共有10个样本,每次迭代所有样本计算梯度
            pred_y = theta[0]*input_x[i][0] + theta[1]*input_x[i][1]    #第i个样本对应的预测值
            err1[i] = (pred_y - y[i]) * input_x[i][0]               
            err2[i] = (pred_y - y[i]) * input_x[i][1]                 
            err1num = err1num + err1[i]                                 #Θ1对应的梯度    
            err2num = err2num + err2[i]                                 #Θ2对应的梯度 
            
        theta[0] = theta[0] - step_size * err1num/10                    #更新Θ1对应的梯度 
        theta[1] = theta[1] - step_size * err2num/10                    #更新Θ2对应的梯度
        
        for i in range(10):
            pred_y = theta[0]*input_x[i][0] + theta[1]*input_x[i][1]    #更新Θ1和Θ2之后重新计算预测值
            error = (1/(2*10))*(pred_y - y[i])**2                       #计算损失值
            loss = loss + error
        
        iter_count += 1
    
    print('theta:', theta)
    print('final loss:', loss)
    print('iter counts:', iter_count)
    

    得到结果为:
    theta: [2.798690040454637, 4.119758556475943]
    final loss: 0.9069318692609009
    iter counts: 10000

    随机梯度下降法

    #SGD
    input_x = [[1,4], [2,5], [5,1], [4,2],[3,5],[8,1],[7,2],[1,2],[6,2],[9,3]]  #输入
    y = [19,26,19,20,28,25,27,13,28,37]   #输出
    theta = [1,1]       #θ参数初始化
    loss = 10           #loss先定义一个数,为了进入循环迭代
    step_size = 0.01    #步长
    eps =0.0001         #精度要求
    max_iters = 1000000   #最大迭代次数
    error =0            #损失值
    iter_count = 0      #当前迭代次数
    
    err1=[0,0,0,0,0,0,0,0,0,0]      #求Θ1梯度的中间变量1
    err2=[0,0,0,0,0,0,0,0,0,0]      #求Θ2梯度的中间变量2
    
    while(loss > eps and iter_count < max_iters):
        loss = 0
        err1num = 0
        err2num = 0
        i = random.randint(0,3)    #随机选取10个样本中的一个,由于样本数增加,导致迭代次数增多,这里缩减为从前4个样本中取数
        pred_y = theta[0]*input_x[i][0] + theta[1]*input_x[i][1]    #计算选取的样本对应的预测值
        err1num = (pred_y - y[i]) * input_x[i][0]                   #Θ1对应的梯度  
        err2num = (pred_y - y[i]) * input_x[i][1]                   #Θ2对应的梯度 
            
        theta[0] = theta[0] - step_size * err1num                   #更新Θ1对应的梯度 
        theta[1] = theta[1] - step_size * err2num                   #更新Θ2对应的梯度
        
        for i in range(4):
            pred_y = theta[0]*input_x[i][0] + theta[1]*input_x[i][1]#更新Θ1和Θ2之后重新计算预测值
            error = (1/2)*(pred_y - y[i])**2                        #计算损失值
            loss = loss + error
        
        iter_count += 1
    
    print('theta:', theta)
    print('final loss:', loss)
    print('iter counts:', iter_count)
    

    计算所得结果:
    theta: [3.001936311335262, 3.9976736608405257]
    final loss: 8.908461998310991e-05
    iter counts: 122

    小批量梯度下降法

    #MBGD
    input_x = [[1,4], [2,5], [5,1], [4,2],[3,5],[8,1],[7,2],[1,2],[6,2],[9,3]]  #输入
    y = [19,26,19,20,28,25,27,13,28,37]   #输出
    theta = [1,1]       #θ参数初始化
    loss = 10           #loss先定义一个数,为了进入循环迭代
    step_size = 0.01    #步长
    eps =0.0001         #精度要求
    max_iters = 100000   #最大迭代次数
    error =0            #损失值
    iter_count = 0      #当前迭代次数
    
    err1=[0,0,0,0,0,0,0,0,0,0]      #求Θ1梯度的中间变量1
    err2=[0,0,0,0,0,0,0,0,0,0]      #求Θ2梯度的中间变量2
    
    while(loss > eps and iter_count < max_iters):
        loss = 0
        err1num = 0
        err2num = 0
        #这里总体样本取前4个,每批次选取其中两个样本
        i = random.randint(0,3)    #缩减为从前4个样本中随机抽取一个样本
        j = (i+1)%4                #选取与i相邻的样本为第二个样本
        pred_yi = theta[0]*input_x[i][0] + theta[1]*input_x[i][1]    #计算选取的样本i对应的预测值
        pred_yj = theta[0]*input_x[j][0] + theta[1]*input_x[j][1]    #计算选取的样本j对应的预测值
        err1num = (pred_yi - y[i]) * input_x[i][0] + (pred_yj - y[j]) * input_x[j][0]    #Θ1对应的梯度  
        err2num = (pred_yi - y[i]) * input_x[i][1] + (pred_yj - y[j]) * input_x[j][1]    #Θ1对应的梯度  
            
        theta[0] = theta[0] - step_size * (1/2) * err1num                   #更新Θ1对应的梯度 
        theta[1] = theta[1] - step_size * (1/2) * err2num                   #更新Θ2对应的梯度
        
        for i in range(4):
            pred_y = theta[0]*input_x[i][0] + theta[1]*input_x[i][1]#更新Θ1和Θ2之后重新计算预测值
            error = (1/2*2)*(pred_y - y[i])**2                        #计算损失值
            loss = loss + error
        
        iter_count += 1
    
    print('theta:', theta)
    print('final loss:', loss)
    print('iter counts:', iter_count)
    

    计算所得结果:
    theta: [3.0015170025160156, 3.9983740403913126]
    final loss: 9.42763188681316e-05
    iter counts: 116

    相关文章

      网友评论

          本文标题:机器学习理论系列2——梯度下降法

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