美文网首页
局部搜索之梯度下降法

局部搜索之梯度下降法

作者: Byte猫 | 来源:发表于2019-04-24 13:27 被阅读0次

    在各种最优化算法中,梯度下降法是最常见的一种,在深度学习的训练中被广为使用。

    梯度下降法的场景假设
    梯度下降法的基本思想可以类比为一个下山的过程。
    假设这样一个场景:一个人被困在山上,需要从山上下来。由于此时山上的浓雾很大,导致可视度很低,因此,下山的路径就无法一次性确定,他必须利用自己周围的信息去找到下山的路径。具体来说就是以他当前的所处的位置为基准,寻找这个位置最陡峭的地方,然后朝着山的高度下降的地方走。


    梯度下降算法的基本过程就和下山的场景很类似。通过定义损失函数,将误差初始值当做“山顶高度”,每次改变参数观察当前最新的“高度”是否比“山顶高度”小而且下降最大。反复迭代直到“高度”不再降低。
    概括来说,山的高度就是误差的大小,为了顺利抵达山脚(拟合),总要向着能使得所处海拔更低的方向(参数)走。

    梯度下降法的搜索迭代示意图如下图所示:


    存在三种梯度下降的变种,他们不同之处在于我们在计算目标函数梯度时所用数据量的多少。依据数据的规模,我们在更新参数的准确性和执行一次更新所用时间之间进行一种折中。


    三条线是三种梯度下降方法每下降一次的路线,蓝色是Batch Gradient Descent,紫色是Stochastic Gradient Descent,绿色是Mini-batch Gradient Descent

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

    它是最基本的梯度下降法,也称批量梯度下降,每次利用全部的训练数据计算目标函数的梯度来更新参数。
    优点:
      (1)一次迭代是对所有样本进行计算,此时利用矩阵进行操作,实现了并行。
      (2)由全数据集确定的方向能够更好地代表样本总体,从而更准确地朝向极值所在的方向。当目标函数为凸函数时,BGD一定能够得到全局最优。
    缺点:
      (1)当样本数目 m 很大时,每迭代一步都需要对所有样本计算,训练过程会很慢。

    # coding=utf-8
    import numpy as np
    import matplotlib.pyplot as plt
    import math
    
    #========================================================
    #  参数设置
    #========================================================
    
    # 学习率
    learning_rate = 0.001
    # 迭代次数
    n_epochs = 50000
    # 设置阈值
    epsilon = 1e-5
    #========================================================
    #  生成数据集
    #========================================================
    
    # 构造训练数据集
    x = np.array([[2, 0., 3], [3, 1., 3], [0, 2., 3], [4, 3., 2], [1, 4., 4]])
    
    # 构建一个权重作为数据集的真正的权重
    theta0 = np.array([[2 ,3, 4]]).T
    # 构建标签数据集y=t1*x1+t2*x2+t3*x3+b 即y=x*theta+b, 这里b=2
    y_train = x.dot(theta0) + np.array([[2],[2],[2],[2],[2]]) + np.random.randn(1)
    
    # 构建一个len(x)行1列的单位矩阵x0,然它和x组合,形成[x0, x1, x2, x3],x0=1的数据形式
    # 这样可以将y=t1*x1+t2*x2+t3*x3+b变成y=b*x0+t1*x1+t2*x2+t3*x3即y=x*theta,其中theta应该为[b, *, *, *],则要拟合的theta应该是[2,2,3,4]
    x0 = np.full((len(x), 1), 1)
    X_train = np.hstack([x0, x])
    
    #========================================================
    #  批量梯度下降算法
    #========================================================
    
    def batch_gradient_descent(X_train, y_train):
        '''
        批量梯度下降算法的实现
        INPUT -> 输入, 目标 
        '''
        lr = learning_rate
        # 初始化迭代次数
        count = 0
        # 初始化theta
        theta = np.random.randn(X_train.shape[1], 1)   
        before_theta = np.zeros((X_train.shape[1], 1))
    
        for epoch in range(n_epochs):
            count += 1
            error = np.dot(X_train, theta) - y_train
            gradient = np.dot(X_train.T, error) / X_train.shape[0]
            # 参数更新
            theta = theta - learning_rate * gradient
    
            # theta-before_theta表示前后两个梯度的变化,当梯度变化很小(在接收的范围内)时,便停止迭代
            if np.linalg.norm(theta - before_theta) < epsilon:
                print(count)
                break
            else:
                before_theta = theta
         
        return theta
    
    #========================================================
    #  主程序
    #========================================================
    if __name__ == '__main__':
        optimal = batch_gradient_descent(X_train, y_train)
        print(optimal)
    

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

    随机梯度下降法不同于批量梯度下降,随机梯度下降是每次迭代使用一个样本来对参数进行更新。使得训练速度加快。
    优点:
      (1)由于不是在全部训练数据上的损失函数,而是在每轮迭代中,随机优化某一条训练数据上的损失函数,这样每一轮参数的更新速度大大加快。
    缺点:
      (1)准确度下降。由于即使在目标函数为强凸函数的情况下,SGD仍旧无法做到线性收敛。
      (2)可能会收敛到局部最优,由于单个样本并不能代表全体样本的趋势。
      (3)不易于并行实现。

    # coding=utf-8
    import numpy as np
    import matplotlib.pyplot as plt
    import math
    
    #========================================================
    #  参数设置
    #========================================================
    
    # 学习率
    learning_rate = 0.0001
    # 迭代次数
    n_epochs = 5000
    # 设置阈值
    epsilon = 1e-5
    #========================================================
    #  生成数据集
    #========================================================
    
    # 构造训练数据集
    x = np.array([[2, 0., 3], [3, 1., 3], [0, 2., 3], [4, 3., 2], [1, 4., 4]])
    
    # 构建一个权重作为数据集的真正的权重
    theta0 = np.array([[2 ,3, 4]]).T
    # 构建标签数据集y=t1*x1+t2*x2+t3*x3+b 即y=x*theta+b, 这里b=2
    y_train = x.dot(theta0) + np.array([[2],[2],[2],[2],[2]]) + np.random.randn(1) 
    
    # 构建一个len(x)行1列的单位矩阵x0,然它和x组合,形成[x0, x1, x2, x3],x0=1的数据形式
    # 这样可以将y=t1*x1+t2*x2+t3*x3+b变成y=b*x0+t1*x1+t2*x2+t3*x3即y=x*theta,其中theta应该为[b, *, *, *],则要拟合的theta应该是[2,2,3,4]
    x0 = np.full((len(x), 1), 1)
    X_train = np.hstack([x0, x])
    
    #========================================================
    #  随机梯度下降算法
    #========================================================
    
    def stochastic_gradient_descent(X_train, y_train):
        '''
        随机梯度下降算法的实现
        INPUT -> 输入, 目标 
        '''
        lr = learning_rate
        # 初始化迭代次数
        count = 0
        # 初始化theta
        theta = np.random.randn(X_train.shape[1], 1)   
        before_theta = np.zeros((X_train.shape[1], 1))
    
        for epoch in range(n_epochs):
            count += 1
            gradient = np.zeros((X_train.shape[1], 1))
            
            # 随机选取一条样本计算梯度
            for i in range(X_train.shape[0]):
                gradient = np.dot(X_train[i], theta)-y_train[i]
                theta = theta - learning_rate * gradient
            
            # theta-before_theta表示前后两个梯度的变化,当梯度变化很小(在接收的范围内)时,便停止迭代
            if np.linalg.norm(theta - before_theta) < epsilon:
                print(count)
                break
            else:
                before_theta = theta
         
        return theta
    
    #========================================================
    #  主程序
    #========================================================
    if __name__ == '__main__':
        optimal = stochastic_gradient_descent(X_train, y_train)
        print(optimal)
    

    3、小批量梯度下降法(Mini-batch Gradient Descent,MBGD)

    小批量梯度下降,是对批量梯度下降以及随机梯度下降的一个折中办法。其思想是:每次使用batch_size个样本来对参数进行更新。以batch_size为64为例,如下图所示:


    # coding=utf-8
    import numpy as np
    import matplotlib.pyplot as plt
    import math
    
    #========================================================
    #  参数设置
    #========================================================
    
    # 学习率
    learning_rate = 0.0001
    # 迭代次数
    n_epochs = 5000
    # 设置阈值
    epsilon = 1e-5
    # 设置小批量的样本数
    minibatch_size= 2
    #========================================================
    #  生成数据集
    #========================================================
    
    # 构造训练数据集
    x = np.array([[2, 0., 3], [3, 1., 3], [0, 2., 3], [4, 3., 2], [1, 4., 4]])
    
    # 构建一个权重作为数据集的真正的权重
    theta0 = np.array([[2 ,3, 4]]).T
    # 构建标签数据集y=t1*x1+t2*x2+t3*x3+b 即y=x*theta+b, 这里b=2
    y_train = x.dot(theta0) + np.array([[2],[2],[2],[2],[2]]) + np.random.randn(1)
    
    # 构建一个len(x)行1列的单位矩阵x0,然它和x组合,形成[x0, x1, x2, x3],x0=1的数据形式
    # 这样可以将y=t1*x1+t2*x2+t3*x3+b变成y=b*x0+t1*x1+t2*x2+t3*x3即y=x*theta,其中theta应该为[b, *, *, *],则要拟合的theta应该是[2,2,3,4]
    x0 = np.full((len(x), 1), 1)
    X_train = np.hstack([x0, x])
    
    #========================================================
    #  批量梯度下降算法
    #========================================================
    
    def minibatch_gradient_descent(X_train, y_train):
        '''
        小批量梯度下降算法的实现
        INPUT -> 输入, 目标 
        '''
        lr = learning_rate
        # 初始化迭代次数
        count = 0
        # 初始化theta
        theta = np.random.randn(X_train.shape[1], 1)   
        before_theta = np.zeros((X_train.shape[1], 1))
    
        for epoch in range(n_epochs):
            count += 1
            gradient = np.zeros((X_train.shape[1], 1))
            i = 0
            while i+minibatch_size <= X_train.shape[0]:
                batch_error = X_train[i: i+minibatch_size].dot(theta) - y_train[i: i+minibatch_size]
                gradient = np.dot(X_train[i: i+minibatch_size].T, batch_error) / X_train[i: i+minibatch_size].shape[0]
                theta = theta - learning_rate * gradient
                i += minibatch_size
    
            # 当theta-before_theta便表示前后两个梯度的变化,当梯度变化很小(在接收的范围内)时,便停止迭代
            if np.linalg.norm(theta - before_theta) < epsilon:
                print(count)
                break
            else:
                before_theta = theta
         
        return theta
    
    #========================================================
    #  主程序
    #========================================================
    if __name__ == '__main__':
        optimal = minibatch_gradient_descent(X_train, y_train)
        print(optimal)
    

    https://blog.csdn.net/u013963380/article/details/82287696
    https://blog.csdn.net/huwenxing0801/article/details/85627245
    https://www.cnblogs.com/maybe2030/p/4751804.html
    https://baijiahao.baidu.com/s?id=1613121229156499765&wfr=spider&for=pc

    相关文章

      网友评论

          本文标题:局部搜索之梯度下降法

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