zoukankan      html  css  js  c++  java
  • cs231n笔记:最优化

    本节是cs231学习笔记:最优化,并介绍了梯度下降方法,然后应用到逻辑回归中

    引言

      在上一节线性分类器中提到,分类方法主要有两部分组成:1.基于参数的评分函数。能够将样本映射到类别的分值。2.损失函数。用来衡量预测标签和真是标签的一致性程度。这一节介绍第三个重要部分:最优化(optimization)。损失函数能让我们定量的评估得到的权重W的好坏,而最优化的目标就是找到一个W,使得损失函数最小。工作流程如下图:

    (x,y)是给定的数据集,W是权重矩阵,通过初始化得到。向前传递到评分函数中得到类别的评分值并存储在向量f中。损失函数计算评分函数值f与类标签y的差值,正则化损失只是一个关于权重的函数。在梯度下降过程中,我们计算权重的梯度,然后使用梯度更新权重。一旦理解了这三个部分的关系,我们可以用更加复杂的评分函数来代替线性映射,比如神经网络、甚至卷积神经网络等,而损失函数和优化过程这两部分则相对保持不变。

    梯度下降

      梯度下降的思想是:要寻找某函数的最值,最好的方法就是沿着函数的梯度方向寻找,移动量的大小称为步长。梯度下降的公式如下:

    我们常常听说过梯度上升、梯度下降,那么两者的区别又是什么呢?其实这两者是一样的,只是公式中的减法变成加法,因此公式为:

    梯度上升是用来求函数的最大值,而梯度下降是用来求最小值。普通的梯度下降版本如下:

    # 普通的梯度下降
    while True:
      weights_grad = evaluate_gradient(loss_fun, data, weights)
      weights += - step_size * weights_grad # 进行梯度更新

    其中的evaluate_gradient是用来计算梯度的,data是训练样本集,weights是权重,step_size是下降的步长。梯度下降方法对神经网络的损失函数优化中最常用的方法,核心思想就是一直沿着梯度方向走,直到结果不变为止。梯度下降每次更新权重W时都需要遍历整个数据集,当训练数据达到百万级别的时候,上面的方法将会十分的耗时,一种改进的方法是:

    小批量数据梯度下降(Mini-batch gradient descent):这种方法一次仅用一个或一部分数据来更新权重,例如在目前最先进的卷及神经网络中,训练集有一百而是多万,一个小批量中包含256个样本。小批量梯度下降的版本:

    # 普通的小批量数据梯度下降
    while True:
      data_batch = sample_training_data(data, 256) # 256个数据
      weights_grad = evaluate_gradient(loss_fun, data_batch, weights)
      weights += - step_size * weights_grad # 参数更新

    这种方法之所以效果不错,是因为训练集中存在相关的样本。要理解这一点,可以想想一种极端情况,在ILSVRC中,120W个图像是1000张不同的图片,每张复制1200份得到,对比这120W张图片的损失均值应该和这1000张子集损失值一样。实际数据集中,不会包含这么多重复图像,所以小批量梯度下降方法是对整个数据集梯度的一个近似。因此小批量梯度下降方法能够更快的收敛,并更加频繁的更新参数。

      小批量数据梯度下降方法有一个极端情况,那就是小批量中只有1个数据样本,这种方法被称作随机梯度下降SGD,Stochastic Gradient Descent)或者被成为在线(on-line)梯度下降,这种方法在实际操作中使用的并不多,因为使用向量化的代码计算包含100个样本的梯度效率要比计算100次1个样本梯度的效率高的多。但SGD常常被用来指代MGD,或者当看到“使用SGD”,我们就假定使用的是MGD。小批量数据集的大小是一个超参数,但是不需要通过交叉验证来调参,依赖存储器的大小。

     实例

      下面引用《机器学习实战》中对logistics regression求参数的例子来帮助理解梯度优化算法,下面是梯度上升代码:

    def gradAscent(raw_data,label):
        #转化为矩阵类型
        train_X = np.mat(raw_data)
        train_Y = np.mat(label).T
        m,n = train_X.shape
        weights = np.ones((n,1))
        alpha = 0.001
        for i in xrange(500):
            h = sigmoid(train_X * weights)
            error = (train_Y - h)
            weights += alpha*train_X.T*error
        return weights

    其中for循环是整个数据集的迭代次数,weights是一个向量,长度为数据集维度的个数。需要注意的是h、error是一个列向量,元素的个数为数据集的大小。其中weights += alpha*train_X.T*error为逻辑回归损失函数梯度迭代公式。可以看出每次迭代都需要对整个数据集进行计算。下面给出随机梯度上升的代码,一次仅用一个样本来更新权重。

    def stocGradAscent(train_X,train_Y):
        train_X = np.array(train_X)
        m,n = train_X.shape
        alpha = 0.01
        weights = np.ones(n)
        for i in range(m):
            h = sigmoid(sum(train_X[i] * weights))
            error = int(train_Y[i]) - h
            weights += alpha * error * train_X[i]
        return weights

    与上面的代码不同的是,for循环迭代的次数是数据集的大小,每次选取一个样本用来更新权重,其中的h和error不再是向量而是一个数值。

    上面两个方法使用的学习率为0.01,学习率代表算法学习速度的快慢。学习率、迭代次数与损失函数的关系如下图:

    除了梯度下降(上升)算法之外,还有一些最小化损失函数的算法,这些算法更加的复杂和优越,通常也不需要人工选择学习率例如:共轭梯度(Conjugate Gradient)、局部优化法(Broyden Fletcher goldfard shann,BFGS)等等,这些方法等遇到了再来补充,有兴趣的可以自行查阅资料。(完)

  • 相关阅读:
    无限极分类,递归分类
    foreach加循环体与不加循环体的区别
    图片base64上传时可能遇到的问题
    php(curl请求)测试接口案例
    PHP取得json前面有乱码(去除文件头部BOM)
    PHP计算连续签到天数以及累计签到天数
    原生端与服务器通过sessionid实现session共享以及登录验证
    php安装xunserch
    ROS学习(二)运行keyboard
    ROS学习(一)Ros 中使用kinect
  • 原文地址:https://www.cnblogs.com/wxshi/p/6063554.html
Copyright © 2011-2022 走看看