美文网首页
SGD、Adam优化器

SGD、Adam优化器

作者: 潇萧之炎 | 来源:发表于2019-09-20 00:47 被阅读0次

    优化器

    https://blog.csdn.net/yukinoai/article/details/84198218(博客 全)
    https://blog.csdn.net/weixin_40170902/article/details/80092628
    https://www.jianshu.com/p/ee39eca29117(简书 损失函数)
    https://www.cnblogs.com/wyuzl/p/7645602.html(BGD实例)
    1.优化损失函数
    损失函数:为了评估模型拟合的好坏,通常用损失函数来度量拟合的程度。损失函数极小化,意味着拟合程度最好,对应的模型参数即为最优参数。在线性回归中,损失函数通常为样本输出和假设函数的差取平方。
    优化损失函数说明了就是想让损失函数收敛到了一定的值,这样模型才是最优的。
    梯度下降优化法经历了SGD→SGDM→NAG→AdaGrad→AdaDelta→Adam→Nadam 这样的发展历程。之所以会不断地提出更加优化的方法,是引入了动量Momentum概念。

    2.梯度下降法调优
    梯度下降法就好比一个蒙着眼睛的人下山,每次在负梯度最大的方向,向前走一步,走出一步后,比较前后的的落差,
    若落差小于一定阈值,则认为到达山谷,若落差大于阈值,则继续向前走,直到到达山谷。

    在梯度下降法中调优比较重要的是3个因素,步长、初始值、归一化
    (1)步长:又称学习率,决定了在梯度下降迭代的过程中,每一步沿梯度负方向前进的长度。
    步长太小,收敛慢,步长太大,会远离最优解。所以需要从小到大,分别测试,选出一个最优解。
    (2)初始值:随机选取初始值,当损失函数是非凸函数时,找到的解可能是局部最优解,需要多测试几次,
    从局部最优解中选出最优解。当损失函数是凸函数时,得到的解就是最优解。
    (3)归一化:如果不归一化,会收敛的很慢,会形成之字的路线。

    3.BGD SDG MBGD
    批量梯度下降法BGD
    gradient = np.dot(xTrains, loss) / m #对所有的样本进行求和,然后除以样本数
    theta = theta - alpha * gradient
    随机梯度下降
    gradient = loss[index1]*x[index1] #只取这一个点进行更新计算
    theta = theta - alpha * gradient.T
    BGD
    计算梯度时使用所有的样本,这样每次算出来的梯度都是当前最优的方向。
    优点:迭代次数少; 若损失函数为凸函数,能够保证收敛到全局最优解;若为非凸函数,能够收敛到局部最优值(结果的准确度)
    缺点:训练速度慢(时间,每一次训练需要的时间);需要内存大(空间);不支持在线更新
    SGD:
    和BGD类似,区别在与求梯度时没有用所有的m个样本的数据,而是仅仅选取一个样本j来求梯度
    优点:训练速度快; 支持在线更新; 有几率跳出局部最优解
    缺点:容易收敛到局部最优,并且容易被困在鞍点; 迭代次数多

    4.牛顿法
    基本思想是对损失函数的二阶泰勒展开进行求导。本质上牛顿法是二阶收敛,梯度下降是一阶收敛,所以牛顿法就更快。
    梯度下降法每次只从你当前所处位置选一个坡度最大的方向走一步,牛顿法在选择方向时,不仅会考虑坡度是否够大,还会考虑你走了一步之后,
    坡度是否会变得更大。所以,可以说牛顿法比梯度下降法看得更远一点,能更快地走到最底部。
    (牛顿法目光更加长远,所以少走弯路;相对而言,梯度下降法只考虑了局部的最优,没有全局思想。)

    5.Momentum [mə'mentəm] 动量优化器
    Momentum旨在加速学习,特别是处理高曲率、小但一致的梯度,或带噪音的梯度。
    Momentum算法会观察历史梯度(动量),若当前梯度的方向与历史梯度一致(表明当前样本不太可能为异常点),
    则会增强这个方向的梯度,若当前梯度与历史梯方向不一致,则梯度会衰减。

    形象理解:一个球推下山,球在下坡时积累惯性(动量),在途中若球运动方向不变,因为惯性球会越来越快,若球的方向发生变化,因为惯性球的速度会变慢。
    加入的这一项,可以使得梯度方向不变的维度上速度变快,梯度方向有所改变的维度上的更新速度变慢,这样就可以加快收敛并减小震荡。
    超参数设定值: 一般 γ 取值 0.9 左右。
    缺点:相当于盲目地沿着坡滚,如果它能具备一些先知,例如快要上坡时,就知道需要减速了的话,适应性会更好。

    6.NAG(Nesterov Momentum)
    Momentum方法中梯度方向由积累的动量和当前梯度方法共同决定,与其看当前梯度方向,不妨先看看跟着积累的动量走一步是什么情况,再决定怎么走。
    在小球向下滚动的过程中,我们希望小球能够提前知道在哪些地方坡面会上升,这样在遇到上升坡面之前,小球提前就开始减速,就不容易陷入局部最优解。

    7.Adagrad(Adaptive gradient algorithm)
    自适应梯度法。它通过记录每次迭代过程中的前进方向和距离,从而使得针对不同问题,有一套自适应调整学习率的方法,
    对于出现频率较低参数采用较大的α更新;相反,对于出现频率较高的参数采用较小的α更新。

    8.RMSprop
    Adagrad会累加之前所有的梯度平方,而RMSprop仅仅是计算对应的平均值,因此可缓解Adagrad算法学习率下降较快的问题。

    9.Adam
    Adam是另一种自适应学习率的方法。总结以上算法,以SGD作为最初的算法,Momentum在其基础上加入了一阶动量(历史梯度的累计),
    AdaGrad和RMSProp在其基础上加入了二阶动量(历史梯度的平方累计),Adam就是结合了一阶动量和二阶动量算法。

    10.Nadam
    Adam是集大成者,而Nadam = Adam + NAG。

    梯度下降代码实现

    import numpy as np
    import random
    
    #下面实现的是批量梯度下降法
    def batchGradientDescent(x, y, theta, alpha, m, maxIterations):
        xTrains = x.transpose()                             #得到它的转置
        # np.dot矩阵乘法
        # theta1 =  [1. 1. 1.], x=10*3 
        for i in range(0, maxIterations):
            hypothesis = np.dot(x, theta)
            # 最后收敛:hypothesis(y预测值) =  [2.5 3.2 3.9 4.6 5.3 6.  6.7 7.4 8.1 8.8]
            # loss =[ 1.77635684e-15  1.33226763e-15  8.88178420e-16  1.77635684e-15 8.88178420e-16  0.00000000e+00 -8.88178420e-16 -1.77635684e-15 0.00000000e+00 -1.77635684e-15]
            loss = hypothesis - y
            gradient = np.dot(xTrains, loss) / m             #对所有的样本进行求和,然后除以样本数
            theta = theta - alpha * gradient
        return theta
     
     #下面实现的是随机梯度下降法
    def StochasticGradientDescent(x, y, theta, alpha, m, maxIterations):
        data = []
        for i in range(10):
            data.append(i)
        xTrains = x.transpose()     #变成3*10,每一列代表一个训练样本
         # 这里随机挑选一个进行更新点进行即可(不用像上面一样全部考虑)
        for i in range(0,maxIterations):
            hypothesis = np.dot(x, theta)
            loss = hypothesis - y                   #注意这里有10个样本的,我下面随机抽取一个进行更新即可
            index = random.sample(data,1)           #任意选取一个样本点,得到它的下标,便于下面找到xTrains的对应列
            # 从data中随机获取1个元素,作为一个slice片断返回,即0-9中的一个。index=[8], index=8
            index1 = index[0]                       #因为回来的时候是list,我要取出变成int,更好解释
            gradient = loss[index1]*x[index1]       #只取这一个点进行更新计算
            theta = theta - alpha * gradient.T
        return theta
     
    def predict(x, theta):
        m, n = np.shape(x)
        xTest = np.ones((m, n+1))                     #在这个例子中,是第三列放1
        xTest[:, :-1] = x                             #前俩列与x相同
        res = np.dot(xTest, theta)                    #预测这个结果
        return res
     
    # 待训练数据A、B为自变量,C为因变量。
    # 希望通过这些训练数据给我训练出一个线性模型,用于进行下面数据的预测,test集合如下:
    # 比如我们给出(3.1,5.5)希望模型预测出来的值与我们给定的9.5的差别是多少?
    # 这不是重点,重点是我们训练模型过程中的参数更新方法
    trainData = np.array([[1.1,1.5,1],[1.3,1.9,1],[1.5,2.3,1],[1.7,2.7,1],[1.9,3.1,1],[2.1,3.5,1],[2.3,3.9,1],[2.5,4.3,1],[2.7,4.7,1],[2.9,5.1,1]])
    trainLabel = np.array([2.5,3.2,3.9,4.6,5.3,6,6.7,7.4,8.1,8.8])
    # 原来的数据是10行3列,这里进行转置,变成3行10列
    # 预处理中自动加1,偏置项,可以理解为常数项b
    m, n = np.shape(trainData)
    # m=10,n=3,theta=[1,1,1]
    theta = np.ones(n)
    alpha = 0.1
    maxIteration = 5000  # 最大迭代次数
    #下面返回的theta就是学到的theta
    theta = batchGradientDescent(trainData, trainLabel, theta, alpha, m, maxIteration)
    print("theta = ",theta)
    
    x = np.array([[3.1, 5.5], [3.3, 5.9], [3.5, 6.3], [3.7, 6.7], [3.9, 7.1]])
    print(predict(x, theta))
    theta = StochasticGradientDescent(trainData, trainLabel, theta, alpha, m, maxIteration)
    print("theta = ",theta)
    x = np.array([[3.1, 5.5], [3.3, 5.9], [3.5, 6.3], [3.7, 6.7], [3.9, 7.1]])
    print(predict(x, theta))
    #yes,is the code
    

    相关文章

      网友评论

          本文标题:SGD、Adam优化器

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